diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 8dc3054..72a030f 100644
*** a/contrib/pg_stat_statements/pg_stat_statements.c
--- b/contrib/pg_stat_statements/pg_stat_statements.c
***************
*** 10,15 ****
--- 10,25 ----
   * an entry, one must hold the lock shared or exclusive (so the entry doesn't
   * disappear!) and also take the entry's mutex spinlock.
   *
+  * Statements go through a normalization process before being stored.
+  * Normalization is ignoring components of the query that don't normally
+  * differentiate it for the purposes of isolating poorly performing queries.
+  * For example, the statements 'SELECT * FROM t WHERE f=1' and
+  * 'SELECT * FROM t WHERE f=2' would both be considered equivalent after
+  * normalization.  This is implemented by generating a series of integers
+  * from the query tree after the re-write stage, into a "query jumble". A
+  * query jumble is distinct from a straight serialization of the query tree in
+  * that Constants are canonicalized, and various extraneous information is
+  * ignored, such as the collation of Vars.
   *
   * Copyright (c) 2008-2011, PostgreSQL Global Development Group
   *
***************
*** 27,38 ****
--- 37,51 ----
  #include "funcapi.h"
  #include "mb/pg_wchar.h"
  #include "miscadmin.h"
+ #include "optimizer/planner.h"
+ #include "parser/parsetree.h"
  #include "pgstat.h"
  #include "storage/fd.h"
  #include "storage/ipc.h"
  #include "storage/spin.h"
  #include "tcop/utility.h"
  #include "utils/builtins.h"
+ #include "utils/memutils.h"
  
  
  PG_MODULE_MAGIC;
*************** static const uint32 PGSS_FILE_HEADER = 0
*** 48,53 ****
--- 61,70 ----
  #define USAGE_INIT				(1.0)	/* including initial planning */
  #define USAGE_DECREASE_FACTOR	(0.99)	/* decreased every entry_dealloc */
  #define USAGE_DEALLOC_PERCENT	5		/* free this % of entries at once */
+ #define JUMBLE_SIZE				1024	    /* query serialization buffer size */
+ /* Magic values */
+ #define HASH_BUF				(0xFA)	/* buffer is a hash of query tree */
+ #define STR_BUF					(0xEB)	/* buffer is query string itself */
  
  /*
   * Hashtable key that defines the identity of a hashtable entry.  The
*************** typedef struct pgssHashKey
*** 63,70 ****
  	Oid			userid;			/* user OID */
  	Oid			dbid;			/* database OID */
  	int			encoding;		/* query encoding */
! 	int			query_len;		/* # of valid bytes in query string */
! 	const char *query_ptr;		/* query string proper */
  } pgssHashKey;
  
  /*
--- 80,86 ----
  	Oid			userid;			/* user OID */
  	Oid			dbid;			/* database OID */
  	int			encoding;		/* query encoding */
! 	char		jumble[JUMBLE_SIZE]; /* Integers from a query tree */
  } pgssHashKey;
  
  /*
*************** typedef struct pgssEntry
*** 95,100 ****
--- 111,117 ----
  {
  	pgssHashKey key;			/* hash key of entry - MUST BE FIRST */
  	Counters	counters;		/* the statistics for this query */
+ 	int			query_len;		/* # of valid bytes in query string */
  	slock_t		mutex;			/* protects the counters only */
  	char		query[1];		/* VARIABLE LENGTH ARRAY - MUST BE LAST */
  	/* Note: the allocated length of query[] is actually pgss->query_size */
*************** typedef struct pgssSharedState
*** 109,116 ****
  	int			query_size;		/* max query length in bytes */
  } pgssSharedState;
  
! /*---- Local variables ----*/
  
  /* Current nesting depth of ExecutorRun calls */
  static int	nested_level = 0;
  
--- 126,146 ----
  	int			query_size;		/* max query length in bytes */
  } pgssSharedState;
  
! typedef struct pgssTokenOffset
! {
! 	int offset;					/* token offset in query string in bytes */
! 	int len;					/* length of token in bytes */
! } pgssTokenOffset;
  
+ /*---- Local variables ----*/
+ /* Jumble of last query tree seen by pgss_PlannerRun */
+ static char *last_jumble = NULL;
+ /* Ptr to buffer that represents position of normalized characters */
+ static pgssTokenOffset *last_offsets = NULL;
+ /* Current Length of last_offsets buffer */
+ static size_t last_offset_buf_size = 10;
+ /* Current number of actual offsets stored in last_offsets */
+ static size_t last_offset_num = 0;
  /* Current nesting depth of ExecutorRun calls */
  static int	nested_level = 0;
  
*************** static ExecutorRun_hook_type prev_Execut
*** 121,126 ****
--- 151,157 ----
  static ExecutorFinish_hook_type prev_ExecutorFinish = NULL;
  static ExecutorEnd_hook_type prev_ExecutorEnd = NULL;
  static ProcessUtility_hook_type prev_ProcessUtility = NULL;
+ static planner_hook_type prev_Planner = NULL;
  
  /* Links to shared memory state */
  static pgssSharedState *pgss = NULL;
*************** static int	pgss_max;			/* max # statemen
*** 147,153 ****
  static int	pgss_track;			/* tracking level */
  static bool pgss_track_utility; /* whether to track utility commands */
  static bool pgss_save;			/* whether to save stats across shutdown */
! 
  
  #define pgss_enabled() \
  	(pgss_track == PGSS_TRACK_ALL || \
--- 178,184 ----
  static int	pgss_track;			/* tracking level */
  static bool pgss_track_utility; /* whether to track utility commands */
  static bool pgss_save;			/* whether to save stats across shutdown */
! static bool pgss_string_key;	/* whether to always only hash query str */
  
  #define pgss_enabled() \
  	(pgss_track == PGSS_TRACK_ALL || \
*************** PG_FUNCTION_INFO_V1(pg_stat_statements);
*** 166,171 ****
--- 197,212 ----
  
  static void pgss_shmem_startup(void);
  static void pgss_shmem_shutdown(int code, Datum arg);
+ static PlannedStmt *pgss_PlannerRun(Query *parse, int cursorOptions, ParamListInfo boundParams);
+ static int comp_offset(const void *a, const void *b);
+ static void JumbleQuery(Query *parse);
+ static bool AppendJumb(char* item, char jumble[], size_t size, size_t *i);
+ static bool PerformJumble(const Query *parse, size_t size, size_t *i);
+ static bool QualsNode(const OpExpr *node, size_t size, size_t *i, List *rtable);
+ static bool LeafNodes(const Node *arg, size_t size, size_t *i, List *rtable);
+ static bool LimitOffsetNode(const Node *node, size_t size, size_t *i, List *rtable);
+ static bool JoinExprNode(JoinExpr *node, size_t size, size_t *i, List *rtable);
+ static bool JoinExprNodeChild(const Node *node, size_t size, size_t *i, List *rtable);
  static void pgss_ExecutorStart(QueryDesc *queryDesc, int eflags);
  static void pgss_ExecutorRun(QueryDesc *queryDesc,
  				 ScanDirection direction,
*************** static void pgss_ProcessUtility(Node *pa
*** 177,186 ****
  					DestReceiver *dest, char *completionTag);
  static uint32 pgss_hash_fn(const void *key, Size keysize);
  static int	pgss_match_fn(const void *key1, const void *key2, Size keysize);
! static void pgss_store(const char *query, double total_time, uint64 rows,
! 		   const BufferUsage *bufusage);
  static Size pgss_memsize(void);
! static pgssEntry *entry_alloc(pgssHashKey *key);
  static void entry_dealloc(void);
  static void entry_reset(void);
  
--- 218,229 ----
  					DestReceiver *dest, char *completionTag);
  static uint32 pgss_hash_fn(const void *key, Size keysize);
  static int	pgss_match_fn(const void *key1, const void *key2, Size keysize);
! static void pgss_store(const char *query, char jumble[],
! 			pgssTokenOffset offs[], int off_n,
! 			double total_time, uint64 rows,
! 			const BufferUsage *bufusage);
  static Size pgss_memsize(void);
! static pgssEntry *entry_alloc(pgssHashKey *key, const char* query, int new_query_len);
  static void entry_dealloc(void);
  static void entry_reset(void);
  
*************** _PG_init(void)
*** 252,257 ****
--- 295,315 ----
  							 NULL,
  							 NULL);
  
+ 	/*
+ 	 * Support legacy pg_stat_statements behavior, for compatibility with
+ 	 * versions shipped with Postgres 8.4, 9.0 and 9.1
+ 	 */
+ 	DefineCustomBoolVariable("pg_stat_statements.string_key",
+ 			   "Differentiate queries based on query string alone.",
+ 							 NULL,
+ 							 &pgss_string_key,
+ 							 false,
+ 							 PGC_POSTMASTER,
+ 							 0,
+ 							 NULL,
+ 							 NULL,
+ 							 NULL);
+ 
  	EmitWarningsOnPlaceholders("pg_stat_statements");
  
  	/*
*************** _PG_init(void)
*** 262,267 ****
--- 320,332 ----
  	RequestAddinShmemSpace(pgss_memsize());
  	RequestAddinLWLocks(1);
  
+ 	/* Allocate a buffer to store selective serialization of the query tree
+ 	 * for the purposes of query normalization.
+ 	 */
+ 	last_jumble = MemoryContextAlloc(TopMemoryContext, JUMBLE_SIZE);
+ 	/* Allocate space for bookkeeping information for query str normalization */
+ 	last_offsets = MemoryContextAlloc(TopMemoryContext, last_offset_buf_size * sizeof(pgssTokenOffset));
+ 
  	/*
  	 * Install hooks.
  	 */
*************** _PG_init(void)
*** 277,282 ****
--- 342,352 ----
  	ExecutorEnd_hook = pgss_ExecutorEnd;
  	prev_ProcessUtility = ProcessUtility_hook;
  	ProcessUtility_hook = pgss_ProcessUtility;
+ 	/*
+ 	 * Install hooks for query normalization
+ 	 */
+ 	prev_Planner = planner_hook;
+ 	planner_hook = pgss_PlannerRun;
  }
  
  /*
*************** _PG_fini(void)
*** 292,297 ****
--- 362,371 ----
  	ExecutorFinish_hook = prev_ExecutorFinish;
  	ExecutorEnd_hook = prev_ExecutorEnd;
  	ProcessUtility_hook = prev_ProcessUtility;
+ 	prev_Planner = planner_hook;
+ 
+ 	pfree(last_jumble);
+ 	pfree(last_offsets);
  }
  
  /*
*************** _PG_fini(void)
*** 300,306 ****
   */
  static void
  pgss_shmem_startup(void)
! {
  	bool		found;
  	HASHCTL		info;
  	FILE	   *file;
--- 374,380 ----
   */
  static void
  pgss_shmem_startup(void)
! {	
  	bool		found;
  	HASHCTL		info;
  	FILE	   *file;
*************** pgss_shmem_startup(void)
*** 395,421 ****
  		if (!PG_VALID_BE_ENCODING(temp.key.encoding))
  			goto error;
  
  		/* Previous incarnation might have had a larger query_size */
! 		if (temp.key.query_len >= buffer_size)
  		{
! 			buffer = (char *) repalloc(buffer, temp.key.query_len + 1);
! 			buffer_size = temp.key.query_len + 1;
  		}
  
! 		if (fread(buffer, 1, temp.key.query_len, file) != temp.key.query_len)
  			goto error;
! 		buffer[temp.key.query_len] = '\0';
  
  		/* Clip to available length if needed */
! 		if (temp.key.query_len >= query_size)
! 			temp.key.query_len = pg_encoding_mbcliplen(temp.key.encoding,
  													   buffer,
! 													   temp.key.query_len,
  													   query_size - 1);
- 		temp.key.query_ptr = buffer;
  
  		/* make the hashtable entry (discards old entries if too many) */
! 		entry = entry_alloc(&temp.key);
  
  		/* copy in the actual stats */
  		entry->counters = temp.counters;
--- 469,496 ----
  		if (!PG_VALID_BE_ENCODING(temp.key.encoding))
  			goto error;
  
+ 
  		/* Previous incarnation might have had a larger query_size */
! 		if (temp.query_len >= buffer_size)
  		{
! 			buffer = (char *) repalloc(buffer, temp.query_len + 1);
! 			buffer_size = temp.query_len + 1;
  		}
  
! 		if (fread(buffer, 1, temp.query_len, file) != temp.query_len)
  			goto error;
! 		buffer[temp.query_len] = '\0';
! 
  
  		/* Clip to available length if needed */
! 		if (temp.query_len >= query_size)
! 			temp.query_len = pg_encoding_mbcliplen(temp.key.encoding,
  													   buffer,
! 													   temp.query_len,
  													   query_size - 1);
  
  		/* make the hashtable entry (discards old entries if too many) */
! 		entry = entry_alloc(&temp.key, buffer, temp.query_len);
  
  		/* copy in the actual stats */
  		entry->counters = temp.counters;
*************** pgss_shmem_shutdown(int code, Datum arg)
*** 477,483 ****
  	hash_seq_init(&hash_seq, pgss_hash);
  	while ((entry = hash_seq_search(&hash_seq)) != NULL)
  	{
! 		int			len = entry->key.query_len;
  
  		if (fwrite(entry, offsetof(pgssEntry, mutex), 1, file) != 1 ||
  			fwrite(entry->query, 1, len, file) != len)
--- 552,558 ----
  	hash_seq_init(&hash_seq, pgss_hash);
  	while ((entry = hash_seq_search(&hash_seq)) != NULL)
  	{
! 		int			len = entry->query_len;
  
  		if (fwrite(entry, offsetof(pgssEntry, mutex), 1, file) != 1 ||
  			fwrite(entry->query, 1, len, file) != len)
*************** error:
*** 500,505 ****
--- 575,1391 ----
  	if (file)
  		FreeFile(file);
  	unlink(PGSS_DUMP_FILE);
+ 
+ }
+ 
+ /*
+  * pgss_PlannerRun: Planner plugin. Will selectively serialize the query tree
+  * for the purposes of query normalization if that's appropriate.
+  */
+ PlannedStmt *
+ pgss_PlannerRun(Query *parse, int cursorOptions, ParamListInfo boundParams)
+ {
+ 	if (!parse->utilityStmt && !pgss_string_key)
+ 	{
+ 		/*
+ 		 * Only generate a jumble if we have no reason to hash the query string
+ 		 * directly instead
+ 		 */
+ 		JumbleQuery(parse);
+ 	}
+ 	/* Invoke the planner */
+ 	if (prev_Planner)
+ 		return prev_Planner(parse, cursorOptions, boundParams);
+ 	else
+ 		return standard_planner(parse, cursorOptions, boundParams);
+ }
+ 
+ /*
+  * comp_offset: Comparator for qsorting pgssTokenOffset values by their
+  * position in the original query string. Often when walking the query tree,
+  * Const tokens will be found in the same order as in the original query string,
+  * but this is certainly not guaranteed.
+  */ 
+ static int comp_offset(const void *a, const void *b)
+ {
+ 	int l = ((pgssTokenOffset*) a)->offset;
+ 	int r = ((pgssTokenOffset*) b)->offset;
+ 	if (l < r)
+ 		return -1;
+ 	else if (l > r)
+ 		return +1;
+ 	else
+ 		return 0;
+ }
+ 
+ /*
+  * JumbleQuery: Selectively serialize query tree, and store it until
+  * needed to hash the query "parse".
+  */
+ static void JumbleQuery(Query *parse)
+ {
+ 	/* State for this run of PerformJumble */
+ 	size_t i = 0;
+ 	last_offset_num = 0;
+ 	memset(last_jumble, 0, JUMBLE_SIZE);
+ 	last_jumble[++i] = HASH_BUF;
+ 	PerformJumble(parse, JUMBLE_SIZE, &i);
+ 	/* Sort offsets for query string normalization */
+ 	qsort(last_offsets, last_offset_num, sizeof(pgssTokenOffset), comp_offset);
+ }
+ 
+ /*
+  * AppendJumb: Append a value that is substantive to a given query to jumble,
+  * while incrementing the iterator.
+  */
+ static bool AppendJumb(char* item, char jumble[], size_t size, size_t *i)
+ {
+ 	Assert(item != NULL);
+ 	Assert(jumble != NULL);
+ 	Assert(i != NULL);
+ 
+ 	/*
+ 	 * Copy the entire item to the buffer, or as much of it as possible to fill
+ 	 * the buffer to capacity.
+ 	 */
+ 	memcpy(jumble + *i, item, Min(*i >= JUMBLE_SIZE? 0:JUMBLE_SIZE - *i, size));
+ 
+ 	if (size + *i >= JUMBLE_SIZE)
+ 	{
+ 		/*
+ 		 * While byte-for-byte, the jumble representation will often be a lot more
+ 		 * compact than the query string, it's possible JUMBLE_SIZE has been set to
+ 		 * a very small value. Besides, it's always possible to contrive a query
+ 		 * where it won't be as compact, such as
+ 		 * "select * from table_with_many_columns". Control is not expected to
+ 		 * reach here most of the time, as this is considered an edge-case.
+ 		 */
+ 		if (size + *i >= JUMBLE_SIZE * 5)
+ 			/* Give up completely, to avoid a possible stack overflow */
+ 			return false;
+ 		/*
+ 		 * Don't give up yet...don't append any more, but keep walking the tree
+ 		 * to find Const nodes to canonicalize. Having done all we can with the
+ 		 * jumble, we must still concern ourselves with the normalized query
+ 		 * str.
+ 		 */
+ 	}
+ 	*i += size;
+ 	return true;
+ }
+ 
+ /*
+  * Wrapper around AppendJumb to encapsulate details of serialization
+  * of individual elements.
+  */ 
+ #define APP_JUMB(item) \
+ if (!AppendJumb((char*)&item, last_jumble, sizeof(item), i))\
+ 	return false;
+ 
+ /* 
+  * Simple wrappers around functions so that they return upon reaching 
+  * end of buffer 
+  */
+ #define PERFORM_JUMBLE(item, size, i) \
+ if (!PerformJumble(item, size, i))\
+ 	return false;
+ 
+ #define QUALS_NODE(item, size, i, rtable) \
+ if (!QualsNode(item, size, i, rtable)) \
+ 	return false;
+ 
+ #define LEAF_NODES(item, size, i, rtable) \
+ if (!LeafNodes(item, size, i, rtable)) \
+ 	return false;
+ 
+ #define LIMIT_OFFSET_NODE(item, size, i, rtable) \
+ if (!LimitOffsetNode(item, size, i, rtable)) \
+ 	return false;
+ 
+ #define JOIN_EXPR_NODE(item, size, i, rtable) \
+ if (!JoinExprNode(item, size, i, rtable)) \
+ 	return false;
+ 
+ #define JOIN_EXPR_NODE_CHILD(item, size, i, rtable) \
+ if (!JoinExprNodeChild(item, size, i, rtable)) \
+ 	return false;
+ 
+ /*
+  * PerformJumble: Serialize the query tree "parse" and canonicalize
+  * constants, while simply skipping over others that are not essential to the
+  * query, such that it is usefully normalized, excluding things from the tree
+  * that are not essential to the query itself.
+  *
+  * A guiding principal as to whether two queries should be considered
+  * equivalent is whether whatever difference exists between the two queries
+  * could be expected to result in two different plans, assuming that all
+  * constants have the same selectivity estimate and excluding factors that are
+  * not essential to the query and the relations on which it operates. A
+  * non-obvious example of such a differentiator is a change in the definition
+  * of a view referenced by a query. We pointedly serialize the query tree
+  * *after* the rewriting stage, so entries in pg_stat_statements accurately
+  * represent discrete operations, while not having artifacts from external
+  * factors that are not essential to what the query actually does. Directly
+  * hashing plans would have the undesirable side-effect of potentially having
+  * totally external factors like planner cost constants differentiate a query,
+  * so that particular implementation was not chosen. Directly hashing the raw
+  * parse tree would prevent us from benefiting from the parser's own
+  * normalization of queries in later stages, such as removing differences
+  * between equivalent syntax, so that implementation was avoided too.
+  *
+  * The last_jumble buffer, that this function scribbles on, can be hashed to
+  * uniquely identify a query that may use different constants in successive
+  * calls.
+  */
+ static bool PerformJumble(const Query *parse, size_t size, size_t *i)
+ {
+ 	ListCell *l;
+ 	/* table join tree (FROM and WHERE clauses) */
+ 	FromExpr *jt = (FromExpr *) parse->jointree;
+ 	/* # of result tuples to skip (int8 expr) */
+ 	FuncExpr *off = (FuncExpr *) parse->limitOffset;
+ 	/* # of result tuples to skip (int8 expr) */
+ 	FuncExpr *limcount = (FuncExpr *) parse->limitCount;
+ 
+ 	APP_JUMB(parse->resultRelation);
+ 
+ 	if (parse->intoClause)
+ 	{
+ 		IntoClause *ic = parse->intoClause;
+ 		RangeVar   *rel = ic->rel;
+ 		APP_JUMB(ic->onCommit);
+ 		APP_JUMB(ic->skipData);
+ 		if (rel)
+ 		{
+ 			APP_JUMB(rel->relpersistence);
+ 			/* Bypass macro abstraction to supply size directly.
+ 			 * 
+ 			 * Serialize schemaname, relname themselves - this is to be
+ 			 * somewhat consistent with the behavior of utility statements like "create
+ 			 * table".
+ 			 */
+ 			if ( (rel->schemaname && !AppendJumb(rel->schemaname, last_jumble, strlen(rel->schemaname), i)) ||
+ 				 (rel->relname && !AppendJumb(rel->relname, last_jumble, strlen(rel->relname), i) 	)
+ 				)
+ 				return false;
+ 		}
+ 	}
+ 
+ 	/* WITH list (of CommonTableExpr's) */
+ 	foreach(l, parse->cteList)
+ 	{
+ 		CommonTableExpr	*cte = (CommonTableExpr *) lfirst(l);
+ 		Query			*cteq = (Query*) cte->ctequery;
+ 		if (cteq)
+ 			PERFORM_JUMBLE(cteq, size, i);
+ 	}
+ 	if (jt)
+ 	{
+ 		if (jt->quals)
+ 		{
+ 			if (IsA(jt->quals, OpExpr))
+ 			{
+ 				QUALS_NODE((OpExpr*) jt->quals, size, i, parse->rtable);
+ 			}
+ 			else
+ 			{
+ 				LEAF_NODES((Node*) jt->quals, size, i, parse->rtable);
+ 			}
+ 		}
+ 		/* table join tree */
+ 		foreach(l, jt->fromlist)
+ 		{
+ 			Node* fr = lfirst(l);
+ 			if (IsA(fr, JoinExpr))
+ 			{
+ 				JOIN_EXPR_NODE((JoinExpr*) fr, size, i, parse->rtable);
+ 			}
+ 			else if (IsA(fr, RangeTblRef))
+ 			{
+ 				RangeTblRef   *rtf = (RangeTblRef *) fr;
+ 				RangeTblEntry *rte = rt_fetch(rtf->rtindex, parse->rtable);
+ 				APP_JUMB(rte->relid);
+ 				APP_JUMB(rte->rtekind);
+ 				/* Subselection in where clause */
+ 				if (rte->subquery)
+ 					PERFORM_JUMBLE(rte->subquery, size, i);
+ 
+ 				/* Function call in where clause */
+ 				if (rte->funcexpr)
+ 					LEAF_NODES((Node*) rte->funcexpr, size, i, parse->rtable);
+ 			}
+ 			else
+ 			{
+ 				elog(ERROR, "unrecognized fromlist node type: %d",
+ 					 (int) nodeTag(fr));
+ 			}
+ 		}
+ 	}
+ 	/*
+ 	 * target list (of TargetEntry)
+ 	 * columns returned by query
+ 	 */
+ 	foreach(l, parse->targetList)
+ 	{
+ 		TargetEntry *tg = (TargetEntry *) lfirst(l);
+ 		Node        *e  = (Node*) tg->expr;
+ 		if (tg->ressortgroupref)
+ 			APP_JUMB(tg->ressortgroupref); /* nonzero if referenced by a sort/group - for ORDER BY */
+ 		APP_JUMB(tg->resno); /* column number for select */
+ 		/* Handle the various types of nodes in
+ 		 * the select list of this query
+ 		 */
+ 		LEAF_NODES(e, size, i, parse->rtable);
+ 	}
+ 	/* return-values list (of TargetEntry) */
+ 	foreach(l, parse->returningList)
+ 	{
+ 		TargetEntry *rt = (TargetEntry *) lfirst(l);
+ 		Expr        *e  = (Expr*) rt->expr;
+ 		/*
+ 		 * Handle the various types of nodes in
+ 		 * the select list of this query
+ 		 */
+ 		if (IsA(e, Var)) /* table column */
+ 		{
+ 			Var *v = (Var*) e;
+ 			RangeTblEntry *rte = rt_fetch(v->varno, parse->rtable);
+ 			APP_JUMB(rte->relid);
+ 			APP_JUMB(v->varattno);
+ 		}
+ 		else
+ 		{
+ 			elog(ERROR, "unrecognized node type for returnlist node: %d",
+ 					(int) nodeTag(e));
+ 		}
+ 	}
+ 	/* a list of SortGroupClause's */
+ 	foreach(l, parse->groupClause)
+ 	{
+ 		SortGroupClause *gc = (SortGroupClause *) lfirst(l);
+ 		APP_JUMB(gc->tleSortGroupRef);
+ 		APP_JUMB(gc->nulls_first);
+ 	}
+ 
+ 	if (parse->havingQual)
+ 	{
+ 		if (IsA(parse->havingQual, OpExpr))
+ 		{
+ 			OpExpr *na = (OpExpr *) parse->havingQual;
+ 			QUALS_NODE(na, size, i, parse->rtable);
+ 		}
+ 		else
+ 		{
+ 			elog(ERROR, "unrecognized node type for havingclause node: %d",
+ 					(int) nodeTag(parse->havingQual));
+ 		}
+ 	}
+ 	foreach(l, parse->windowClause)
+ 	{
+ 		WindowClause *wc = (WindowClause *) lfirst(l);
+ 		ListCell     *il;
+ 		APP_JUMB(wc->frameOptions);
+ 		foreach(il, wc->partitionClause) /* PARTITION BY list */
+ 		{
+ 			Node *n = (Node *) lfirst(il);
+ 			LEAF_NODES(n, size, i, parse->rtable);
+ 		}
+ 		foreach(il, wc->orderClause) /* ORDER BY list */
+ 		{
+ 			Node *n = (Node *) lfirst(il);
+ 			LEAF_NODES(n, size, i, parse->rtable);
+ 		}
+ 	}
+ 
+ 	foreach(l, parse->distinctClause)
+ 	{
+ 		SortGroupClause *dc = (SortGroupClause *) lfirst(l);
+ 		APP_JUMB(dc->tleSortGroupRef);
+ 		APP_JUMB(dc->nulls_first);
+ 	}
+ 
+ 	/* Don't look at parse->sortClause,
+ 	 * because the value ressortgroupref is already
+ 	 * serialized when we iterate through targetList
+ 	 */
+ 
+ 	if (off)
+ 		LIMIT_OFFSET_NODE((Node*) off, size, i, parse->rtable);
+ 
+ 	if (limcount)
+ 		LIMIT_OFFSET_NODE((Node*) limcount, size, i, parse->rtable);
+ 
+ 	foreach(l, parse->rowMarks)
+ 	{
+ 		RowMarkClause *rc = (RowMarkClause *) lfirst(l);
+ 		APP_JUMB(rc->rti);				/* range table index of target relation */
+ 		APP_JUMB(rc->forUpdate);			/* true = FOR UPDATE, false = FOR SHARE */
+ 		APP_JUMB(rc->noWait);				/* NOWAIT option */
+ 		APP_JUMB(rc->pushedDown);			/* pushed down from higher query level? */
+ 	}
+ 
+ 	if (parse->setOperations)
+ 	{
+ 		/*
+ 		 * set-operation tree if this is top
+ 		 * level of a UNION/INTERSECT/EXCEPT query
+ 		 */
+ 		SetOperationStmt *topop = (SetOperationStmt *) parse->setOperations;
+ 		APP_JUMB(topop->op);
+ 		APP_JUMB(topop->all);
+ 
+ 		/* leaf selects are RTE subselections */
+ 		foreach(l, parse->rtable)
+ 		{
+ 			RangeTblEntry *r = (RangeTblEntry *) lfirst(l);
+ 			if (r->subquery)
+ 				PERFORM_JUMBLE(r->subquery, size, i);
+ 		}
+ 	}
+ 	return true;
+ }
+ 
+ /* 
+  * Perform selective serialization of "Quals" nodes when
+  * they're IsA(*, OpExpr)
+  */
+ static bool QualsNode(const OpExpr *node, size_t size, size_t *i, List *rtable)
+ {
+ 	ListCell *l;
+ 	APP_JUMB(node->opno);
+ 	foreach(l, node->args)
+ 	{
+ 		Node *arg = (Node *) lfirst(l);
+ 		LEAF_NODES(arg, size, i, rtable);
+ 	}
+ 	return true;
+ }
+ 
+ /*
+  * LeafNodes: Selectively serialize a selection of parser/prim nodes that are
+  * frequently, though certainly not necesssarily leaf nodes, such as Vars
+  * (columns), constants and function calls
+  */
+ static bool LeafNodes(const Node *arg, size_t size, size_t *i, List *rtable)
+ {
+ 	ListCell *l;
+ 	if (IsA(arg, Const))
+ 	{
+ 		/*
+ 		 * Serialize generic magic value to
+ 		 * normalize constants
+ 		 */
+ 		char  magic = 0xC0;
+ 		Const *c = (Const *) arg;
+ 		APP_JUMB(magic);
+ 		/* Datatype of the constant is a 
+ 		 * differentiator 
+ 		 */
+ 		APP_JUMB(c->consttype);
+ 		/* 
+ 		 * Some Const nodes naturally don't have a location.
+ 		 * 
+ 		 * Views that have constants in their
+ 		 * definitions will have a tok_len of 0
+ 		 */
+ 		if (c->location > 0 && c->tok_len > 0) 
+ 		{
+ 			if (last_offset_num >= last_offset_buf_size)
+ 			{
+ 				last_offset_buf_size *= 2;
+ 				last_offsets = repalloc(last_offsets, last_offset_buf_size * sizeof(pgssTokenOffset));
+ 			}
+ 			last_offsets[last_offset_num].offset = c->location;
+ 			last_offsets[last_offset_num].len = c->tok_len;
+ 			last_offset_num++;
+ 		}
+ 	}
+ 	else if (IsA(arg, Var))
+ 	{
+ 		char		  magic = 0xFA;
+ 		Var			  *v = (Var *) arg;
+ 		RangeTblEntry *rte = rt_fetch(v->varno, rtable);
+ 		APP_JUMB(magic);
+ 		APP_JUMB(rte->relid);
+ 		APP_JUMB(v->varattno); /* column number of table */
+ 	}
+ 	else if (IsA(arg, Param))
+ 	{
+ 		Param *p = ((Param *) arg);
+ 		APP_JUMB(p->paramkind);
+ 		APP_JUMB(p->paramid);
+ 	}
+ 	else if (IsA(arg, RelabelType))
+ 	{
+ 		APP_JUMB(((RelabelType *) arg)->resulttype);
+ 	}
+ 	else if (IsA(arg, WindowFunc))
+ 	{
+ 		WindowFunc *wf = (WindowFunc *) arg;
+ 		APP_JUMB(wf->winfnoid);
+ 		foreach(l, wf->args)
+ 		{
+ 			Node *arg = (Node *) lfirst(l);
+ 			LEAF_NODES(arg, size, i, rtable);
+ 		}
+ 	}
+ 	else if (IsA(arg, FuncExpr))
+ 	{
+ 		FuncExpr *f = (FuncExpr *) arg;
+ 		APP_JUMB(f->funcid);
+ 		foreach(l, f->args)
+ 		{
+ 			Node *arg = (Node *) lfirst(l);
+ 			LEAF_NODES(arg, size, i, rtable);
+ 		}
+ 	}
+ 	else if (IsA(arg, OpExpr))
+ 	{
+ 		QUALS_NODE((OpExpr*) arg, size, i, rtable);
+ 	}
+ 	else if (IsA(arg, CoerceViaIO))
+ 	{
+ 		APP_JUMB(((CoerceViaIO*) arg)->coerceformat);
+ 		APP_JUMB(((CoerceViaIO*) arg)->resulttype);
+ 	}
+ 	else if (IsA(arg, Aggref))
+ 	{
+ 		Aggref *a =  (Aggref *) arg;
+ 		APP_JUMB(a->aggfnoid);
+ 		foreach(l, a->args)
+ 		{
+ 			Node *arg = (Node *) lfirst(l);
+ 			LEAF_NODES(arg, size, i, rtable);
+ 		}
+ 	}
+ 	else if (IsA(arg, SubLink))
+ 	{
+ 		SubLink *s = (SubLink*) arg;
+ 		APP_JUMB(s->subLinkType);
+ 		/* Serialize select-list subselect recursively */
+ 		if (s->subselect)
+ 			PERFORM_JUMBLE((Query*) s->subselect, size, i);
+ 	}
+ 	else if (IsA(arg, TargetEntry))
+ 	{
+ 		TargetEntry *rt = (TargetEntry *) arg;
+ 		Node *e = (Node*) rt->expr;
+ 		APP_JUMB(rt->resorigtbl); /* OID of column's source table */
+ 		APP_JUMB(rt->ressortgroupref); /*  nonzero if referenced by a sort/group - for ORDER BY */
+ 		LEAF_NODES(e, size, i, rtable);
+ 	}
+ 	else if (IsA(arg, BoolExpr))
+ 	{
+ 		BoolExpr *be = (BoolExpr *) arg;	
+ 		APP_JUMB(be->boolop);
+ 		foreach(l, be->args)
+ 		{
+ 			Node *arg = (Node *) lfirst(l);
+ 			LEAF_NODES(arg, size, i, rtable);
+ 		}
+ 	}
+ 	else if (IsA(arg, NullTest))
+ 	{
+ 		NullTest *nt = (NullTest *) arg;
+ 		Node     *arg = (Node *) nt->arg;
+ 		APP_JUMB(nt->nulltesttype);	/* IS NULL, IS NOT NULL */
+ 		APP_JUMB(nt->argisrow);		/* is input a composite type ? */
+ 		LEAF_NODES(arg, size, i, rtable);
+ 	}
+ 	else if (IsA(arg, ArrayExpr))
+ 	{
+ 		ArrayExpr *ae = (ArrayExpr *) arg;		
+ 		APP_JUMB(ae->array_typeid);	/* type of expression result */
+ 		APP_JUMB(ae->element_typeid);	/* common type of array elements */
+ 		foreach(l, ae->elements)
+ 		{
+ 			Node *arg = (Node *) lfirst(l);
+ 			LEAF_NODES(arg, size, i, rtable);
+ 		}
+ 	}
+ 	else if (IsA(arg, CaseExpr))
+ 	{
+ 		CaseExpr *ce = (CaseExpr*) arg;	
+ 		Assert(ce->casetype != InvalidOid);
+ 		APP_JUMB(ce->casetype);
+ 		foreach(l, ce->args)
+ 		{
+ 			Node *arg = (Node *) lfirst(l);
+ 			LEAF_NODES(arg, size, i, rtable);
+ 		}
+ 		if (ce->arg)	
+ 			LEAF_NODES((Node*) ce->arg, size, i, rtable);
+ 
+ 		if (ce->defresult)
+ 		{
+ 			/* Default result (ELSE clause) 
+ 			 * The ptr may be NULL, because no else clause
+ 			 * was actually specified, and thus the value is
+ 			 * equivalent to SQL ELSE NULL
+ 			 */
+ 			LEAF_NODES((Node*) ce->defresult, size, i, rtable); /* the default result (ELSE clause) */
+ 		}
+ 	}
+ 	else if (IsA(arg, CaseTestExpr))
+ 	{
+ 		CaseTestExpr *ct = (CaseTestExpr*) arg;
+ 		APP_JUMB(ct->typeId);
+ 	}
+ 	else if (IsA(arg, CaseWhen))
+ 	{
+ 		CaseWhen *cw = (CaseWhen*) arg;
+ 		Node     *res = (Node*) cw->result;
+ 		Node     *exp = (Node*) cw->expr;
+ 		if (res)
+ 			LEAF_NODES(res, size, i, rtable);
+ 		if (exp)
+ 			LEAF_NODES(exp, size, i, rtable);
+ 	}
+ 	else if (IsA(arg, MinMaxExpr))
+ 	{
+ 		MinMaxExpr *cw = (MinMaxExpr*) arg;
+ 		APP_JUMB(cw->minmaxtype);
+ 		APP_JUMB(cw->op);
+ 		foreach(l, cw->args)
+ 		{
+ 			Node *arg = (Node *) lfirst(l);
+ 			LEAF_NODES(arg, size, i, rtable);
+ 		}
+ 	}
+ 	else if (IsA(arg, ScalarArrayOpExpr))
+ 	{
+ 		ScalarArrayOpExpr *sa = (ScalarArrayOpExpr*) arg;
+ 		APP_JUMB(sa->opfuncid);
+ 		APP_JUMB(sa->useOr);
+ 		foreach(l, sa->args)
+ 		{
+ 			Node *arg = (Node *) lfirst(l);
+ 			LEAF_NODES(arg, size, i, rtable);
+ 		}
+ 	}
+ 	else if (IsA(arg, CoalesceExpr))
+ 	{
+ 		CoalesceExpr *ca = (CoalesceExpr*) arg;
+ 		foreach(l, ca->args)
+ 		{
+ 			Node *arg = (Node *) lfirst(l);
+ 			LEAF_NODES(arg, size, i, rtable);
+ 		}
+ 	}
+ 	else if (IsA(arg, ArrayCoerceExpr))
+ 	{
+ 		ArrayCoerceExpr *ac = (ArrayCoerceExpr *) arg;
+ 		LEAF_NODES((Node*) ac->arg, size, i, rtable);
+ 	}
+ 	else if (IsA(arg, WindowClause))
+ 	{
+ 		WindowClause *wc = (WindowClause*) arg;
+ 		foreach(l, wc->partitionClause)
+ 		{
+ 			Node *arg = (Node *) lfirst(l);
+ 			LEAF_NODES(arg, size, i, rtable);
+ 		}
+ 		foreach(l, wc->orderClause)
+ 		{
+ 			Node *arg = (Node *) lfirst(l);
+ 			LEAF_NODES(arg, size, i, rtable);
+ 		}
+ 	}
+ 	else if (IsA(arg, SortGroupClause))
+ 	{
+ 		SortGroupClause *sgc = (SortGroupClause*) arg;
+ 		APP_JUMB(sgc->tleSortGroupRef);
+ 		APP_JUMB(sgc->nulls_first);
+ 	}
+ 	else if (IsA(arg, Integer) ||
+ 		  IsA(arg, Float) ||
+ 		  IsA(arg, String) ||
+ 		  IsA(arg, BitString) ||
+ 		  IsA(arg, Null)
+ 		)
+ 	{
+ 		/* It is not necessary to
+ 		 * serialize integral values
+ 		 */
+ 	}
+ 	else if (IsA(arg, BooleanTest))
+ 	{
+ 		BooleanTest *bt = (BooleanTest *) arg;
+ 		APP_JUMB(bt->booltesttype);
+ 		LEAF_NODES((Node*) bt->arg, size, i, rtable);
+ 	}
+ 	else if (IsA(arg, ArrayRef))
+ 	{
+ 		ArrayRef *ar = (ArrayRef*) arg;
+ 		APP_JUMB(ar->refarraytype);
+ 		foreach(l, ar->refupperindexpr)
+ 		{
+ 			Node *arg = (Node *) lfirst(l);
+ 			LEAF_NODES(arg, size, i, rtable);
+ 		}
+ 		foreach(l, ar->reflowerindexpr)
+ 		{
+ 			Node *arg = (Node *) lfirst(l);
+ 			LEAF_NODES(arg, size, i, rtable);
+ 		}
+ 	}
+ 	else if (IsA(arg, NullIfExpr))
+ 	{
+ 		/* NullIfExpr is just a typedef for OpExpr */
+ 		QUALS_NODE((OpExpr*) arg, size, i, rtable);
+ 	}
+ 	else if (IsA(arg, RowExpr))
+ 	{
+ 		RowExpr *re = (RowExpr*) arg;
+ 		APP_JUMB(re->row_format);
+ 		foreach(l, re->args)
+ 		{
+ 			Node *arg = (Node *) lfirst(l);
+ 			LEAF_NODES(arg, size, i, rtable);
+ 		}
+ 
+ 	}
+ 	else if (IsA(arg, XmlExpr))
+ 	{
+ 		XmlExpr *xml = (XmlExpr*) arg;
+ 		APP_JUMB(xml->op);
+ 		foreach(l, xml->args)
+ 		{
+ 			Node *arg = (Node *) lfirst(l);
+ 			LEAF_NODES(arg, size, i, rtable);
+ 		}
+ 		foreach(l, xml->named_args) /* non-XML expressions for xml_attributes */
+ 		{
+ 			Node *arg = (Node *) lfirst(l);
+ 			LEAF_NODES(arg, size, i, rtable);
+ 		}
+ 		foreach(l, xml->arg_names) /* parallel list of Value strings */
+ 		{
+ 			Node *arg = (Node *) lfirst(l);
+ 			LEAF_NODES(arg, size, i, rtable);
+ 		}
+ 	}
+ 	else if (IsA(arg, RowCompareExpr))
+ 	{
+ 		RowCompareExpr *rc = (RowCompareExpr*) arg;
+ 		foreach(l, rc->largs)
+ 		{
+ 			Node *arg = (Node *) lfirst(l);
+ 			LEAF_NODES(arg, size, i, rtable);
+ 		}
+ 		foreach(l, rc->rargs)
+ 		{
+ 			Node *arg = (Node *) lfirst(l);
+ 			LEAF_NODES(arg, size, i, rtable);
+ 		}
+ 	}
+ 	else
+ 	{
+ 		elog(ERROR, "unrecognized node type for LeafNodes node: %d",
+ 				(int) nodeTag(arg));
+ 	}
+ 	return true;
+ }
+ 
+ /* 
+  * Perform selective serialization of limit or offset nodes
+  */
+ static bool LimitOffsetNode(const Node *node, size_t size, size_t *i, List *rtable)
+ {
+ 	ListCell *l;
+ 	if (IsA(node, FuncExpr))
+ 	{
+ 		foreach(l, ((FuncExpr*) node)->args)
+ 		{
+ 			Node *arg = (Node *) lfirst(l);
+ 			LEAF_NODES(arg, size, i, rtable);
+ 		}
+ 	}
+ 	else if (IsA(node, Const))
+ 	{
+ 		/* This should be a differentiator, as it results in the addition of a limit node */
+ 		char magic = 0xEA;
+ 		APP_JUMB(magic);
+ 	}
+ 	else
+ 	{
+ 		/* Fall back on leaf node representation */
+ 		LEAF_NODES(node, size, i, rtable);
+ 	}
+ 	return true;
+ }
+ 
+ /*
+  * JoinExprNode: Perform selective serialization of JoinExpr nodes
+  */
+ static bool JoinExprNode(JoinExpr *node, size_t size, size_t *i, List *rtable)
+ {
+ 	Node	 *larg = node->larg;	/* left subtree */
+ 	Node	 *rarg = node->rarg;	/* right subtree */
+ 	ListCell *l;
+ 
+ 	Assert( IsA(node, JoinExpr));
+ 
+ 	APP_JUMB(node->jointype);
+ 	APP_JUMB(node->isNatural);
+ 
+ 	if (node->quals)
+ 	{
+ 		if ( IsA(node, OpExpr))
+ 		{
+ 			QUALS_NODE((OpExpr*) node->quals, size, i, rtable);
+ 		}
+ 		else
+ 		{
+ 			LEAF_NODES((Node*) node->quals, size, i, rtable);
+ 		}
+ 
+ 	}	
+ 	foreach(l, node->usingClause) /* USING clause, if any (list of String) */
+ 	{
+ 		Node *arg = (Node *) lfirst(l);
+ 		LEAF_NODES(arg, size, i, rtable);
+ 	}
+ 	if (larg)
+ 		JOIN_EXPR_NODE_CHILD(larg, size, i, rtable);
+ 	if (rarg)
+ 		JOIN_EXPR_NODE_CHILD(rarg, size, i, rtable);
+ 
+ 	return true;
+ }
+ 
+ /*
+  * JoinExprNodeChild: Serialize children of the JoinExpr node
+  */
+ static bool JoinExprNodeChild(const Node *node, size_t size, size_t *i, List *rtable)
+ {
+ 	if (IsA(node, RangeTblRef))
+ 	{
+ 		RangeTblRef   *rt = (RangeTblRef*) node;
+ 		RangeTblEntry *rte = rt_fetch(rt->rtindex, rtable);
+ 		ListCell      *l;
+ 
+ 		APP_JUMB(rte->relid);
+ 		APP_JUMB(rte->jointype);
+ 
+ 		if (rte->subquery)
+ 			PERFORM_JUMBLE((Query*) rte->subquery, size, i);
+ 		
+ 		foreach(l, rte->joinaliasvars)
+ 		{
+ 			Node *arg = (Node *) lfirst(l);
+ 			LEAF_NODES(arg, size, i, rtable);
+ 		}	
+ 	}
+ 	else if (IsA(node, JoinExpr))
+ 	{	
+ 		JOIN_EXPR_NODE((JoinExpr*) node, size, i, rtable);
+ 	}
+ 	else
+ 	{
+ 		LEAF_NODES(node, size, i, rtable);
+ 	}
+ 	return true;
  }
  
  /*
*************** pgss_ExecutorEnd(QueryDesc *queryDesc)
*** 591,600 ****
--- 1477,1527 ----
  		 */
  		InstrEndLoop(queryDesc->totaltime);
  
+ 		if (queryDesc->params || queryDesc->utilitystmt || pgss_string_key)
+ 		{
+ 			/*
+ 			 * This query was paramaterized or is a utility statement, or
+ 			 * pg_stat_statements is in legacy pgss_string_key mode - hash the
+ 			 * query string, as the last call to pgss_PlannerRun won't have
+ 			 * hashed the tree of this particular query - it may have skipped
+ 			 * hashing, or there may not have even been a call corresponding to
+ 			 * a call to this call of pgss_ExecutorEnd.
+ 			 *
+ 			 * If we're dealing with a parameterized query, the query string
+ 			 * is the original query string anyway, so there is no need to
+ 			 * worry about its stability.
+ 			 *
+ 			 * The fact that constants in the prepared query won't be
+ 			 * canonicalized is clearly a feature rather than a bug, as the
+ 			 * user evidently considers such constant essential to the query, or
+ 			 * they'd have paramaterized them.
+ 			 */
+ 			memset(last_jumble, 0, JUMBLE_SIZE);
+ 			last_jumble[0] = STR_BUF;
+ 			memcpy(last_jumble + 1, queryDesc->sourceText,
+ 				Min(JUMBLE_SIZE - 1, strlen(queryDesc->sourceText) )
+ 				);
+ 		}
+ 		/* 
+ 		 * There is an assumption that last_* variables were set by a prior,
+ 		 * corresponding call to pgss_PlannerRun within this backend (provided
+ 		 * that we jumbled the query tree with the intention of hashing it - that
+ 		 * won't be the case if the jumble is actually just a STR_BUF copy of
+ 		 * the query string).
+ 		 */
  		pgss_store(queryDesc->sourceText,
+ 				   last_jumble,
+ 				   last_offsets,
+ 				   last_offset_num,
  				   queryDesc->totaltime->total,
  				   queryDesc->estate->es_processed,
  				   &queryDesc->totaltime->bufusage);
+ 
+ 		if (last_offset_buf_size > 10)
+ 		{
+ 			last_offset_buf_size = 10;
+ 			last_offsets = repalloc(last_offsets, last_offset_buf_size * sizeof(pgssTokenOffset));
+ 		}
  	}
  
  	if (prev_ExecutorEnd)
*************** pgss_ProcessUtility(Node *parsetree, con
*** 665,671 ****
  		bufusage.temp_blks_written =
  			pgBufferUsage.temp_blks_written - bufusage.temp_blks_written;
  
! 		pgss_store(queryString, INSTR_TIME_GET_DOUBLE(duration), rows,
  				   &bufusage);
  	}
  	else
--- 1592,1605 ----
  		bufusage.temp_blks_written =
  			pgBufferUsage.temp_blks_written - bufusage.temp_blks_written;
  
! 		/* In the case of utility statements, hash the query string directly */
! 		memset(last_jumble, 0, JUMBLE_SIZE);
! 		last_jumble[0] = STR_BUF;
! 		memcpy(last_jumble + 1, queryString,
! 			Min(JUMBLE_SIZE - 1, strlen(queryString) )
! 			);
! 
! 		pgss_store(queryString, last_jumble, NULL, 0, INSTR_TIME_GET_DOUBLE(duration), rows,
  				   &bufusage);
  	}
  	else
*************** pgss_hash_fn(const void *key, Size keysi
*** 690,697 ****
  	/* we don't bother to include encoding in the hash */
  	return hash_uint32((uint32) k->userid) ^
  		hash_uint32((uint32) k->dbid) ^
! 		DatumGetUInt32(hash_any((const unsigned char *) k->query_ptr,
! 								k->query_len));
  }
  
  /*
--- 1624,1630 ----
  	/* we don't bother to include encoding in the hash */
  	return hash_uint32((uint32) k->userid) ^
  		hash_uint32((uint32) k->dbid) ^
! 		DatumGetUInt32(hash_any((const unsigned char* ) k->jumble, JUMBLE_SIZE) );
  }
  
  /*
*************** pgss_match_fn(const void *key1, const vo
*** 706,713 ****
  	if (k1->userid == k2->userid &&
  		k1->dbid == k2->dbid &&
  		k1->encoding == k2->encoding &&
! 		k1->query_len == k2->query_len &&
! 		memcmp(k1->query_ptr, k2->query_ptr, k1->query_len) == 0)
  		return 0;
  	else
  		return 1;
--- 1639,1645 ----
  	if (k1->userid == k2->userid &&
  		k1->dbid == k2->dbid &&
  		k1->encoding == k2->encoding &&
! 		memcmp(k1->jumble, k2->jumble, JUMBLE_SIZE) == 0)
  		return 0;
  	else
  		return 1;
*************** pgss_match_fn(const void *key1, const vo
*** 717,727 ****
   * Store some statistics for a statement.
   */
  static void
! pgss_store(const char *query, double total_time, uint64 rows,
! 		   const BufferUsage *bufusage)
  {
  	pgssHashKey key;
  	double		usage;
  	pgssEntry  *entry;
  
  	Assert(query != NULL);
--- 1649,1663 ----
   * Store some statistics for a statement.
   */
  static void
! pgss_store(const char *query, char jumble[],
! 			pgssTokenOffset offs[], int off_n,
! 			double total_time, uint64 rows,
! 			const BufferUsage *bufusage)
  {
  	pgssHashKey key;
  	double		usage;
+ 	int		    new_query_len = strlen(query);
+ 	char	   *norm_query = NULL;
  	pgssEntry  *entry;
  
  	Assert(query != NULL);
*************** pgss_store(const char *query, double tot
*** 734,747 ****
  	key.userid = GetUserId();
  	key.dbid = MyDatabaseId;
  	key.encoding = GetDatabaseEncoding();
! 	key.query_len = strlen(query);
! 	if (key.query_len >= pgss->query_size)
! 		key.query_len = pg_encoding_mbcliplen(key.encoding,
  											  query,
! 											  key.query_len,
  											  pgss->query_size - 1);
- 	key.query_ptr = query;
- 
  	usage = USAGE_EXEC(duration);
  
  	/* Lookup the hash table entry with shared lock. */
--- 1670,1682 ----
  	key.userid = GetUserId();
  	key.dbid = MyDatabaseId;
  	key.encoding = GetDatabaseEncoding();
! 	memcpy(key.jumble, jumble, JUMBLE_SIZE);
! 
! 	if (new_query_len >= pgss->query_size)
! 		new_query_len = pg_encoding_mbcliplen(key.encoding,
  											  query,
! 											  new_query_len,
  											  pgss->query_size - 1);
  	usage = USAGE_EXEC(duration);
  
  	/* Lookup the hash table entry with shared lock. */
*************** pgss_store(const char *query, double tot
*** 750,759 ****
  	entry = (pgssEntry *) hash_search(pgss_hash, &key, HASH_FIND, NULL);
  	if (!entry)
  	{
! 		/* Must acquire exclusive lock to add a new entry. */
! 		LWLockRelease(pgss->lock);
! 		LWLockAcquire(pgss->lock, LW_EXCLUSIVE);
! 		entry = entry_alloc(&key);
  	}
  
  	/* Grab the spinlock while updating the counters. */
--- 1685,1755 ----
  	entry = (pgssEntry *) hash_search(pgss_hash, &key, HASH_FIND, NULL);
  	if (!entry)
  	{
! 		/*
! 		 * It is necessary to generate a normalized version of the query
! 		 * string that will be used to represent it. It's important that
! 		 * the user be presented with a stable representation of the query.
! 		 *
! 		 * Note that the representation seen by the user will only have
! 		 * non-differentiating Const tokens swapped with '?' characters, and 
! 		 * this does not for example take account of the fact that alias names
! 		 * could vary between successive calls of what is regarded as the same
! 		 * query.
! 		 */
! 		if (off_n > 0)
! 		{
! 			int i,
! 			  last_off = 0,
! 			  quer_it = 0,
! 			  n_quer_it = 0,
! 			  off = 0,
! 			  tok_len = 0,
! 			  len_to_wrt = 0,
! 			  last_tok_len = 0;
! 
! 			norm_query = palloc0(new_query_len + 1);
! 			for(i = 0; i < off_n; i++)
! 			{
! 				off = offs[i].offset;
! 				tok_len = offs[i].len;
! 				len_to_wrt = off - last_off;
! 				len_to_wrt -= last_tok_len;
! 				/*
! 				 * Each iteration copies everything prior to the current
! 				 * offset/token to be replaced, except bytes copied in
! 				 * previous iterations
! 				 */
! 				if (off + tok_len > new_query_len)
! 					break;
! 				memcpy(norm_query + n_quer_it, query + quer_it, len_to_wrt);
! 
! 				n_quer_it += len_to_wrt;
! 				norm_query[n_quer_it++] = '?';
! 				quer_it += len_to_wrt + tok_len;
! 				last_off = off;
! 				last_tok_len = tok_len;
! 			}
! 			/* Finish off last piece of query string */
! 			memcpy(norm_query + n_quer_it, query + (off + tok_len), 
! 				Min( strlen(query) - (off + tok_len),
! 					new_query_len - n_quer_it ) );
! 			/*
! 			 * Must acquire exclusive lock to add a new entry.
! 			 * Leave that until as late as possible.
! 			 */
! 			LWLockRelease(pgss->lock);
! 			LWLockAcquire(pgss->lock, LW_EXCLUSIVE);
! 
! 			entry = entry_alloc(&key, norm_query, strlen(norm_query));
! 		}
! 		else
! 		{
! 			/* Acquire exclusive lock as required by entry_alloc() */
! 			LWLockRelease(pgss->lock);
! 			LWLockAcquire(pgss->lock, LW_EXCLUSIVE);
! 
! 			entry = entry_alloc(&key, query, new_query_len);
! 		}
  	}
  
  	/* Grab the spinlock while updating the counters. */
*************** pgss_store(const char *query, double tot
*** 775,782 ****
  		e->counters.usage += usage;
  		SpinLockRelease(&e->mutex);
  	}
- 
  	LWLockRelease(pgss->lock);
  }
  
  /*
--- 1771,1779 ----
  		e->counters.usage += usage;
  		SpinLockRelease(&e->mutex);
  	}
  	LWLockRelease(pgss->lock);
+ 	if (norm_query)
+ 		pfree(norm_query);
  }
  
  /*
*************** pg_stat_statements(PG_FUNCTION_ARGS)
*** 857,869 ****
  		values[i++] = ObjectIdGetDatum(entry->key.userid);
  		values[i++] = ObjectIdGetDatum(entry->key.dbid);
  
  		if (is_superuser || entry->key.userid == userid)
  		{
  			char	   *qstr;
  
  			qstr = (char *)
  				pg_do_encoding_conversion((unsigned char *) entry->query,
! 										  entry->key.query_len,
  										  entry->key.encoding,
  										  GetDatabaseEncoding());
  			values[i++] = CStringGetTextDatum(qstr);
--- 1854,1875 ----
  		values[i++] = ObjectIdGetDatum(entry->key.userid);
  		values[i++] = ObjectIdGetDatum(entry->key.dbid);
  
+ 		/* copy counters to a local variable to keep locking time short */
+ 		{
+ 			volatile pgssEntry *e = (volatile pgssEntry *) entry;
+ 
+ 			SpinLockAcquire(&e->mutex);
+ 			tmp = e->counters;
+ 			SpinLockRelease(&e->mutex);
+ 		}
+ 
  		if (is_superuser || entry->key.userid == userid)
  		{
  			char	   *qstr;
  
  			qstr = (char *)
  				pg_do_encoding_conversion((unsigned char *) entry->query,
! 										  entry->query_len,
  										  entry->key.encoding,
  										  GetDatabaseEncoding());
  			values[i++] = CStringGetTextDatum(qstr);
*************** pg_stat_statements(PG_FUNCTION_ARGS)
*** 873,887 ****
  		else
  			values[i++] = CStringGetTextDatum("<insufficient privilege>");
  
- 		/* copy counters to a local variable to keep locking time short */
- 		{
- 			volatile pgssEntry *e = (volatile pgssEntry *) entry;
- 
- 			SpinLockAcquire(&e->mutex);
- 			tmp = e->counters;
- 			SpinLockRelease(&e->mutex);
- 		}
- 
  		values[i++] = Int64GetDatumFast(tmp.calls);
  		values[i++] = Float8GetDatumFast(tmp.total_time);
  		values[i++] = Int64GetDatumFast(tmp.rows);
--- 1879,1884 ----
*************** pgss_memsize(void)
*** 933,946 ****
   * have made the entry while we waited to get exclusive lock.
   */
  static pgssEntry *
! entry_alloc(pgssHashKey *key)
  {
  	pgssEntry  *entry;
  	bool		found;
  
- 	/* Caller must have clipped query properly */
- 	Assert(key->query_len < pgss->query_size);
- 
  	/* Make space if needed */
  	while (hash_get_num_entries(pgss_hash) >= pgss_max)
  		entry_dealloc();
--- 1930,1940 ----
   * have made the entry while we waited to get exclusive lock.
   */
  static pgssEntry *
! entry_alloc(pgssHashKey *key, const char* query, int new_query_len)
  {
  	pgssEntry  *entry;
  	bool		found;
  
  	/* Make space if needed */
  	while (hash_get_num_entries(pgss_hash) >= pgss_max)
  		entry_dealloc();
*************** entry_alloc(pgssHashKey *key)
*** 950,968 ****
  
  	if (!found)
  	{
  		/* New entry, initialize it */
  
- 		/* dynahash tried to copy the key for us, but must fix query_ptr */
- 		entry->key.query_ptr = entry->query;
  		/* reset the statistics */
  		memset(&entry->counters, 0, sizeof(Counters));
  		entry->counters.usage = USAGE_INIT;
  		/* re-initialize the mutex each time ... we assume no one using it */
  		SpinLockInit(&entry->mutex);
  		/* ... and don't forget the query text */
! 		memcpy(entry->query, key->query_ptr, key->query_len);
! 		entry->query[key->query_len] = '\0';
  	}
  
  	return entry;
  }
--- 1944,1964 ----
  
  	if (!found)
  	{
+ 		entry->query_len = new_query_len;
+ 		Assert(entry->query_len > 0);
  		/* New entry, initialize it */
  
  		/* reset the statistics */
  		memset(&entry->counters, 0, sizeof(Counters));
  		entry->counters.usage = USAGE_INIT;
  		/* re-initialize the mutex each time ... we assume no one using it */
  		SpinLockInit(&entry->mutex);
  		/* ... and don't forget the query text */
! 		memcpy(entry->query, query, entry->query_len);
! 		entry->query[entry->query_len] = '\0';
  	}
+ 	/* Caller must have clipped query properly */
+ 	Assert(entry->query_len < pgss->query_size);
  
  	return entry;
  }
*************** entry_alloc(pgssHashKey *key)
*** 971,977 ****
   * qsort comparator for sorting into increasing usage order
   */
  static int
! entry_cmp(const void *lhs, const void *rhs)
  {
  	double		l_usage = (*(pgssEntry * const *) lhs)->counters.usage;
  	double		r_usage = (*(pgssEntry * const *) rhs)->counters.usage;
--- 1967,1973 ----
   * qsort comparator for sorting into increasing usage order
   */
  static int
! entry_cmp_usage(const void *lhs, const void *rhs)
  {
  	double		l_usage = (*(pgssEntry * const *) lhs)->counters.usage;
  	double		r_usage = (*(pgssEntry * const *) rhs)->counters.usage;
*************** entry_dealloc(void)
*** 1009,1015 ****
  		entry->counters.usage *= USAGE_DECREASE_FACTOR;
  	}
  
! 	qsort(entries, i, sizeof(pgssEntry *), entry_cmp);
  	nvictims = Max(10, i * USAGE_DEALLOC_PERCENT / 100);
  	nvictims = Min(nvictims, i);
  
--- 2005,2011 ----
  		entry->counters.usage *= USAGE_DECREASE_FACTOR;
  	}
  
! 	qsort(entries, i, sizeof(pgssEntry *), entry_cmp_usage);
  	nvictims = Max(10, i * USAGE_DEALLOC_PERCENT / 100);
  	nvictims = Min(nvictims, i);
  
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index e11d896..ccd92d3 100644
*** a/src/backend/catalog/heap.c
--- b/src/backend/catalog/heap.c
*************** cookDefault(ParseState *pstate,
*** 2441,2447 ****
  									 atttypid, atttypmod,
  									 COERCION_ASSIGNMENT,
  									 COERCE_IMPLICIT_CAST,
! 									 -1);
  		if (expr == NULL)
  			ereport(ERROR,
  					(errcode(ERRCODE_DATATYPE_MISMATCH),
--- 2441,2447 ----
  									 atttypid, atttypmod,
  									 COERCION_ASSIGNMENT,
  									 COERCE_IMPLICIT_CAST,
! 									 -1, -1);
  		if (expr == NULL)
  			ereport(ERROR,
  					(errcode(ERRCODE_DATATYPE_MISMATCH),
diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c
index a949215..e80d57f 100644
*** a/src/backend/commands/prepare.c
--- b/src/backend/commands/prepare.c
*************** EvaluateParams(PreparedStatement *pstmt,
*** 365,371 ****
  									 expected_type_id, -1,
  									 COERCION_ASSIGNMENT,
  									 COERCE_IMPLICIT_CAST,
! 									 -1);
  
  		if (expr == NULL)
  			ereport(ERROR,
--- 365,371 ----
  									 expected_type_id, -1,
  									 COERCION_ASSIGNMENT,
  									 COERCE_IMPLICIT_CAST,
! 									 -1, -1);
  
  		if (expr == NULL)
  			ereport(ERROR,
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 1ee201c..f6b64d5 100644
*** a/src/backend/commands/tablecmds.c
--- b/src/backend/commands/tablecmds.c
*************** ATExecAddColumn(List **wqueue, AlteredTa
*** 4493,4499 ****
  													typmod,
  													COERCION_ASSIGNMENT,
  													COERCE_IMPLICIT_CAST,
! 													-1);
  			if (defval == NULL) /* should not happen */
  				elog(ERROR, "failed to coerce base type to domain");
  		}
--- 4493,4499 ----
  													typmod,
  													COERCION_ASSIGNMENT,
  													COERCE_IMPLICIT_CAST,
! 													-1, -1);
  			if (defval == NULL) /* should not happen */
  				elog(ERROR, "failed to coerce base type to domain");
  		}
*************** ATPrepAlterColumnType(List **wqueue,
*** 6987,6993 ****
  										  targettype, targettypmod,
  										  COERCION_ASSIGNMENT,
  										  COERCE_IMPLICIT_CAST,
! 										  -1);
  		if (transform == NULL)
  			ereport(ERROR,
  					(errcode(ERRCODE_DATATYPE_MISMATCH),
--- 6987,6993 ----
  										  targettype, targettypmod,
  										  COERCION_ASSIGNMENT,
  										  COERCE_IMPLICIT_CAST,
! 										  -1, -1);
  		if (transform == NULL)
  			ereport(ERROR,
  					(errcode(ERRCODE_DATATYPE_MISMATCH),
*************** ATExecAlterColumnType(AlteredTableInfo *
*** 7154,7160 ****
  											targettype, targettypmod,
  											COERCION_ASSIGNMENT,
  											COERCE_IMPLICIT_CAST,
! 											-1);
  		if (defaultexpr == NULL)
  			ereport(ERROR,
  					(errcode(ERRCODE_DATATYPE_MISMATCH),
--- 7154,7160 ----
  											targettype, targettypmod,
  											COERCION_ASSIGNMENT,
  											COERCE_IMPLICIT_CAST,
! 											-1, -1);
  		if (defaultexpr == NULL)
  			ereport(ERROR,
  					(errcode(ERRCODE_DATATYPE_MISMATCH),
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 7178b52..c40a1bf 100644
*** a/src/backend/nodes/copyfuncs.c
--- b/src/backend/nodes/copyfuncs.c
*************** _copyAConst(const A_Const *from)
*** 2130,2135 ****
--- 2130,2136 ----
  	}
  
  	COPY_LOCATION_FIELD(location);
+ 	COPY_LOCATION_FIELD(tok_len);
  
  	return newnode;
  }
*************** _copyTypeCast(const TypeCast *from)
*** 2284,2289 ****
--- 2285,2291 ----
  	COPY_NODE_FIELD(arg);
  	COPY_NODE_FIELD(typeName);
  	COPY_LOCATION_FIELD(location);
+ 	COPY_LOCATION_FIELD(tok_len);
  
  	return newnode;
  }
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index c3e0ee1..1569b7d 100644
*** a/src/backend/parser/gram.y
--- b/src/backend/parser/gram.y
***************
*** 65,71 ****
  #include "utils/numeric.h"
  #include "utils/xml.h"
  
- 
  /* Location tracking support --- simpler than bison's default */
  #define YYLLOC_DEFAULT(Current, Rhs, N) \
  	do { \
--- 65,70 ----
*************** static void base_yyerror(YYLTYPE *yylloc
*** 109,123 ****
  						 const char *msg);
  static Node *makeColumnRef(char *colname, List *indirection,
  						   int location, core_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);
! static Node *makeIntConst(int val, int location);
! static Node *makeFloatConst(char *str, int location);
! 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, core_yyscan_t yyscanner);
  static void check_qualified_name(List *names, core_yyscan_t yyscanner);
--- 108,122 ----
  						 const char *msg);
  static Node *makeColumnRef(char *colname, List *indirection,
  						   int location, core_yyscan_t yyscanner);
! static Node *makeTypeCast(Node *arg, TypeName *typename, int location, int length);
! static Node *makeStringConst(char *str, int location, int length);
! static Node *makeStringConstCast(char *str, int location, int length, TypeName *typename);
! static Node *makeIntConst(int val, int location, int length);
! static Node *makeFloatConst(char *str, int location, int length);
! static Node *makeBitStringConst(char *str, int location, int length);
! static Node *makeNullAConst(int location, int length);
! static Node *makeAConst(Value *v, int location, int length);
! static Node *makeBoolAConst(bool state, int location, int length);
  static FuncCall *makeOverlaps(List *largs, List *rargs,
  							  int location, core_yyscan_t yyscanner);
  static void check_qualified_name(List *names, core_yyscan_t yyscanner);
*************** static void insertSelectOptions(SelectSt
*** 131,137 ****
  								WithClause *withClause,
  								core_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);
  static Node *makeAArrayExpr(List *elements, int location);
  static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args,
--- 130,136 ----
  								WithClause *withClause,
  								core_yyscan_t yyscanner);
  static Node *makeSetOp(SetOperation op, bool all, Node *larg, Node *rarg);
! static Node *doNegate(Node *n, int location, int length);
  static void doNegateFloat(Value *v);
  static Node *makeAArrayExpr(List *elements, int location);
  static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args,
*************** AlterOptRoleElem:
*** 912,918 ****
  						ereport(ERROR,
  								(errcode(ERRCODE_SYNTAX_ERROR),
  								 errmsg("unrecognized role option \"%s\"", $1),
! 									 parser_errposition(@1)));
  				}
  		;
  
--- 911,917 ----
  						ereport(ERROR,
  								(errcode(ERRCODE_SYNTAX_ERROR),
  								 errmsg("unrecognized role option \"%s\"", $1),
! 									 parser_errposition(@1.begins)));
  				}
  		;
  
*************** set_rest:	/* Generic SET syntaxes: */
*** 1298,1304 ****
  					ereport(ERROR,
  							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
  							 errmsg("current database cannot be changed"),
! 							 parser_errposition(@2)));
  					$$ = NULL; /*not reached*/
  				}
  			| SCHEMA Sconst
--- 1297,1303 ----
  					ereport(ERROR,
  							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
  							 errmsg("current database cannot be changed"),
! 							 parser_errposition(@2.begins)));
  					$$ = NULL; /*not reached*/
  				}
  			| SCHEMA Sconst
*************** set_rest:	/* Generic SET syntaxes: */
*** 1306,1312 ****
  					VariableSetStmt *n = makeNode(VariableSetStmt);
  					n->kind = VAR_SET_VALUE;
  					n->name = "search_path";
! 					n->args = list_make1(makeStringConst($2, @2));
  					$$ = n;
  				}
  			| NAMES opt_encoding
--- 1305,1311 ----
  					VariableSetStmt *n = makeNode(VariableSetStmt);
  					n->kind = VAR_SET_VALUE;
  					n->name = "search_path";
! 					n->args = list_make1(makeStringConst($2, @2.begins, @2.length));
  					$$ = n;
  				}
  			| NAMES opt_encoding
*************** set_rest:	/* Generic SET syntaxes: */
*** 1315,1321 ****
  					n->kind = VAR_SET_VALUE;
  					n->name = "client_encoding";
  					if ($2 != NULL)
! 						n->args = list_make1(makeStringConst($2, @2));
  					else
  						n->kind = VAR_SET_DEFAULT;
  					$$ = n;
--- 1314,1320 ----
  					n->kind = VAR_SET_VALUE;
  					n->name = "client_encoding";
  					if ($2 != NULL)
! 						n->args = list_make1(makeStringConst($2, @2.begins, @2.length));
  					else
  						n->kind = VAR_SET_DEFAULT;
  					$$ = n;
*************** set_rest:	/* Generic SET syntaxes: */
*** 1325,1331 ****
  					VariableSetStmt *n = makeNode(VariableSetStmt);
  					n->kind = VAR_SET_VALUE;
  					n->name = "role";
! 					n->args = list_make1(makeStringConst($2, @2));
  					$$ = n;
  				}
  			| SESSION AUTHORIZATION ColId_or_Sconst
--- 1324,1330 ----
  					VariableSetStmt *n = makeNode(VariableSetStmt);
  					n->kind = VAR_SET_VALUE;
  					n->name = "role";
! 					n->args = list_make1(makeStringConst($2, @2.begins, @2.length));
  					$$ = n;
  				}
  			| SESSION AUTHORIZATION ColId_or_Sconst
*************** set_rest:	/* Generic SET syntaxes: */
*** 1333,1339 ****
  					VariableSetStmt *n = makeNode(VariableSetStmt);
  					n->kind = VAR_SET_VALUE;
  					n->name = "session_authorization";
! 					n->args = list_make1(makeStringConst($3, @3));
  					$$ = n;
  				}
  			| SESSION AUTHORIZATION DEFAULT
--- 1332,1338 ----
  					VariableSetStmt *n = makeNode(VariableSetStmt);
  					n->kind = VAR_SET_VALUE;
  					n->name = "session_authorization";
! 					n->args = list_make1(makeStringConst($3, @3.begins, @3.length));
  					$$ = n;
  				}
  			| SESSION AUTHORIZATION DEFAULT
*************** set_rest:	/* Generic SET syntaxes: */
*** 1348,1354 ****
  					VariableSetStmt *n = makeNode(VariableSetStmt);
  					n->kind = VAR_SET_VALUE;
  					n->name = "xmloption";
! 					n->args = list_make1(makeStringConst($3 == XMLOPTION_DOCUMENT ? "DOCUMENT" : "CONTENT", @3));
  					$$ = n;
  				}
  			/* Special syntaxes invented by PostgreSQL: */
--- 1347,1353 ----
  					VariableSetStmt *n = makeNode(VariableSetStmt);
  					n->kind = VAR_SET_VALUE;
  					n->name = "xmloption";
! 					n->args = list_make1(makeStringConst($3 == XMLOPTION_DOCUMENT ? "DOCUMENT" : "CONTENT", @3.begins, @3.length));
  					$$ = n;
  				}
  			/* Special syntaxes invented by PostgreSQL: */
*************** set_rest:	/* Generic SET syntaxes: */
*** 1357,1363 ****
  					VariableSetStmt *n = makeNode(VariableSetStmt);
  					n->kind = VAR_SET_MULTI;
  					n->name = "TRANSACTION SNAPSHOT";
! 					n->args = list_make1(makeStringConst($3, @3));
  					$$ = n;
  				}
  		;
--- 1356,1362 ----
  					VariableSetStmt *n = makeNode(VariableSetStmt);
  					n->kind = VAR_SET_MULTI;
  					n->name = "TRANSACTION SNAPSHOT";
! 					n->args = list_make1(makeStringConst($3, @3.begins, @3.length));
  					$$ = n;
  				}
  		;
*************** var_list:	var_value								{ $$ = list_m
*** 1375,1383 ****
  		;
  
  var_value:	opt_boolean_or_string
! 				{ $$ = makeStringConst($1, @1); }
  			| NumericOnly
! 				{ $$ = makeAConst($1, @1); }
  		;
  
  iso_level:	READ UNCOMMITTED						{ $$ = "read uncommitted"; }
--- 1374,1382 ----
  		;
  
  var_value:	opt_boolean_or_string
! 				{ $$ = makeStringConst($1, @1.begins, @1.length); }
  			| NumericOnly
! 				{ $$ = makeAConst($1, @1.begins, @1.length); }
  		;
  
  iso_level:	READ UNCOMMITTED						{ $$ = "read uncommitted"; }
*************** opt_boolean_or_string:
*** 1409,1419 ****
  zone_value:
  			Sconst
  				{
! 					$$ = makeStringConst($1, @1);
  				}
  			| IDENT
  				{
! 					$$ = makeStringConst($1, @1);
  				}
  			| ConstInterval Sconst opt_interval
  				{
--- 1408,1418 ----
  zone_value:
  			Sconst
  				{
! 					$$ = makeStringConst($1, @1.begins, @1.length);
  				}
  			| IDENT
  				{
! 					$$ = makeStringConst($1, @1.begins, @1.length);
  				}
  			| ConstInterval Sconst opt_interval
  				{
*************** zone_value:
*** 1425,1434 ****
  							ereport(ERROR,
  									(errcode(ERRCODE_SYNTAX_ERROR),
  									 errmsg("time zone interval must be HOUR or HOUR TO MINUTE"),
! 									 parser_errposition(@3)));
  					}
  					t->typmods = $3;
! 					$$ = makeStringConstCast($2, @2, t);
  				}
  			| ConstInterval '(' Iconst ')' Sconst opt_interval
  				{
--- 1424,1433 ----
  							ereport(ERROR,
  									(errcode(ERRCODE_SYNTAX_ERROR),
  									 errmsg("time zone interval must be HOUR or HOUR TO MINUTE"),
! 									 parser_errposition(@3.begins)));
  					}
  					t->typmods = $3;
! 					$$ = makeStringConstCast($2, @2.begins, @2.length, t);
  				}
  			| ConstInterval '(' Iconst ')' Sconst opt_interval
  				{
*************** zone_value:
*** 1440,1459 ****
  							ereport(ERROR,
  									(errcode(ERRCODE_SYNTAX_ERROR),
  									 errmsg("time zone interval must be HOUR or HOUR TO MINUTE"),
! 									 parser_errposition(@6)));
  						if (list_length($6) != 1)
  							ereport(ERROR,
  									(errcode(ERRCODE_SYNTAX_ERROR),
  									 errmsg("interval precision specified twice"),
! 									 parser_errposition(@1)));
! 						t->typmods = lappend($6, makeIntConst($3, @3));
  					}
  					else
! 						t->typmods = list_make2(makeIntConst(INTERVAL_FULL_RANGE, -1),
! 												makeIntConst($3, @3));
! 					$$ = makeStringConstCast($5, @5, t);
  				}
! 			| NumericOnly							{ $$ = makeAConst($1, @1); }
  			| DEFAULT								{ $$ = NULL; }
  			| LOCAL									{ $$ = NULL; }
  		;
--- 1439,1458 ----
  							ereport(ERROR,
  									(errcode(ERRCODE_SYNTAX_ERROR),
  									 errmsg("time zone interval must be HOUR or HOUR TO MINUTE"),
! 									 parser_errposition(@6.begins)));
  						if (list_length($6) != 1)
  							ereport(ERROR,
  									(errcode(ERRCODE_SYNTAX_ERROR),
  									 errmsg("interval precision specified twice"),
! 									 parser_errposition(@1.begins)));
! 						t->typmods = lappend($6, makeIntConst($3, @3.begins, @3.length));
  					}
  					else
! 						t->typmods = list_make2(makeIntConst(INTERVAL_FULL_RANGE, -1, -1),
! 												makeIntConst($3, @3.begins, @3.length));
! 					$$ = makeStringConstCast($5, @5.begins, @5.length, t);
  				}
! 			| NumericOnly							{ $$ = makeAConst($1, @1.begins, @1.length); }
  			| DEFAULT								{ $$ = NULL; }
  			| LOCAL									{ $$ = NULL; }
  		;
*************** alter_table_cmd:
*** 1965,1971 ****
  				{
  					AlterTableCmd *n = makeNode(AlterTableCmd);
  					TypeName *def = makeTypeNameFromNameList($2);
! 					def->location = @2;
  					n->subtype = AT_AddOf;
  					n->def = (Node *) def;
  					$$ = (Node *)n;
--- 1964,1970 ----
  				{
  					AlterTableCmd *n = makeNode(AlterTableCmd);
  					TypeName *def = makeTypeNameFromNameList($2);
! 					def->location = @2.begins;
  					n->subtype = AT_AddOf;
  					n->def = (Node *) def;
  					$$ = (Node *)n;
*************** opt_collate_clause:
*** 2035,2041 ****
  					CollateClause *n = makeNode(CollateClause);
  					n->arg = NULL;
  					n->collname = $2;
! 					n->location = @1;
  					$$ = (Node *) n;
  				}
  			| /* EMPTY */				{ $$ = NULL; }
--- 2034,2040 ----
  					CollateClause *n = makeNode(CollateClause);
  					n->arg = NULL;
  					n->collname = $2;
! 					n->location = @1.begins;
  					$$ = (Node *) n;
  				}
  			| /* EMPTY */				{ $$ = NULL; }
*************** AlterCompositeTypeStmt:
*** 2094,2100 ****
  					AlterTableStmt *n = makeNode(AlterTableStmt);
  
  					/* can't use qualified_name, sigh */
! 					n->relation = makeRangeVarFromAnyName($3, @3, yyscanner);
  					n->cmds = $4;
  					n->relkind = OBJECT_TYPE;
  					$$ = (Node *)n;
--- 2093,2099 ----
  					AlterTableStmt *n = makeNode(AlterTableStmt);
  
  					/* can't use qualified_name, sigh */
! 					n->relation = makeRangeVarFromAnyName($3, @3.begins, yyscanner);
  					n->cmds = $4;
  					n->relkind = OBJECT_TYPE;
  					$$ = (Node *)n;
*************** CreateStmt:	CREATE OptTemp TABLE qualifi
*** 2428,2434 ****
  					n->relation = $4;
  					n->tableElts = $7;
  					n->ofTypename = makeTypeNameFromNameList($6);
! 					n->ofTypename->location = @6;
  					n->constraints = NIL;
  					n->options = $8;
  					n->oncommit = $9;
--- 2427,2433 ----
  					n->relation = $4;
  					n->tableElts = $7;
  					n->ofTypename = makeTypeNameFromNameList($6);
! 					n->ofTypename->location = @6.begins;
  					n->constraints = NIL;
  					n->options = $8;
  					n->oncommit = $9;
*************** CreateStmt:	CREATE OptTemp TABLE qualifi
*** 2444,2450 ****
  					n->relation = $7;
  					n->tableElts = $10;
  					n->ofTypename = makeTypeNameFromNameList($9);
! 					n->ofTypename->location = @9;
  					n->constraints = NIL;
  					n->options = $11;
  					n->oncommit = $12;
--- 2443,2449 ----
  					n->relation = $7;
  					n->tableElts = $10;
  					n->ofTypename = makeTypeNameFromNameList($9);
! 					n->ofTypename->location = @9.begins;
  					n->constraints = NIL;
  					n->options = $11;
  					n->oncommit = $12;
*************** ColConstraint:
*** 2564,2570 ****
  					Constraint *n = (Constraint *) $3;
  					Assert(IsA(n, Constraint));
  					n->conname = $2;
! 					n->location = @1;
  					$$ = (Node *) n;
  				}
  			| ColConstraintElem						{ $$ = $1; }
--- 2563,2569 ----
  					Constraint *n = (Constraint *) $3;
  					Assert(IsA(n, Constraint));
  					n->conname = $2;
! 					n->location = @1.begins;
  					$$ = (Node *) n;
  				}
  			| ColConstraintElem						{ $$ = $1; }
*************** ColConstraint:
*** 2579,2585 ****
  					CollateClause *n = makeNode(CollateClause);
  					n->arg = NULL;
  					n->collname = $2;
! 					n->location = @1;
  					$$ = (Node *) n;
  				}
  		;
--- 2578,2584 ----
  					CollateClause *n = makeNode(CollateClause);
  					n->arg = NULL;
  					n->collname = $2;
! 					n->location = @1.begins;
  					$$ = (Node *) n;
  				}
  		;
*************** ColConstraintElem:
*** 2604,2624 ****
  				{
  					Constraint *n = makeNode(Constraint);
  					n->contype = CONSTR_NOTNULL;
! 					n->location = @1;
  					$$ = (Node *)n;
  				}
  			| NULL_P
  				{
  					Constraint *n = makeNode(Constraint);
  					n->contype = CONSTR_NULL;
! 					n->location = @1;
  					$$ = (Node *)n;
  				}
  			| UNIQUE opt_definition OptConsTableSpace
  				{
  					Constraint *n = makeNode(Constraint);
  					n->contype = CONSTR_UNIQUE;
! 					n->location = @1;
  					n->keys = NULL;
  					n->options = $2;
  					n->indexname = NULL;
--- 2603,2623 ----
  				{
  					Constraint *n = makeNode(Constraint);
  					n->contype = CONSTR_NOTNULL;
! 					n->location = @1.begins;
  					$$ = (Node *)n;
  				}
  			| NULL_P
  				{
  					Constraint *n = makeNode(Constraint);
  					n->contype = CONSTR_NULL;
! 					n->location = @1.begins;
  					$$ = (Node *)n;
  				}
  			| UNIQUE opt_definition OptConsTableSpace
  				{
  					Constraint *n = makeNode(Constraint);
  					n->contype = CONSTR_UNIQUE;
! 					n->location = @1.begins;
  					n->keys = NULL;
  					n->options = $2;
  					n->indexname = NULL;
*************** ColConstraintElem:
*** 2629,2635 ****
  				{
  					Constraint *n = makeNode(Constraint);
  					n->contype = CONSTR_PRIMARY;
! 					n->location = @1;
  					n->keys = NULL;
  					n->options = $3;
  					n->indexname = NULL;
--- 2628,2634 ----
  				{
  					Constraint *n = makeNode(Constraint);
  					n->contype = CONSTR_PRIMARY;
! 					n->location = @1.begins;
  					n->keys = NULL;
  					n->options = $3;
  					n->indexname = NULL;
*************** ColConstraintElem:
*** 2640,2646 ****
  				{
  					Constraint *n = makeNode(Constraint);
  					n->contype = CONSTR_CHECK;
! 					n->location = @1;
  					n->raw_expr = $3;
  					n->cooked_expr = NULL;
  					$$ = (Node *)n;
--- 2639,2645 ----
  				{
  					Constraint *n = makeNode(Constraint);
  					n->contype = CONSTR_CHECK;
! 					n->location = @1.begins;
  					n->raw_expr = $3;
  					n->cooked_expr = NULL;
  					$$ = (Node *)n;
*************** ColConstraintElem:
*** 2649,2655 ****
  				{
  					Constraint *n = makeNode(Constraint);
  					n->contype = CONSTR_DEFAULT;
! 					n->location = @1;
  					n->raw_expr = $2;
  					n->cooked_expr = NULL;
  					$$ = (Node *)n;
--- 2648,2654 ----
  				{
  					Constraint *n = makeNode(Constraint);
  					n->contype = CONSTR_DEFAULT;
! 					n->location = @1.begins;
  					n->raw_expr = $2;
  					n->cooked_expr = NULL;
  					$$ = (Node *)n;
*************** ColConstraintElem:
*** 2658,2664 ****
  				{
  					Constraint *n = makeNode(Constraint);
  					n->contype = CONSTR_FOREIGN;
! 					n->location = @1;
  					n->pktable			= $2;
  					n->fk_attrs			= NIL;
  					n->pk_attrs			= $3;
--- 2657,2663 ----
  				{
  					Constraint *n = makeNode(Constraint);
  					n->contype = CONSTR_FOREIGN;
! 					n->location = @1.begins;
  					n->pktable			= $2;
  					n->fk_attrs			= NIL;
  					n->pk_attrs			= $3;
*************** ConstraintAttr:
*** 2691,2718 ****
  				{
  					Constraint *n = makeNode(Constraint);
  					n->contype = CONSTR_ATTR_DEFERRABLE;
! 					n->location = @1;
  					$$ = (Node *)n;
  				}
  			| NOT DEFERRABLE
  				{
  					Constraint *n = makeNode(Constraint);
  					n->contype = CONSTR_ATTR_NOT_DEFERRABLE;
! 					n->location = @1;
  					$$ = (Node *)n;
  				}
  			| INITIALLY DEFERRED
  				{
  					Constraint *n = makeNode(Constraint);
  					n->contype = CONSTR_ATTR_DEFERRED;
! 					n->location = @1;
  					$$ = (Node *)n;
  				}
  			| INITIALLY IMMEDIATE
  				{
  					Constraint *n = makeNode(Constraint);
  					n->contype = CONSTR_ATTR_IMMEDIATE;
! 					n->location = @1;
  					$$ = (Node *)n;
  				}
  		;
--- 2690,2717 ----
  				{
  					Constraint *n = makeNode(Constraint);
  					n->contype = CONSTR_ATTR_DEFERRABLE;
! 					n->location = @1.begins;
  					$$ = (Node *)n;
  				}
  			| NOT DEFERRABLE
  				{
  					Constraint *n = makeNode(Constraint);
  					n->contype = CONSTR_ATTR_NOT_DEFERRABLE;
! 					n->location = @1.begins;
  					$$ = (Node *)n;
  				}
  			| INITIALLY DEFERRED
  				{
  					Constraint *n = makeNode(Constraint);
  					n->contype = CONSTR_ATTR_DEFERRED;
! 					n->location = @1.begins;
  					$$ = (Node *)n;
  				}
  			| INITIALLY IMMEDIATE
  				{
  					Constraint *n = makeNode(Constraint);
  					n->contype = CONSTR_ATTR_IMMEDIATE;
! 					n->location = @1.begins;
  					$$ = (Node *)n;
  				}
  		;
*************** TableConstraint:
*** 2762,2768 ****
  					Constraint *n = (Constraint *) $3;
  					Assert(IsA(n, Constraint));
  					n->conname = $2;
! 					n->location = @1;
  					$$ = (Node *) n;
  				}
  			| ConstraintElem						{ $$ = $1; }
--- 2761,2767 ----
  					Constraint *n = (Constraint *) $3;
  					Assert(IsA(n, Constraint));
  					n->conname = $2;
! 					n->location = @1.begins;
  					$$ = (Node *) n;
  				}
  			| ConstraintElem						{ $$ = $1; }
*************** ConstraintElem:
*** 2773,2782 ****
  				{
  					Constraint *n = makeNode(Constraint);
  					n->contype = CONSTR_CHECK;
! 					n->location = @1;
  					n->raw_expr = $3;
  					n->cooked_expr = NULL;
! 					processCASbits($5, @5, "CHECK",
  								   NULL, NULL, &n->skip_validation,
  								   yyscanner);
  					n->initially_valid = !n->skip_validation;
--- 2772,2781 ----
  				{
  					Constraint *n = makeNode(Constraint);
  					n->contype = CONSTR_CHECK;
! 					n->location = @1.begins;
  					n->raw_expr = $3;
  					n->cooked_expr = NULL;
! 					processCASbits($5, @5.begins, "CHECK",
  								   NULL, NULL, &n->skip_validation,
  								   yyscanner);
  					n->initially_valid = !n->skip_validation;
*************** ConstraintElem:
*** 2787,2798 ****
  				{
  					Constraint *n = makeNode(Constraint);
  					n->contype = CONSTR_UNIQUE;
! 					n->location = @1;
  					n->keys = $3;
  					n->options = $5;
  					n->indexname = NULL;
  					n->indexspace = $6;
! 					processCASbits($7, @7, "UNIQUE",
  								   &n->deferrable, &n->initdeferred, NULL,
  								   yyscanner);
  					$$ = (Node *)n;
--- 2786,2797 ----
  				{
  					Constraint *n = makeNode(Constraint);
  					n->contype = CONSTR_UNIQUE;
! 					n->location = @1.begins;
  					n->keys = $3;
  					n->options = $5;
  					n->indexname = NULL;
  					n->indexspace = $6;
! 					processCASbits($7, @7.begins, "UNIQUE",
  								   &n->deferrable, &n->initdeferred, NULL,
  								   yyscanner);
  					$$ = (Node *)n;
*************** ConstraintElem:
*** 2801,2812 ****
  				{
  					Constraint *n = makeNode(Constraint);
  					n->contype = CONSTR_UNIQUE;
! 					n->location = @1;
  					n->keys = NIL;
  					n->options = NIL;
  					n->indexname = $2;
  					n->indexspace = NULL;
! 					processCASbits($3, @3, "UNIQUE",
  								   &n->deferrable, &n->initdeferred, NULL,
  								   yyscanner);
  					$$ = (Node *)n;
--- 2800,2811 ----
  				{
  					Constraint *n = makeNode(Constraint);
  					n->contype = CONSTR_UNIQUE;
! 					n->location = @1.begins;
  					n->keys = NIL;
  					n->options = NIL;
  					n->indexname = $2;
  					n->indexspace = NULL;
! 					processCASbits($3, @3.begins, "UNIQUE",
  								   &n->deferrable, &n->initdeferred, NULL,
  								   yyscanner);
  					$$ = (Node *)n;
*************** ConstraintElem:
*** 2816,2827 ****
  				{
  					Constraint *n = makeNode(Constraint);
  					n->contype = CONSTR_PRIMARY;
! 					n->location = @1;
  					n->keys = $4;
  					n->options = $6;
  					n->indexname = NULL;
  					n->indexspace = $7;
! 					processCASbits($8, @8, "PRIMARY KEY",
  								   &n->deferrable, &n->initdeferred, NULL,
  								   yyscanner);
  					$$ = (Node *)n;
--- 2815,2826 ----
  				{
  					Constraint *n = makeNode(Constraint);
  					n->contype = CONSTR_PRIMARY;
! 					n->location = @1.begins;
  					n->keys = $4;
  					n->options = $6;
  					n->indexname = NULL;
  					n->indexspace = $7;
! 					processCASbits($8, @8.begins, "PRIMARY KEY",
  								   &n->deferrable, &n->initdeferred, NULL,
  								   yyscanner);
  					$$ = (Node *)n;
*************** ConstraintElem:
*** 2830,2841 ****
  				{
  					Constraint *n = makeNode(Constraint);
  					n->contype = CONSTR_PRIMARY;
! 					n->location = @1;
  					n->keys = NIL;
  					n->options = NIL;
  					n->indexname = $3;
  					n->indexspace = NULL;
! 					processCASbits($4, @4, "PRIMARY KEY",
  								   &n->deferrable, &n->initdeferred, NULL,
  								   yyscanner);
  					$$ = (Node *)n;
--- 2829,2840 ----
  				{
  					Constraint *n = makeNode(Constraint);
  					n->contype = CONSTR_PRIMARY;
! 					n->location = @1.begins;
  					n->keys = NIL;
  					n->options = NIL;
  					n->indexname = $3;
  					n->indexspace = NULL;
! 					processCASbits($4, @4.begins, "PRIMARY KEY",
  								   &n->deferrable, &n->initdeferred, NULL,
  								   yyscanner);
  					$$ = (Node *)n;
*************** ConstraintElem:
*** 2846,2859 ****
  				{
  					Constraint *n = makeNode(Constraint);
  					n->contype = CONSTR_EXCLUSION;
! 					n->location = @1;
  					n->access_method	= $2;
  					n->exclusions		= $4;
  					n->options			= $6;
  					n->indexname		= NULL;
  					n->indexspace		= $7;
  					n->where_clause		= $8;
! 					processCASbits($9, @9, "EXCLUDE",
  								   &n->deferrable, &n->initdeferred, NULL,
  								   yyscanner);
  					$$ = (Node *)n;
--- 2845,2858 ----
  				{
  					Constraint *n = makeNode(Constraint);
  					n->contype = CONSTR_EXCLUSION;
! 					n->location = @1.begins;
  					n->access_method	= $2;
  					n->exclusions		= $4;
  					n->options			= $6;
  					n->indexname		= NULL;
  					n->indexspace		= $7;
  					n->where_clause		= $8;
! 					processCASbits($9, @9.begins, "EXCLUDE",
  								   &n->deferrable, &n->initdeferred, NULL,
  								   yyscanner);
  					$$ = (Node *)n;
*************** ConstraintElem:
*** 2863,2876 ****
  				{
  					Constraint *n = makeNode(Constraint);
  					n->contype = CONSTR_FOREIGN;
! 					n->location = @1;
  					n->pktable			= $7;
  					n->fk_attrs			= $4;
  					n->pk_attrs			= $8;
  					n->fk_matchtype		= $9;
  					n->fk_upd_action	= (char) ($10 >> 8);
  					n->fk_del_action	= (char) ($10 & 0xFF);
! 					processCASbits($11, @11, "FOREIGN KEY",
  								   &n->deferrable, &n->initdeferred,
  								   &n->skip_validation,
  								   yyscanner);
--- 2862,2875 ----
  				{
  					Constraint *n = makeNode(Constraint);
  					n->contype = CONSTR_FOREIGN;
! 					n->location = @1.begins;
  					n->pktable			= $7;
  					n->fk_attrs			= $4;
  					n->pk_attrs			= $8;
  					n->fk_matchtype		= $9;
  					n->fk_upd_action	= (char) ($10 >> 8);
  					n->fk_del_action	= (char) ($10 & 0xFF);
! 					processCASbits($11, @11.begins, "FOREIGN KEY",
  								   &n->deferrable, &n->initdeferred,
  								   &n->skip_validation,
  								   yyscanner);
*************** key_match:  MATCH FULL
*** 2904,2910 ****
  				ereport(ERROR,
  						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
  						 errmsg("MATCH PARTIAL not yet implemented"),
! 						 parser_errposition(@1)));
  				$$ = FKCONSTR_MATCH_PARTIAL;
  			}
  		| MATCH SIMPLE
--- 2903,2909 ----
  				ereport(ERROR,
  						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
  						 errmsg("MATCH PARTIAL not yet implemented"),
! 						 parser_errposition(@1.begins)));
  				$$ = FKCONSTR_MATCH_PARTIAL;
  			}
  		| MATCH SIMPLE
*************** CreateTrigStmt:
*** 4029,4035 ****
  					n->columns = (List *) lsecond($6);
  					n->whenClause = $14;
  					n->isconstraint  = TRUE;
! 					processCASbits($10, @10, "TRIGGER",
  								   &n->deferrable, &n->initdeferred, NULL,
  								   yyscanner);
  					n->constrrel = $9;
--- 4028,4034 ----
  					n->columns = (List *) lsecond($6);
  					n->whenClause = $14;
  					n->isconstraint  = TRUE;
! 					processCASbits($10, @10.begins, "TRIGGER",
  								   &n->deferrable, &n->initdeferred, NULL,
  								   yyscanner);
  					n->constrrel = $9;
*************** ConstraintAttributeSpec:
*** 4150,4163 ****
  						ereport(ERROR,
  								(errcode(ERRCODE_SYNTAX_ERROR),
  								 errmsg("constraint declared INITIALLY DEFERRED must be DEFERRABLE"),
! 								 parser_errposition(@2)));
  					/* generic message for other conflicts */
  					if ((newspec & (CAS_NOT_DEFERRABLE | CAS_DEFERRABLE)) == (CAS_NOT_DEFERRABLE | CAS_DEFERRABLE) ||
  						(newspec & (CAS_INITIALLY_IMMEDIATE | CAS_INITIALLY_DEFERRED)) == (CAS_INITIALLY_IMMEDIATE | CAS_INITIALLY_DEFERRED))
  						ereport(ERROR,
  								(errcode(ERRCODE_SYNTAX_ERROR),
  								 errmsg("conflicting constraint properties"),
! 								 parser_errposition(@2)));
  					$$ = newspec;
  				}
  		;
--- 4149,4162 ----
  						ereport(ERROR,
  								(errcode(ERRCODE_SYNTAX_ERROR),
  								 errmsg("constraint declared INITIALLY DEFERRED must be DEFERRABLE"),
! 								 parser_errposition(@2.begins)));
  					/* generic message for other conflicts */
  					if ((newspec & (CAS_NOT_DEFERRABLE | CAS_DEFERRABLE)) == (CAS_NOT_DEFERRABLE | CAS_DEFERRABLE) ||
  						(newspec & (CAS_INITIALLY_IMMEDIATE | CAS_INITIALLY_DEFERRED)) == (CAS_INITIALLY_IMMEDIATE | CAS_INITIALLY_DEFERRED))
  						ereport(ERROR,
  								(errcode(ERRCODE_SYNTAX_ERROR),
  								 errmsg("conflicting constraint properties"),
! 								 parser_errposition(@2.begins)));
  					$$ = newspec;
  				}
  		;
*************** CreateAssertStmt:
*** 4211,4217 ****
  					n->trigname = $3;
  					n->args = list_make1($6);
  					n->isconstraint  = TRUE;
! 					processCASbits($8, @8, "ASSERTION",
  								   &n->deferrable, &n->initdeferred, NULL,
  								   yyscanner);
  
--- 4210,4216 ----
  					n->trigname = $3;
  					n->args = list_make1($6);
  					n->isconstraint  = TRUE;
! 					processCASbits($8, @8.begins, "ASSERTION",
  								   &n->deferrable, &n->initdeferred, NULL,
  								   yyscanner);
  
*************** DefineStmt:
*** 4304,4310 ****
  					CompositeTypeStmt *n = makeNode(CompositeTypeStmt);
  
  					/* can't use qualified_name, sigh */
! 					n->typevar = makeRangeVarFromAnyName($3, @3, yyscanner);
  					n->coldeflist = $6;
  					$$ = (Node *)n;
  				}
--- 4303,4309 ----
  					CompositeTypeStmt *n = makeNode(CompositeTypeStmt);
  
  					/* can't use qualified_name, sigh */
! 					n->typevar = makeRangeVarFromAnyName($3, @3.begins, yyscanner);
  					n->coldeflist = $6;
  					$$ = (Node *)n;
  				}
*************** opt_recheck:	RECHECK
*** 4578,4584 ****
  							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
  							 errmsg("RECHECK is no longer required"),
  							 errhint("Update your data type."),
! 							 parser_errposition(@1)));
  					$$ = TRUE;
  				}
  			| /*EMPTY*/						{ $$ = FALSE; }
--- 4577,4583 ----
  							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
  							 errmsg("RECHECK is no longer required"),
  							 errhint("Update your data type."),
! 							 parser_errposition(@1.begins)));
  					$$ = TRUE;
  				}
  			| /*EMPTY*/						{ $$ = FALSE; }
*************** CreateFunctionStmt:
*** 5826,5832 ****
  					n->funcname = $4;
  					n->parameters = mergeTableFuncParameters($5, $9);
  					n->returnType = TableFuncTypeName($9);
! 					n->returnType->location = @7;
  					n->options = $11;
  					n->withClause = $12;
  					$$ = (Node *)n;
--- 5825,5831 ----
  					n->funcname = $4;
  					n->parameters = mergeTableFuncParameters($5, $9);
  					n->returnType = TableFuncTypeName($9);
! 					n->returnType->location = @7.begins;
  					n->options = $11;
  					n->withClause = $12;
  					$$ = (Node *)n;
*************** func_type:	Typename								{ $$ = $1; }
*** 5967,5980 ****
  				{
  					$$ = makeTypeNameFromNameList(lcons(makeString($1), $2));
  					$$->pct_type = true;
! 					$$->location = @1;
  				}
  			| SETOF type_function_name attrs '%' TYPE_P
  				{
  					$$ = makeTypeNameFromNameList(lcons(makeString($2), $3));
  					$$->pct_type = true;
  					$$->setof = TRUE;
! 					$$->location = @2;
  				}
  		;
  
--- 5966,5979 ----
  				{
  					$$ = makeTypeNameFromNameList(lcons(makeString($1), $2));
  					$$->pct_type = true;
! 					$$->location = @1.begins;
  				}
  			| SETOF type_function_name attrs '%' TYPE_P
  				{
  					$$ = makeTypeNameFromNameList(lcons(makeString($2), $3));
  					$$->pct_type = true;
  					$$->setof = TRUE;
! 					$$->location = @2.begins;
  				}
  		;
  
*************** oper_argtypes:
*** 6231,6237 ****
  						   (errcode(ERRCODE_SYNTAX_ERROR),
  							errmsg("missing argument"),
  							errhint("Use NONE to denote the missing argument of a unary operator."),
! 							parser_errposition(@3)));
  				}
  			| '(' Typename ',' Typename ')'
  					{ $$ = list_make2($2, $4); }
--- 6230,6236 ----
  						   (errcode(ERRCODE_SYNTAX_ERROR),
  							errmsg("missing argument"),
  							errhint("Use NONE to denote the missing argument of a unary operator."),
! 							parser_errposition(@3.begins)));
  				}
  			| '(' Typename ',' Typename ')'
  					{ $$ = list_make2($2, $4); }
*************** RenameStmt: ALTER AGGREGATE func_name ag
*** 6662,6668 ****
  					RenameStmt *n = makeNode(RenameStmt);
  					n->renameType = OBJECT_ATTRIBUTE;
  					n->relationType = OBJECT_TYPE;
! 					n->relation = makeRangeVarFromAnyName($3, @3, yyscanner);
  					n->subname = $6;
  					n->newname = $8;
  					n->behavior = $9;
--- 6661,6667 ----
  					RenameStmt *n = makeNode(RenameStmt);
  					n->renameType = OBJECT_ATTRIBUTE;
  					n->relationType = OBJECT_TYPE;
! 					n->relation = makeRangeVarFromAnyName($3, @3.begins, yyscanner);
  					n->subname = $6;
  					n->newname = $8;
  					n->behavior = $9;
*************** opt_transaction:	WORK							{}
*** 7257,7275 ****
  transaction_mode_item:
  			ISOLATION LEVEL iso_level
  					{ $$ = makeDefElem("transaction_isolation",
! 									   makeStringConst($3, @3)); }
  			| READ ONLY
  					{ $$ = makeDefElem("transaction_read_only",
! 									   makeIntConst(TRUE, @1)); }
  			| READ WRITE
  					{ $$ = makeDefElem("transaction_read_only",
! 									   makeIntConst(FALSE, @1)); }
  			| DEFERRABLE
  					{ $$ = makeDefElem("transaction_deferrable",
! 									   makeIntConst(TRUE, @1)); }
  			| NOT DEFERRABLE
  					{ $$ = makeDefElem("transaction_deferrable",
! 									   makeIntConst(FALSE, @1)); }
  		;
  
  /* Syntax with commas is SQL-spec, without commas is Postgres historical */
--- 7256,7274 ----
  transaction_mode_item:
  			ISOLATION LEVEL iso_level
  					{ $$ = makeDefElem("transaction_isolation",
! 									   makeStringConst($3, @3.begins, @3.length)); }
  			| READ ONLY
  					{ $$ = makeDefElem("transaction_read_only",
! 									   makeIntConst(TRUE, @1.begins, @1.length)); }
  			| READ WRITE
  					{ $$ = makeDefElem("transaction_read_only",
! 									   makeIntConst(FALSE, @1.begins, @1.length)); }
  			| DEFERRABLE
  					{ $$ = makeDefElem("transaction_deferrable",
! 									   makeIntConst(TRUE, @1.begins, @1.length)); }
  			| NOT DEFERRABLE
  					{ $$ = makeDefElem("transaction_deferrable",
! 									   makeIntConst(FALSE, @1.begins, @1.length)); }
  		;
  
  /* Syntax with commas is SQL-spec, without commas is Postgres historical */
*************** insert_column_item:
*** 8116,8122 ****
  					$$->name = $1;
  					$$->indirection = check_indirection($2, yyscanner);
  					$$->val = NULL;
! 					$$->location = @1;
  				}
  		;
  
--- 8115,8121 ----
  					$$->name = $1;
  					$$->indirection = check_indirection($2, yyscanner);
  					$$->val = NULL;
! 					$$->location = @1.begins;
  				}
  		;
  
*************** multiple_set_clause:
*** 8246,8252 ****
  						ereport(ERROR,
  								(errcode(ERRCODE_SYNTAX_ERROR),
  								 errmsg("number of columns does not match number of values"),
! 								 parser_errposition(@1)));
  					forboth(col_cell, $2, val_cell, $5)
  					{
  						ResTarget *res_col = (ResTarget *) lfirst(col_cell);
--- 8245,8251 ----
  						ereport(ERROR,
  								(errcode(ERRCODE_SYNTAX_ERROR),
  								 errmsg("number of columns does not match number of values"),
! 								 parser_errposition(@1.begins)));
  					forboth(col_cell, $2, val_cell, $5)
  					{
  						ResTarget *res_col = (ResTarget *) lfirst(col_cell);
*************** set_target:
*** 8266,8272 ****
  					$$->name = $1;
  					$$->indirection = check_indirection($2, yyscanner);
  					$$->val = NULL;	/* upper production sets this */
! 					$$->location = @1;
  				}
  		;
  
--- 8265,8271 ----
  					$$->name = $1;
  					$$->indirection = check_indirection($2, yyscanner);
  					$$->val = NULL;	/* upper production sets this */
! 					$$->location = @1.begins;
  				}
  		;
  
*************** with_clause:
*** 8523,8536 ****
  				$$ = makeNode(WithClause);
  				$$->ctes = $2;
  				$$->recursive = false;
! 				$$->location = @1;
  			}
  		| WITH RECURSIVE cte_list
  			{
  				$$ = makeNode(WithClause);
  				$$->ctes = $3;
  				$$->recursive = true;
! 				$$->location = @1;
  			}
  		;
  
--- 8522,8535 ----
  				$$ = makeNode(WithClause);
  				$$->ctes = $2;
  				$$->recursive = false;
! 				$$->location = @1.begins;
  			}
  		| WITH RECURSIVE cte_list
  			{
  				$$ = makeNode(WithClause);
  				$$->ctes = $3;
  				$$->recursive = true;
! 				$$->location = @1.begins;
  			}
  		;
  
*************** common_table_expr:  name opt_name_list A
*** 8545,8551 ****
  				n->ctename = $1;
  				n->aliascolnames = $2;
  				n->ctequery = $5;
! 				n->location = @1;
  				$$ = (Node *) n;
  			}
  		;
--- 8544,8550 ----
  				n->ctename = $1;
  				n->aliascolnames = $2;
  				n->ctequery = $5;
! 				n->location = @1.begins;
  				$$ = (Node *) n;
  			}
  		;
*************** sortby:		a_expr USING qual_all_Op opt_nu
*** 8662,8668 ****
  					$$->sortby_dir = SORTBY_USING;
  					$$->sortby_nulls = $4;
  					$$->useOp = $3;
! 					$$->location = @3;
  				}
  			| a_expr opt_asc_desc opt_nulls_order
  				{
--- 8661,8667 ----
  					$$->sortby_dir = SORTBY_USING;
  					$$->sortby_nulls = $4;
  					$$->useOp = $3;
! 					$$->location = @3.begins;
  				}
  			| a_expr opt_asc_desc opt_nulls_order
  				{
*************** limit_clause:
*** 8698,8704 ****
  							(errcode(ERRCODE_SYNTAX_ERROR),
  							 errmsg("LIMIT #,# syntax is not supported"),
  							 errhint("Use separate LIMIT and OFFSET clauses."),
! 							 parser_errposition(@1)));
  				}
  			/* SQL:2008 syntax */
  			| FETCH first_or_next opt_select_fetch_first_value row_or_rows ONLY
--- 8697,8703 ----
  							(errcode(ERRCODE_SYNTAX_ERROR),
  							 errmsg("LIMIT #,# syntax is not supported"),
  							 errhint("Use separate LIMIT and OFFSET clauses."),
! 							 parser_errposition(@1.begins)));
  				}
  			/* SQL:2008 syntax */
  			| FETCH first_or_next opt_select_fetch_first_value row_or_rows ONLY
*************** select_limit_value:
*** 8718,8724 ****
  			| ALL
  				{
  					/* LIMIT ALL is represented as a NULL constant */
! 					$$ = makeNullAConst(@1);
  				}
  		;
  
--- 8717,8723 ----
  			| ALL
  				{
  					/* LIMIT ALL is represented as a NULL constant */
! 					$$ = makeNullAConst(@1.begins, @1.length);
  				}
  		;
  
*************** select_offset_value:
*** 8733,8741 ****
   * default to 1.
   */
  opt_select_fetch_first_value:
! 			SignedIconst						{ $$ = makeIntConst($1, @1); }
  			| '(' a_expr ')'					{ $$ = $2; }
! 			| /*EMPTY*/							{ $$ = makeIntConst(1, -1); }
  		;
  
  /*
--- 8732,8740 ----
   * default to 1.
   */
  opt_select_fetch_first_value:
! 			SignedIconst						{ $$ = makeIntConst($1, @1.begins, @1.length); }
  			| '(' a_expr ')'					{ $$ = $2; }
! 			| /*EMPTY*/							{ $$ = makeIntConst(1, -1, -1); }
  		;
  
  /*
*************** table_ref:	relation_expr
*** 8917,8929 ****
  								(errcode(ERRCODE_SYNTAX_ERROR),
  								 errmsg("VALUES in FROM must have an alias"),
  								 errhint("For example, FROM (VALUES ...) [AS] foo."),
! 								 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."),
! 								 parser_errposition(@1)));
  					$$ = NULL;
  				}
  			| select_with_parens alias_clause
--- 8916,8928 ----
  								(errcode(ERRCODE_SYNTAX_ERROR),
  								 errmsg("VALUES in FROM must have an alias"),
  								 errhint("For example, FROM (VALUES ...) [AS] foo."),
! 								 parser_errposition(@1.begins)));
  					else
  						ereport(ERROR,
  								(errcode(ERRCODE_SYNTAX_ERROR),
  								 errmsg("subquery in FROM must have an alias"),
  								 errhint("For example, FROM (SELECT ...) [AS] foo."),
! 								 parser_errposition(@1.begins)));
  					$$ = NULL;
  				}
  			| select_with_parens alias_clause
*************** SimpleTypename:
*** 9283,9294 ****
  							ereport(ERROR,
  									(errcode(ERRCODE_SYNTAX_ERROR),
  									 errmsg("interval precision specified twice"),
! 									 parser_errposition(@1)));
! 						$$->typmods = lappend($5, makeIntConst($3, @3));
  					}
  					else
! 						$$->typmods = list_make2(makeIntConst(INTERVAL_FULL_RANGE, -1),
! 												 makeIntConst($3, @3));
  				}
  		;
  
--- 9282,9293 ----
  							ereport(ERROR,
  									(errcode(ERRCODE_SYNTAX_ERROR),
  									 errmsg("interval precision specified twice"),
! 									 parser_errposition(@1.begins)));
! 						$$->typmods = lappend($5, makeIntConst($3, @3.begins, @3.length));
  					}
  					else
! 						$$->typmods = list_make2(makeIntConst(INTERVAL_FULL_RANGE, -1, -1),
! 												 makeIntConst($3, @3.begins, @3.length));
  				}
  		;
  
*************** GenericType:
*** 9322,9334 ****
  				{
  					$$ = makeTypeName($1);
  					$$->typmods = $2;
! 					$$->location = @1;
  				}
  			| type_function_name attrs opt_type_modifiers
  				{
  					$$ = makeTypeNameFromNameList(lcons(makeString($1), $2));
  					$$->typmods = $3;
! 					$$->location = @1;
  				}
  		;
  
--- 9321,9333 ----
  				{
  					$$ = makeTypeName($1);
  					$$->typmods = $2;
! 					$$->location = @1.begins;
  				}
  			| type_function_name attrs opt_type_modifiers
  				{
  					$$ = makeTypeNameFromNameList(lcons(makeString($1), $2));
  					$$->typmods = $3;
! 					$$->location = @1.begins;
  				}
  		;
  
*************** opt_type_modifiers: '(' expr_list ')'
*** 9342,9401 ****
  Numeric:	INT_P
  				{
  					$$ = SystemTypeName("int4");
! 					$$->location = @1;
  				}
  			| INTEGER
  				{
  					$$ = SystemTypeName("int4");
! 					$$->location = @1;
  				}
  			| SMALLINT
  				{
  					$$ = SystemTypeName("int2");
! 					$$->location = @1;
  				}
  			| BIGINT
  				{
  					$$ = SystemTypeName("int8");
! 					$$->location = @1;
  				}
  			| REAL
  				{
  					$$ = SystemTypeName("float4");
! 					$$->location = @1;
  				}
  			| FLOAT_P opt_float
  				{
  					$$ = $2;
! 					$$->location = @1;
  				}
  			| DOUBLE_P PRECISION
  				{
  					$$ = SystemTypeName("float8");
! 					$$->location = @1;
  				}
  			| DECIMAL_P opt_type_modifiers
  				{
  					$$ = SystemTypeName("numeric");
  					$$->typmods = $2;
! 					$$->location = @1;
  				}
  			| DEC opt_type_modifiers
  				{
  					$$ = SystemTypeName("numeric");
  					$$->typmods = $2;
! 					$$->location = @1;
  				}
  			| NUMERIC opt_type_modifiers
  				{
  					$$ = SystemTypeName("numeric");
  					$$->typmods = $2;
! 					$$->location = @1;
  				}
  			| BOOLEAN_P
  				{
  					$$ = SystemTypeName("bool");
! 					$$->location = @1;
  				}
  		;
  
--- 9341,9400 ----
  Numeric:	INT_P
  				{
  					$$ = SystemTypeName("int4");
! 					$$->location = @1.begins;
  				}
  			| INTEGER
  				{
  					$$ = SystemTypeName("int4");
! 					$$->location = @1.begins;
  				}
  			| SMALLINT
  				{
  					$$ = SystemTypeName("int2");
! 					$$->location = @1.begins;
  				}
  			| BIGINT
  				{
  					$$ = SystemTypeName("int8");
! 					$$->location = @1.begins;
  				}
  			| REAL
  				{
  					$$ = SystemTypeName("float4");
! 					$$->location = @1.begins;
  				}
  			| FLOAT_P opt_float
  				{
  					$$ = $2;
! 					$$->location = @1.begins;
  				}
  			| DOUBLE_P PRECISION
  				{
  					$$ = SystemTypeName("float8");
! 					$$->location = @1.begins;
  				}
  			| DECIMAL_P opt_type_modifiers
  				{
  					$$ = SystemTypeName("numeric");
  					$$->typmods = $2;
! 					$$->location = @1.begins;
  				}
  			| DEC opt_type_modifiers
  				{
  					$$ = SystemTypeName("numeric");
  					$$->typmods = $2;
! 					$$->location = @1.begins;
  				}
  			| NUMERIC opt_type_modifiers
  				{
  					$$ = SystemTypeName("numeric");
  					$$->typmods = $2;
! 					$$->location = @1.begins;
  				}
  			| BOOLEAN_P
  				{
  					$$ = SystemTypeName("bool");
! 					$$->location = @1.begins;
  				}
  		;
  
*************** opt_float:	'(' Iconst ')'
*** 9409,9415 ****
  						ereport(ERROR,
  								(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
  								 errmsg("precision for type float must be at least 1 bit"),
! 								 parser_errposition(@2)));
  					else if ($2 <= 24)
  						$$ = SystemTypeName("float4");
  					else if ($2 <= 53)
--- 9408,9414 ----
  						ereport(ERROR,
  								(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
  								 errmsg("precision for type float must be at least 1 bit"),
! 								 parser_errposition(@2.begins)));
  					else if ($2 <= 24)
  						$$ = SystemTypeName("float4");
  					else if ($2 <= 53)
*************** opt_float:	'(' Iconst ')'
*** 9418,9424 ****
  						ereport(ERROR,
  								(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
  								 errmsg("precision for type float must be less than 54 bits"),
! 								 parser_errposition(@2)));
  				}
  			| /*EMPTY*/
  				{
--- 9417,9423 ----
  						ereport(ERROR,
  								(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
  								 errmsg("precision for type float must be less than 54 bits"),
! 								 parser_errposition(@2.begins)));
  				}
  			| /*EMPTY*/
  				{
*************** BitWithLength:
*** 9461,9467 ****
  					typname = $2 ? "varbit" : "bit";
  					$$ = SystemTypeName(typname);
  					$$->typmods = $4;
! 					$$->location = @1;
  				}
  		;
  
--- 9460,9466 ----
  					typname = $2 ? "varbit" : "bit";
  					$$ = SystemTypeName(typname);
  					$$->typmods = $4;
! 					$$->location = @1.begins;
  				}
  		;
  
*************** BitWithoutLength:
*** 9476,9484 ****
  					else
  					{
  						$$ = SystemTypeName("bit");
! 						$$->typmods = list_make1(makeIntConst(1, -1));
  					}
! 					$$->location = @1;
  				}
  		;
  
--- 9475,9483 ----
  					else
  					{
  						$$ = SystemTypeName("bit");
! 						$$->typmods = list_make1(makeIntConst(1, -1, -1));
  					}
! 					$$->location = @1.begins;
  				}
  		;
  
*************** CharacterWithLength:  character '(' Icon
*** 9528,9535 ****
  					}
  
  					$$ = SystemTypeName($1);
! 					$$->typmods = list_make1(makeIntConst($3, @3));
! 					$$->location = @1;
  				}
  		;
  
--- 9527,9534 ----
  					}
  
  					$$ = SystemTypeName($1);
! 					$$->typmods = list_make1(makeIntConst($3, @3.begins, @3.length));
! 					$$->location = @1.begins;
  				}
  		;
  
*************** CharacterWithoutLength:	 character opt_c
*** 9550,9558 ****
  
  					/* char defaults to char(1), varchar to no limit */
  					if (strcmp($1, "bpchar") == 0)
! 						$$->typmods = list_make1(makeIntConst(1, -1));
  
! 					$$->location = @1;
  				}
  		;
  
--- 9549,9557 ----
  
  					/* char defaults to char(1), varchar to no limit */
  					if (strcmp($1, "bpchar") == 0)
! 						$$->typmods = list_make1(makeIntConst(1, -1, -1));
  
! 					$$->location = @1.begins;
  				}
  		;
  
*************** ConstDatetime:
*** 9590,9597 ****
  						$$ = SystemTypeName("timestamptz");
  					else
  						$$ = SystemTypeName("timestamp");
! 					$$->typmods = list_make1(makeIntConst($3, @3));
! 					$$->location = @1;
  				}
  			| TIMESTAMP opt_timezone
  				{
--- 9589,9596 ----
  						$$ = SystemTypeName("timestamptz");
  					else
  						$$ = SystemTypeName("timestamp");
! 					$$->typmods = list_make1(makeIntConst($3, @3.begins, @3.length));
! 					$$->location = @1.begins;
  				}
  			| TIMESTAMP opt_timezone
  				{
*************** ConstDatetime:
*** 9599,9605 ****
  						$$ = SystemTypeName("timestamptz");
  					else
  						$$ = SystemTypeName("timestamp");
! 					$$->location = @1;
  				}
  			| TIME '(' Iconst ')' opt_timezone
  				{
--- 9598,9604 ----
  						$$ = SystemTypeName("timestamptz");
  					else
  						$$ = SystemTypeName("timestamp");
! 					$$->location = @1.begins;
  				}
  			| TIME '(' Iconst ')' opt_timezone
  				{
*************** ConstDatetime:
*** 9607,9614 ****
  						$$ = SystemTypeName("timetz");
  					else
  						$$ = SystemTypeName("time");
! 					$$->typmods = list_make1(makeIntConst($3, @3));
! 					$$->location = @1;
  				}
  			| TIME opt_timezone
  				{
--- 9606,9613 ----
  						$$ = SystemTypeName("timetz");
  					else
  						$$ = SystemTypeName("time");
! 					$$->typmods = list_make1(makeIntConst($3, @3.begins, @3.length));
! 					$$->location = @1.begins;
  				}
  			| TIME opt_timezone
  				{
*************** ConstDatetime:
*** 9616,9622 ****
  						$$ = SystemTypeName("timetz");
  					else
  						$$ = SystemTypeName("time");
! 					$$->location = @1;
  				}
  		;
  
--- 9615,9621 ----
  						$$ = SystemTypeName("timetz");
  					else
  						$$ = SystemTypeName("time");
! 					$$->location = @1.begins;
  				}
  		;
  
*************** ConstInterval:
*** 9624,9630 ****
  			INTERVAL
  				{
  					$$ = SystemTypeName("interval");
! 					$$->location = @1;
  				}
  		;
  
--- 9623,9629 ----
  			INTERVAL
  				{
  					$$ = SystemTypeName("interval");
! 					$$->location = @1.begins;
  				}
  		;
  
*************** opt_timezone:
*** 9636,9667 ****
  
  opt_interval:
  			YEAR_P
! 				{ $$ = list_make1(makeIntConst(INTERVAL_MASK(YEAR), @1)); }
  			| MONTH_P
! 				{ $$ = list_make1(makeIntConst(INTERVAL_MASK(MONTH), @1)); }
  			| DAY_P
! 				{ $$ = list_make1(makeIntConst(INTERVAL_MASK(DAY), @1)); }
  			| HOUR_P
! 				{ $$ = list_make1(makeIntConst(INTERVAL_MASK(HOUR), @1)); }
  			| MINUTE_P
! 				{ $$ = list_make1(makeIntConst(INTERVAL_MASK(MINUTE), @1)); }
  			| interval_second
  				{ $$ = $1; }
  			| YEAR_P TO MONTH_P
  				{
  					$$ = list_make1(makeIntConst(INTERVAL_MASK(YEAR) |
! 												 INTERVAL_MASK(MONTH), @1));
  				}
  			| DAY_P TO HOUR_P
  				{
  					$$ = list_make1(makeIntConst(INTERVAL_MASK(DAY) |
! 												 INTERVAL_MASK(HOUR), @1));
  				}
  			| DAY_P TO MINUTE_P
  				{
  					$$ = list_make1(makeIntConst(INTERVAL_MASK(DAY) |
  												 INTERVAL_MASK(HOUR) |
! 												 INTERVAL_MASK(MINUTE), @1));
  				}
  			| DAY_P TO interval_second
  				{
--- 9635,9666 ----
  
  opt_interval:
  			YEAR_P
! 				{ $$ = list_make1(makeIntConst(INTERVAL_MASK(YEAR), @1.begins, @1.length)); }
  			| MONTH_P
! 				{ $$ = list_make1(makeIntConst(INTERVAL_MASK(MONTH), @1.begins, @1.length)); }
  			| DAY_P
! 				{ $$ = list_make1(makeIntConst(INTERVAL_MASK(DAY), @1.begins, @1.length)); }
  			| HOUR_P
! 				{ $$ = list_make1(makeIntConst(INTERVAL_MASK(HOUR), @1.begins, @1.length)); }
  			| MINUTE_P
! 				{ $$ = list_make1(makeIntConst(INTERVAL_MASK(MINUTE), @1.begins, @1.length)); }
  			| interval_second
  				{ $$ = $1; }
  			| YEAR_P TO MONTH_P
  				{
  					$$ = list_make1(makeIntConst(INTERVAL_MASK(YEAR) |
! 												 INTERVAL_MASK(MONTH), @1.begins, @1.length));
  				}
  			| DAY_P TO HOUR_P
  				{
  					$$ = list_make1(makeIntConst(INTERVAL_MASK(DAY) |
! 												 INTERVAL_MASK(HOUR), @1.begins, @1.length));
  				}
  			| DAY_P TO MINUTE_P
  				{
  					$$ = list_make1(makeIntConst(INTERVAL_MASK(DAY) |
  												 INTERVAL_MASK(HOUR) |
! 												 INTERVAL_MASK(MINUTE), @1.begins, @1.length));
  				}
  			| DAY_P TO interval_second
  				{
*************** opt_interval:
*** 9669,9693 ****
  					linitial($$) = makeIntConst(INTERVAL_MASK(DAY) |
  												INTERVAL_MASK(HOUR) |
  												INTERVAL_MASK(MINUTE) |
! 												INTERVAL_MASK(SECOND), @1);
  				}
  			| HOUR_P TO MINUTE_P
  				{
  					$$ = list_make1(makeIntConst(INTERVAL_MASK(HOUR) |
! 												 INTERVAL_MASK(MINUTE), @1));
  				}
  			| HOUR_P TO interval_second
  				{
  					$$ = $3;
  					linitial($$) = makeIntConst(INTERVAL_MASK(HOUR) |
  												INTERVAL_MASK(MINUTE) |
! 												INTERVAL_MASK(SECOND), @1);
  				}
  			| MINUTE_P TO interval_second
  				{
  					$$ = $3;
  					linitial($$) = makeIntConst(INTERVAL_MASK(MINUTE) |
! 												INTERVAL_MASK(SECOND), @1);
  				}
  			| /*EMPTY*/
  				{ $$ = NIL; }
--- 9668,9692 ----
  					linitial($$) = makeIntConst(INTERVAL_MASK(DAY) |
  												INTERVAL_MASK(HOUR) |
  												INTERVAL_MASK(MINUTE) |
! 												INTERVAL_MASK(SECOND), @1.begins, @1.length);
  				}
  			| HOUR_P TO MINUTE_P
  				{
  					$$ = list_make1(makeIntConst(INTERVAL_MASK(HOUR) |
! 												 INTERVAL_MASK(MINUTE), @1.begins, @1.length));
  				}
  			| HOUR_P TO interval_second
  				{
  					$$ = $3;
  					linitial($$) = makeIntConst(INTERVAL_MASK(HOUR) |
  												INTERVAL_MASK(MINUTE) |
! 												INTERVAL_MASK(SECOND), @1.begins, @1.length);
  				}
  			| MINUTE_P TO interval_second
  				{
  					$$ = $3;
  					linitial($$) = makeIntConst(INTERVAL_MASK(MINUTE) |
! 												INTERVAL_MASK(SECOND), @1.begins, @1.length);
  				}
  			| /*EMPTY*/
  				{ $$ = NIL; }
*************** opt_interval:
*** 9696,9707 ****
  interval_second:
  			SECOND_P
  				{
! 					$$ = list_make1(makeIntConst(INTERVAL_MASK(SECOND), @1));
  				}
  			| SECOND_P '(' Iconst ')'
  				{
! 					$$ = list_make2(makeIntConst(INTERVAL_MASK(SECOND), @1),
! 									makeIntConst($3, @3));
  				}
  		;
  
--- 9695,9706 ----
  interval_second:
  			SECOND_P
  				{
! 					$$ = list_make1(makeIntConst(INTERVAL_MASK(SECOND), @1.begins, @1.length));
  				}
  			| SECOND_P '(' Iconst ')'
  				{
! 					$$ = list_make2(makeIntConst(INTERVAL_MASK(SECOND), @1.begins, @1.length),
! 									makeIntConst($3, @3.begins, @3.length));
  				}
  		;
  
*************** interval_second:
*** 9730,9742 ****
   */
  a_expr:		c_expr									{ $$ = $1; }
  			| a_expr TYPECAST Typename
! 					{ $$ = makeTypeCast($1, $3, @2); }
  			| a_expr COLLATE any_name
  				{
  					CollateClause *n = makeNode(CollateClause);
  					n->arg = $1;
  					n->collname = $3;
! 					n->location = @2;
  					$$ = (Node *) n;
  				}
  			| a_expr AT TIME ZONE a_expr			%prec AT
--- 9729,9741 ----
   */
  a_expr:		c_expr									{ $$ = $1; }
  			| a_expr TYPECAST Typename
! 					{ $$ = makeTypeCast($1, $3, @2.begins, @2.length); }
  			| a_expr COLLATE any_name
  				{
  					CollateClause *n = makeNode(CollateClause);
  					n->arg = $1;
  					n->collname = $3;
! 					n->location = @2.begins;
  					$$ = (Node *) n;
  				}
  			| a_expr AT TIME ZONE a_expr			%prec AT
*************** a_expr:		c_expr									{ $$ = $1; }
*** 9749,9755 ****
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @2;
  					$$ = (Node *) n;
  				}
  		/*
--- 9748,9754 ----
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @2.begins;
  					$$ = (Node *) n;
  				}
  		/*
*************** a_expr:		c_expr									{ $$ = $1; }
*** 9762,9805 ****
  		 * also to b_expr and to the MathOp list above.
  		 */
  			| '+' a_expr					%prec UMINUS
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", NULL, $2, @1); }
  			| '-' a_expr					%prec UMINUS
! 				{ $$ = doNegate($2, @1); }
  			| a_expr '+' a_expr
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", $1, $3, @2); }
  			| a_expr '-' a_expr
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "-", $1, $3, @2); }
  			| a_expr '*' a_expr
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "*", $1, $3, @2); }
  			| a_expr '/' a_expr
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "/", $1, $3, @2); }
  			| a_expr '%' a_expr
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "%", $1, $3, @2); }
  			| a_expr '^' a_expr
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "^", $1, $3, @2); }
  			| a_expr '<' a_expr
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $3, @2); }
  			| a_expr '>' a_expr
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $3, @2); }
  			| a_expr '=' a_expr
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "=", $1, $3, @2); }
  
  			| a_expr qual_Op a_expr				%prec Op
! 				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, $3, @2); }
  			| qual_Op a_expr					%prec Op
! 				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $1, NULL, $2, @1); }
  			| a_expr qual_Op					%prec POSTFIXOP
! 				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, NULL, @2); }
  
  			| a_expr AND a_expr
! 				{ $$ = (Node *) makeA_Expr(AEXPR_AND, NIL, $1, $3, @2); }
  			| a_expr OR a_expr
! 				{ $$ = (Node *) makeA_Expr(AEXPR_OR, NIL, $1, $3, @2); }
  			| NOT a_expr
! 				{ $$ = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL, $2, @1); }
  
  			| a_expr LIKE a_expr
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~~", $1, $3, @2); }
  			| a_expr LIKE a_expr ESCAPE a_expr
  				{
  					FuncCall *n = makeNode(FuncCall);
--- 9761,9804 ----
  		 * also to b_expr and to the MathOp list above.
  		 */
  			| '+' a_expr					%prec UMINUS
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", NULL, $2, @1.begins); }
  			| '-' a_expr					%prec UMINUS
! 				{ $$ = doNegate($2, @1.begins, @1.length); }
  			| a_expr '+' a_expr
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", $1, $3, @2.begins); }
  			| a_expr '-' a_expr
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "-", $1, $3, @2.begins); }
  			| a_expr '*' a_expr
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "*", $1, $3, @2.begins); }
  			| a_expr '/' a_expr
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "/", $1, $3, @2.begins); }
  			| a_expr '%' a_expr
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "%", $1, $3, @2.begins); }
  			| a_expr '^' a_expr
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "^", $1, $3, @2.begins); }
  			| a_expr '<' a_expr
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $3, @2.begins); }
  			| a_expr '>' a_expr
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $3, @2.begins); }
  			| a_expr '=' a_expr
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "=", $1, $3, @2.begins); }
  
  			| a_expr qual_Op a_expr				%prec Op
! 				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, $3, @2.begins); }
  			| qual_Op a_expr					%prec Op
! 				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $1, NULL, $2, @1.begins); }
  			| a_expr qual_Op					%prec POSTFIXOP
! 				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, NULL, @2.begins); }
  
  			| a_expr AND a_expr
! 				{ $$ = (Node *) makeA_Expr(AEXPR_AND, NIL, $1, $3, @2.begins); }
  			| a_expr OR a_expr
! 				{ $$ = (Node *) makeA_Expr(AEXPR_OR, NIL, $1, $3, @2.begins); }
  			| NOT a_expr
! 				{ $$ = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL, $2, @1.begins); }
  
  			| a_expr LIKE a_expr
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~~", $1, $3, @2.begins); }
  			| a_expr LIKE a_expr ESCAPE a_expr
  				{
  					FuncCall *n = makeNode(FuncCall);
*************** a_expr:		c_expr									{ $$ = $1; }
*** 9810,9820 ****
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @2;
! 					$$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~~", $1, (Node *) n, @2);
  				}
  			| a_expr NOT LIKE a_expr
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~", $1, $4, @2); }
  			| a_expr NOT LIKE a_expr ESCAPE a_expr
  				{
  					FuncCall *n = makeNode(FuncCall);
--- 9809,9819 ----
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @2.begins;
! 					$$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~~", $1, (Node *) n, @2.begins);
  				}
  			| a_expr NOT LIKE a_expr
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~", $1, $4, @2.begins); }
  			| a_expr NOT LIKE a_expr ESCAPE a_expr
  				{
  					FuncCall *n = makeNode(FuncCall);
*************** a_expr:		c_expr									{ $$ = $1; }
*** 9825,9835 ****
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @2;
! 					$$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~", $1, (Node *) n, @2);
  				}
  			| a_expr ILIKE a_expr
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~~*", $1, $3, @2); }
  			| a_expr ILIKE a_expr ESCAPE a_expr
  				{
  					FuncCall *n = makeNode(FuncCall);
--- 9824,9834 ----
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @2.begins;
! 					$$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~", $1, (Node *) n, @2.begins);
  				}
  			| a_expr ILIKE a_expr
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~~*", $1, $3, @2.begins); }
  			| a_expr ILIKE a_expr ESCAPE a_expr
  				{
  					FuncCall *n = makeNode(FuncCall);
*************** a_expr:		c_expr									{ $$ = $1; }
*** 9840,9850 ****
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @2;
! 					$$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~~*", $1, (Node *) n, @2);
  				}
  			| a_expr NOT ILIKE a_expr
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~*", $1, $4, @2); }
  			| a_expr NOT ILIKE a_expr ESCAPE a_expr
  				{
  					FuncCall *n = makeNode(FuncCall);
--- 9839,9849 ----
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @2.begins;
! 					$$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~~*", $1, (Node *) n, @2.begins);
  				}
  			| a_expr NOT ILIKE a_expr
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~*", $1, $4, @2.begins); }
  			| a_expr NOT ILIKE a_expr ESCAPE a_expr
  				{
  					FuncCall *n = makeNode(FuncCall);
*************** a_expr:		c_expr									{ $$ = $1; }
*** 9855,9876 ****
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @2;
! 					$$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~*", $1, (Node *) n, @2);
  				}
  
  			| a_expr SIMILAR TO a_expr				%prec SIMILAR
  				{
  					FuncCall *n = makeNode(FuncCall);
  					n->funcname = SystemFuncName("similar_escape");
! 					n->args = list_make2($4, makeNullAConst(-1));
  					n->agg_order = NIL;
  					n->agg_star = FALSE;
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @2;
! 					$$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~", $1, (Node *) n, @2);
  				}
  			| a_expr SIMILAR TO a_expr ESCAPE a_expr
  				{
--- 9854,9875 ----
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @2.begins;
! 					$$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~*", $1, (Node *) n, @2.begins);
  				}
  
  			| a_expr SIMILAR TO a_expr				%prec SIMILAR
  				{
  					FuncCall *n = makeNode(FuncCall);
  					n->funcname = SystemFuncName("similar_escape");
! 					n->args = list_make2($4, makeNullAConst(-1, -1));
  					n->agg_order = NIL;
  					n->agg_star = FALSE;
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @2.begins;
! 					$$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~", $1, (Node *) n, @2.begins);
  				}
  			| a_expr SIMILAR TO a_expr ESCAPE a_expr
  				{
*************** a_expr:		c_expr									{ $$ = $1; }
*** 9882,9902 ****
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @2;
! 					$$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~", $1, (Node *) n, @2);
  				}
  			| a_expr NOT SIMILAR TO a_expr			%prec SIMILAR
  				{
  					FuncCall *n = makeNode(FuncCall);
  					n->funcname = SystemFuncName("similar_escape");
! 					n->args = list_make2($5, makeNullAConst(-1));
  					n->agg_order = NIL;
  					n->agg_star = FALSE;
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @2;
! 					$$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~", $1, (Node *) n, @2);
  				}
  			| a_expr NOT SIMILAR TO a_expr ESCAPE a_expr
  				{
--- 9881,9901 ----
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @2.begins;
! 					$$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~", $1, (Node *) n, @2.begins);
  				}
  			| a_expr NOT SIMILAR TO a_expr			%prec SIMILAR
  				{
  					FuncCall *n = makeNode(FuncCall);
  					n->funcname = SystemFuncName("similar_escape");
! 					n->args = list_make2($5, makeNullAConst(-1, -1));
  					n->agg_order = NIL;
  					n->agg_star = FALSE;
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @2.begins;
! 					$$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~", $1, (Node *) n, @2.begins);
  				}
  			| a_expr NOT SIMILAR TO a_expr ESCAPE a_expr
  				{
*************** a_expr:		c_expr									{ $$ = $1; }
*** 9908,9915 ****
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @2;
! 					$$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~", $1, (Node *) n, @2);
  				}
  
  			/* NullTest clause
--- 9907,9914 ----
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @2.begins;
! 					$$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~", $1, (Node *) n, @2.begins);
  				}
  
  			/* NullTest clause
*************** a_expr:		c_expr									{ $$ = $1; }
*** 9951,9957 ****
  				}
  			| row OVERLAPS row
  				{
! 					$$ = (Node *)makeOverlaps($1, $3, @2, yyscanner);
  				}
  			| a_expr IS TRUE_P							%prec IS
  				{
--- 9950,9956 ----
  				}
  			| row OVERLAPS row
  				{
! 					$$ = (Node *)makeOverlaps($1, $3, @2.begins, yyscanner);
  				}
  			| a_expr IS TRUE_P							%prec IS
  				{
*************** a_expr:		c_expr									{ $$ = $1; }
*** 9997,10019 ****
  				}
  			| a_expr IS DISTINCT FROM a_expr			%prec IS
  				{
! 					$$ = (Node *) makeSimpleA_Expr(AEXPR_DISTINCT, "=", $1, $5, @2);
  				}
  			| a_expr IS NOT DISTINCT FROM a_expr		%prec IS
  				{
  					$$ = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL,
  									(Node *) makeSimpleA_Expr(AEXPR_DISTINCT,
! 															  "=", $1, $6, @2),
! 											 @2);
  
  				}
  			| a_expr IS OF '(' type_list ')'			%prec IS
  				{
! 					$$ = (Node *) makeSimpleA_Expr(AEXPR_OF, "=", $1, (Node *) $5, @2);
  				}
  			| a_expr IS NOT OF '(' type_list ')'		%prec IS
  				{
! 					$$ = (Node *) makeSimpleA_Expr(AEXPR_OF, "<>", $1, (Node *) $6, @2);
  				}
  			/*
  			 *	Ideally we would not use hard-wired operators below but
--- 9996,10018 ----
  				}
  			| a_expr IS DISTINCT FROM a_expr			%prec IS
  				{
! 					$$ = (Node *) makeSimpleA_Expr(AEXPR_DISTINCT, "=", $1, $5, @2.begins);
  				}
  			| a_expr IS NOT DISTINCT FROM a_expr		%prec IS
  				{
  					$$ = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL,
  									(Node *) makeSimpleA_Expr(AEXPR_DISTINCT,
! 															  "=", $1, $6, @2.begins),
! 											 @2.begins);
  
  				}
  			| a_expr IS OF '(' type_list ')'			%prec IS
  				{
! 					$$ = (Node *) makeSimpleA_Expr(AEXPR_OF, "=", $1, (Node *) $5, @2.begins);
  				}
  			| a_expr IS NOT OF '(' type_list ')'		%prec IS
  				{
! 					$$ = (Node *) makeSimpleA_Expr(AEXPR_OF, "<>", $1, (Node *) $6, @2.begins);
  				}
  			/*
  			 *	Ideally we would not use hard-wired operators below but
*************** a_expr:		c_expr									{ $$ = $1; }
*** 10024,10065 ****
  			| a_expr BETWEEN opt_asymmetric b_expr AND b_expr		%prec BETWEEN
  				{
  					$$ = (Node *) makeA_Expr(AEXPR_AND, NIL,
! 						(Node *) makeSimpleA_Expr(AEXPR_OP, ">=", $1, $4, @2),
! 						(Node *) makeSimpleA_Expr(AEXPR_OP, "<=", $1, $6, @2),
! 											 @2);
  				}
  			| a_expr NOT BETWEEN opt_asymmetric b_expr AND b_expr	%prec BETWEEN
  				{
  					$$ = (Node *) makeA_Expr(AEXPR_OR, NIL,
! 						(Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $5, @2),
! 						(Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $7, @2),
! 											 @2);
  				}
  			| a_expr BETWEEN SYMMETRIC b_expr AND b_expr			%prec BETWEEN
  				{
  					$$ = (Node *) makeA_Expr(AEXPR_OR, NIL,
  						(Node *) makeA_Expr(AEXPR_AND, NIL,
! 							(Node *) makeSimpleA_Expr(AEXPR_OP, ">=", $1, $4, @2),
! 							(Node *) makeSimpleA_Expr(AEXPR_OP, "<=", $1, $6, @2),
! 											@2),
  						(Node *) makeA_Expr(AEXPR_AND, NIL,
! 							(Node *) makeSimpleA_Expr(AEXPR_OP, ">=", $1, $6, @2),
! 							(Node *) makeSimpleA_Expr(AEXPR_OP, "<=", $1, $4, @2),
! 											@2),
! 											 @2);
  				}
  			| a_expr NOT BETWEEN SYMMETRIC b_expr AND b_expr		%prec BETWEEN
  				{
  					$$ = (Node *) makeA_Expr(AEXPR_AND, NIL,
  						(Node *) makeA_Expr(AEXPR_OR, NIL,
! 							(Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $5, @2),
! 							(Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $7, @2),
! 											@2),
  						(Node *) makeA_Expr(AEXPR_OR, NIL,
! 							(Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $7, @2),
! 							(Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $5, @2),
! 											@2),
! 											 @2);
  				}
  			| a_expr IN_P in_expr
  				{
--- 10023,10065 ----
  			| a_expr BETWEEN opt_asymmetric b_expr AND b_expr		%prec BETWEEN
  				{
  					$$ = (Node *) makeA_Expr(AEXPR_AND, NIL,
! 						(Node *) makeSimpleA_Expr(AEXPR_OP, ">=", $1, $4, @2.begins),
! 						(Node *) makeSimpleA_Expr(AEXPR_OP, "<=", $1, $6, @2.begins),
! 											 @2.begins);
  				}
  			| a_expr NOT BETWEEN opt_asymmetric b_expr AND b_expr	%prec BETWEEN
  				{
  					$$ = (Node *) makeA_Expr(AEXPR_OR, NIL,
! 						(Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $5, @2.begins),
! 						(Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $7, @2.begins),
! 											 @2.begins);
  				}
  			| a_expr BETWEEN SYMMETRIC b_expr AND b_expr			%prec BETWEEN
  				{
  					$$ = (Node *) makeA_Expr(AEXPR_OR, NIL,
  						(Node *) makeA_Expr(AEXPR_AND, NIL,
! 
! 						    (Node *) makeSimpleA_Expr(AEXPR_OP, ">=", $1, $4, @2.begins),
! 						    (Node *) makeSimpleA_Expr(AEXPR_OP, "<=", $1, $6, @2.begins),
! 											@2.begins),
  						(Node *) makeA_Expr(AEXPR_AND, NIL,
! 						    (Node *) makeSimpleA_Expr(AEXPR_OP, ">=", $1, $6, @2.begins),
! 						    (Node *) makeSimpleA_Expr(AEXPR_OP, "<=", $1, $4, @2.begins),
! 											@2.begins),
! 											 @2.begins);
  				}
  			| a_expr NOT BETWEEN SYMMETRIC b_expr AND b_expr		%prec BETWEEN
  				{
  					$$ = (Node *) makeA_Expr(AEXPR_AND, NIL,
  						(Node *) makeA_Expr(AEXPR_OR, NIL,
! 						    (Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $5, @2.begins),
! 						    (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $7, @2.begins),
! 											@2.begins),
  						(Node *) makeA_Expr(AEXPR_OR, NIL,
! 						    (Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $7, @2.begins),
! 						    (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $5, @2.begins),
! 											@2.begins),
! 											 @2.begins);
  				}
  			| a_expr IN_P in_expr
  				{
*************** a_expr:		c_expr									{ $$ = $1; }
*** 10071,10083 ****
  						n->subLinkType = ANY_SUBLINK;
  						n->testexpr = $1;
  						n->operName = list_make1(makeString("="));
! 						n->location = @2;
  						$$ = (Node *)n;
  					}
  					else
  					{
  						/* generate scalar IN expression */
! 						$$ = (Node *) makeSimpleA_Expr(AEXPR_IN, "=", $1, $3, @2);
  					}
  				}
  			| a_expr NOT IN_P in_expr
--- 10071,10083 ----
  						n->subLinkType = ANY_SUBLINK;
  						n->testexpr = $1;
  						n->operName = list_make1(makeString("="));
! 						n->location = @2.begins;
  						$$ = (Node *)n;
  					}
  					else
  					{
  						/* generate scalar IN expression */
! 						$$ = (Node *) makeSimpleA_Expr(AEXPR_IN, "=", $1, $3, @2.begins);
  					}
  				}
  			| a_expr NOT IN_P in_expr
*************** a_expr:		c_expr									{ $$ = $1; }
*** 10091,10104 ****
  						n->subLinkType = ANY_SUBLINK;
  						n->testexpr = $1;
  						n->operName = list_make1(makeString("="));
! 						n->location = @3;
  						/* Stick a NOT on top */
! 						$$ = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL, (Node *) n, @2);
  					}
  					else
  					{
  						/* generate scalar NOT IN expression */
! 						$$ = (Node *) makeSimpleA_Expr(AEXPR_IN, "<>", $1, $4, @2);
  					}
  				}
  			| a_expr subquery_Op sub_type select_with_parens	%prec Op
--- 10091,10104 ----
  						n->subLinkType = ANY_SUBLINK;
  						n->testexpr = $1;
  						n->operName = list_make1(makeString("="));
! 						n->location = @3.begins;
  						/* Stick a NOT on top */
! 						$$ = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL, (Node *) n, @2.begins);
  					}
  					else
  					{
  						/* generate scalar NOT IN expression */
! 						$$ = (Node *) makeSimpleA_Expr(AEXPR_IN, "<>", $1, $4, @2.begins);
  					}
  				}
  			| a_expr subquery_Op sub_type select_with_parens	%prec Op
*************** a_expr:		c_expr									{ $$ = $1; }
*** 10108,10122 ****
  					n->testexpr = $1;
  					n->operName = $2;
  					n->subselect = $4;
! 					n->location = @2;
  					$$ = (Node *)n;
  				}
  			| a_expr subquery_Op sub_type '(' a_expr ')'		%prec Op
  				{
  					if ($3 == ANY_SUBLINK)
! 						$$ = (Node *) makeA_Expr(AEXPR_OP_ANY, $2, $1, $5, @2);
  					else
! 						$$ = (Node *) makeA_Expr(AEXPR_OP_ALL, $2, $1, $5, @2);
  				}
  			| UNIQUE select_with_parens
  				{
--- 10108,10122 ----
  					n->testexpr = $1;
  					n->operName = $2;
  					n->subselect = $4;
! 					n->location = @2.begins;
  					$$ = (Node *)n;
  				}
  			| a_expr subquery_Op sub_type '(' a_expr ')'		%prec Op
  				{
  					if ($3 == ANY_SUBLINK)
! 						$$ = (Node *) makeA_Expr(AEXPR_OP_ANY, $2, $1, $5, @2.begins);
  					else
! 						$$ = (Node *) makeA_Expr(AEXPR_OP_ALL, $2, $1, $5, @2.begins);
  				}
  			| UNIQUE select_with_parens
  				{
*************** a_expr:		c_expr									{ $$ = $1; }
*** 10132,10150 ****
  					ereport(ERROR,
  							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
  							 errmsg("UNIQUE predicate is not yet implemented"),
! 							 parser_errposition(@1)));
  				}
  			| a_expr IS DOCUMENT_P					%prec IS
  				{
  					$$ = makeXmlExpr(IS_DOCUMENT, NULL, NIL,
! 									 list_make1($1), @2);
  				}
  			| a_expr IS NOT DOCUMENT_P				%prec IS
  				{
  					$$ = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL,
  											 makeXmlExpr(IS_DOCUMENT, NULL, NIL,
! 														 list_make1($1), @2),
! 											 @2);
  				}
  		;
  
--- 10132,10150 ----
  					ereport(ERROR,
  							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
  							 errmsg("UNIQUE predicate is not yet implemented"),
! 							 parser_errposition(@1.begins)));
  				}
  			| a_expr IS DOCUMENT_P					%prec IS
  				{
  					$$ = makeXmlExpr(IS_DOCUMENT, NULL, NIL,
! 									 list_make1($1), @2.begins);
  				}
  			| a_expr IS NOT DOCUMENT_P				%prec IS
  				{
  					$$ = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL,
  											 makeXmlExpr(IS_DOCUMENT, NULL, NIL,
! 														 list_make1($1), @2.begins),
! 											 @2.begins);
  				}
  		;
  
*************** a_expr:		c_expr									{ $$ = $1; }
*** 10160,10222 ****
  b_expr:		c_expr
  				{ $$ = $1; }
  			| b_expr TYPECAST Typename
! 				{ $$ = makeTypeCast($1, $3, @2); }
  			| '+' b_expr					%prec UMINUS
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", NULL, $2, @1); }
  			| '-' b_expr					%prec UMINUS
! 				{ $$ = doNegate($2, @1); }
  			| b_expr '+' b_expr
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", $1, $3, @2); }
  			| b_expr '-' b_expr
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "-", $1, $3, @2); }
  			| b_expr '*' b_expr
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "*", $1, $3, @2); }
  			| b_expr '/' b_expr
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "/", $1, $3, @2); }
  			| b_expr '%' b_expr
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "%", $1, $3, @2); }
  			| b_expr '^' b_expr
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "^", $1, $3, @2); }
  			| b_expr '<' b_expr
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $3, @2); }
  			| b_expr '>' b_expr
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $3, @2); }
  			| b_expr '=' b_expr
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "=", $1, $3, @2); }
  			| b_expr qual_Op b_expr				%prec Op
! 				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, $3, @2); }
  			| qual_Op b_expr					%prec Op
! 				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $1, NULL, $2, @1); }
  			| b_expr qual_Op					%prec POSTFIXOP
! 				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, NULL, @2); }
  			| b_expr IS DISTINCT FROM b_expr		%prec IS
  				{
! 					$$ = (Node *) makeSimpleA_Expr(AEXPR_DISTINCT, "=", $1, $5, @2);
  				}
  			| b_expr IS NOT DISTINCT FROM b_expr	%prec IS
  				{
  					$$ = (Node *) makeA_Expr(AEXPR_NOT, NIL,
! 						NULL, (Node *) makeSimpleA_Expr(AEXPR_DISTINCT, "=", $1, $6, @2), @2);
  				}
  			| b_expr IS OF '(' type_list ')'		%prec IS
  				{
! 					$$ = (Node *) makeSimpleA_Expr(AEXPR_OF, "=", $1, (Node *) $5, @2);
  				}
  			| b_expr IS NOT OF '(' type_list ')'	%prec IS
  				{
! 					$$ = (Node *) makeSimpleA_Expr(AEXPR_OF, "<>", $1, (Node *) $6, @2);
  				}
  			| b_expr IS DOCUMENT_P					%prec IS
  				{
  					$$ = makeXmlExpr(IS_DOCUMENT, NULL, NIL,
! 									 list_make1($1), @2);
  				}
  			| b_expr IS NOT DOCUMENT_P				%prec IS
  				{
  					$$ = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL,
  											 makeXmlExpr(IS_DOCUMENT, NULL, NIL,
! 														 list_make1($1), @2),
! 											 @2);
  				}
  		;
  
--- 10160,10222 ----
  b_expr:		c_expr
  				{ $$ = $1; }
  			| b_expr TYPECAST Typename
! 				{ $$ = makeTypeCast($1, $3, @2.begins, @2.length); }
  			| '+' b_expr					%prec UMINUS
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", NULL, $2, @1.begins); }
  			| '-' b_expr					%prec UMINUS
! 				{ $$ = doNegate($2, @1.begins, @1.length); }
  			| b_expr '+' b_expr
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", $1, $3, @2.begins); }
  			| b_expr '-' b_expr
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "-", $1, $3, @2.begins); }
  			| b_expr '*' b_expr
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "*", $1, $3, @2.begins); }
  			| b_expr '/' b_expr
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "/", $1, $3, @2.begins); }
  			| b_expr '%' b_expr
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "%", $1, $3, @2.begins); }
  			| b_expr '^' b_expr
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "^", $1, $3, @2.begins); }
  			| b_expr '<' b_expr
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $3, @2.begins); }
  			| b_expr '>' b_expr
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $3, @2.begins); }
  			| b_expr '=' b_expr
! 				{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "=", $1, $3, @2.begins); }
  			| b_expr qual_Op b_expr				%prec Op
! 				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, $3, @2.begins); }
  			| qual_Op b_expr					%prec Op
! 				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $1, NULL, $2, @1.begins); }
  			| b_expr qual_Op					%prec POSTFIXOP
! 				{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, NULL, @2.begins); }
  			| b_expr IS DISTINCT FROM b_expr		%prec IS
  				{
! 					$$ = (Node *) makeSimpleA_Expr(AEXPR_DISTINCT, "=", $1, $5, @2.begins);
  				}
  			| b_expr IS NOT DISTINCT FROM b_expr	%prec IS
  				{
  					$$ = (Node *) makeA_Expr(AEXPR_NOT, NIL,
! 						NULL, (Node *) makeSimpleA_Expr(AEXPR_DISTINCT, "=", $1, $6, @2.begins), @2.begins);
  				}
  			| b_expr IS OF '(' type_list ')'		%prec IS
  				{
! 					$$ = (Node *) makeSimpleA_Expr(AEXPR_OF, "=", $1, (Node *) $5, @2.begins);
  				}
  			| b_expr IS NOT OF '(' type_list ')'	%prec IS
  				{
! 					$$ = (Node *) makeSimpleA_Expr(AEXPR_OF, "<>", $1, (Node *) $6, @2.begins);
  				}
  			| b_expr IS DOCUMENT_P					%prec IS
  				{
  					$$ = makeXmlExpr(IS_DOCUMENT, NULL, NIL,
! 									 list_make1($1), @2.begins);
  				}
  			| b_expr IS NOT DOCUMENT_P				%prec IS
  				{
  					$$ = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL,
  											 makeXmlExpr(IS_DOCUMENT, NULL, NIL,
! 														 list_make1($1), @2.begins),
! 											 @2.begins);
  				}
  		;
  
*************** c_expr:		columnref								{ $$ = $1; }
*** 10234,10240 ****
  				{
  					ParamRef *p = makeNode(ParamRef);
  					p->number = $1;
! 					p->location = @1;
  					if ($2)
  					{
  						A_Indirection *n = makeNode(A_Indirection);
--- 10234,10240 ----
  				{
  					ParamRef *p = makeNode(ParamRef);
  					p->number = $1;
! 					p->location = @1.begins;
  					if ($2)
  					{
  						A_Indirection *n = makeNode(A_Indirection);
*************** c_expr:		columnref								{ $$ = $1; }
*** 10268,10274 ****
  					n->testexpr = NULL;
  					n->operName = NIL;
  					n->subselect = $1;
! 					n->location = @1;
  					$$ = (Node *)n;
  				}
  			| EXISTS select_with_parens
--- 10268,10274 ----
  					n->testexpr = NULL;
  					n->operName = NIL;
  					n->subselect = $1;
! 					n->location = @1.begins;
  					$$ = (Node *)n;
  				}
  			| EXISTS select_with_parens
*************** c_expr:		columnref								{ $$ = $1; }
*** 10278,10284 ****
  					n->testexpr = NULL;
  					n->operName = NIL;
  					n->subselect = $2;
! 					n->location = @1;
  					$$ = (Node *)n;
  				}
  			| ARRAY select_with_parens
--- 10278,10284 ----
  					n->testexpr = NULL;
  					n->operName = NIL;
  					n->subselect = $2;
! 					n->location = @1.begins;
  					$$ = (Node *)n;
  				}
  			| ARRAY select_with_parens
*************** c_expr:		columnref								{ $$ = $1; }
*** 10288,10294 ****
  					n->testexpr = NULL;
  					n->operName = NIL;
  					n->subselect = $2;
! 					n->location = @1;
  					$$ = (Node *)n;
  				}
  			| ARRAY array_expr
--- 10288,10294 ----
  					n->testexpr = NULL;
  					n->operName = NIL;
  					n->subselect = $2;
! 					n->location = @1.begins;
  					$$ = (Node *)n;
  				}
  			| ARRAY array_expr
*************** c_expr:		columnref								{ $$ = $1; }
*** 10296,10302 ****
  					A_ArrayExpr *n = (A_ArrayExpr *) $2;
  					Assert(IsA(n, A_ArrayExpr));
  					/* point outermost A_ArrayExpr to the ARRAY keyword */
! 					n->location = @1;
  					$$ = (Node *)n;
  				}
  			| row
--- 10296,10302 ----
  					A_ArrayExpr *n = (A_ArrayExpr *) $2;
  					Assert(IsA(n, A_ArrayExpr));
  					/* point outermost A_ArrayExpr to the ARRAY keyword */
! 					n->location = @1.begins;
  					$$ = (Node *)n;
  				}
  			| row
*************** c_expr:		columnref								{ $$ = $1; }
*** 10304,10310 ****
  					RowExpr *r = makeNode(RowExpr);
  					r->args = $1;
  					r->row_typeid = InvalidOid;	/* not analyzed yet */
! 					r->location = @1;
  					$$ = (Node *)r;
  				}
  		;
--- 10304,10310 ----
  					RowExpr *r = makeNode(RowExpr);
  					r->args = $1;
  					r->row_typeid = InvalidOid;	/* not analyzed yet */
! 					r->location = @1.begins;
  					$$ = (Node *)r;
  				}
  		;
*************** func_expr:	func_name '(' ')' over_clause
*** 10327,10333 ****
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = $4;
! 					n->location = @1;
  					$$ = (Node *)n;
  				}
  			| func_name '(' func_arg_list ')' over_clause
--- 10327,10333 ----
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = $4;
! 					n->location = @1.begins;
  					$$ = (Node *)n;
  				}
  			| func_name '(' func_arg_list ')' over_clause
*************** func_expr:	func_name '(' ')' over_clause
*** 10340,10346 ****
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = $5;
! 					n->location = @1;
  					$$ = (Node *)n;
  				}
  			| func_name '(' VARIADIC func_arg_expr ')' over_clause
--- 10340,10346 ----
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = $5;
! 					n->location = @1.begins;
  					$$ = (Node *)n;
  				}
  			| func_name '(' VARIADIC func_arg_expr ')' over_clause
*************** func_expr:	func_name '(' ')' over_clause
*** 10353,10359 ****
  					n->agg_distinct = FALSE;
  					n->func_variadic = TRUE;
  					n->over = $6;
! 					n->location = @1;
  					$$ = (Node *)n;
  				}
  			| func_name '(' func_arg_list ',' VARIADIC func_arg_expr ')' over_clause
--- 10353,10359 ----
  					n->agg_distinct = FALSE;
  					n->func_variadic = TRUE;
  					n->over = $6;
! 					n->location = @1.begins;
  					$$ = (Node *)n;
  				}
  			| func_name '(' func_arg_list ',' VARIADIC func_arg_expr ')' over_clause
*************** func_expr:	func_name '(' ')' over_clause
*** 10366,10372 ****
  					n->agg_distinct = FALSE;
  					n->func_variadic = TRUE;
  					n->over = $8;
! 					n->location = @1;
  					$$ = (Node *)n;
  				}
  			| func_name '(' func_arg_list sort_clause ')' over_clause
--- 10366,10372 ----
  					n->agg_distinct = FALSE;
  					n->func_variadic = TRUE;
  					n->over = $8;
! 					n->location = @1.begins;
  					$$ = (Node *)n;
  				}
  			| func_name '(' func_arg_list sort_clause ')' over_clause
*************** func_expr:	func_name '(' ')' over_clause
*** 10379,10385 ****
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = $6;
! 					n->location = @1;
  					$$ = (Node *)n;
  				}
  			| func_name '(' ALL func_arg_list opt_sort_clause ')' over_clause
--- 10379,10385 ----
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = $6;
! 					n->location = @1.begins;
  					$$ = (Node *)n;
  				}
  			| func_name '(' ALL func_arg_list opt_sort_clause ')' over_clause
*************** func_expr:	func_name '(' ')' over_clause
*** 10396,10402 ****
  					 */
  					n->func_variadic = FALSE;
  					n->over = $7;
! 					n->location = @1;
  					$$ = (Node *)n;
  				}
  			| func_name '(' DISTINCT func_arg_list opt_sort_clause ')' over_clause
--- 10396,10402 ----
  					 */
  					n->func_variadic = FALSE;
  					n->over = $7;
! 					n->location = @1.begins;
  					$$ = (Node *)n;
  				}
  			| func_name '(' DISTINCT func_arg_list opt_sort_clause ')' over_clause
*************** func_expr:	func_name '(' ')' over_clause
*** 10409,10415 ****
  					n->agg_distinct = TRUE;
  					n->func_variadic = FALSE;
  					n->over = $7;
! 					n->location = @1;
  					$$ = (Node *)n;
  				}
  			| func_name '(' '*' ')' over_clause
--- 10409,10415 ----
  					n->agg_distinct = TRUE;
  					n->func_variadic = FALSE;
  					n->over = $7;
! 					n->location = @1.begins;
  					$$ = (Node *)n;
  				}
  			| func_name '(' '*' ')' over_clause
*************** func_expr:	func_name '(' ')' over_clause
*** 10432,10438 ****
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = $5;
! 					n->location = @1;
  					$$ = (Node *)n;
  				}
  			| CURRENT_DATE
--- 10432,10438 ----
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = $5;
! 					n->location = @1.begins;
  					$$ = (Node *)n;
  				}
  			| CURRENT_DATE
*************** func_expr:	func_name '(' ')' over_clause
*** 10453,10460 ****
  					 * to rely on it.)
  					 */
  					Node *n;
! 					n = makeStringConstCast("now", @1, SystemTypeName("text"));
! 					$$ = makeTypeCast(n, SystemTypeName("date"), -1);
  				}
  			| CURRENT_TIME
  				{
--- 10453,10460 ----
  					 * to rely on it.)
  					 */
  					Node *n;
! 					n = makeStringConstCast("now", @1.begins, @1.length, SystemTypeName("text"));
! 					$$ = makeTypeCast(n, SystemTypeName("date"), -1, -1);
  				}
  			| CURRENT_TIME
  				{
*************** func_expr:	func_name '(' ')' over_clause
*** 10463,10470 ****
  					 * See comments for CURRENT_DATE.
  					 */
  					Node *n;
! 					n = makeStringConstCast("now", @1, SystemTypeName("text"));
! 					$$ = makeTypeCast(n, SystemTypeName("timetz"), -1);
  				}
  			| CURRENT_TIME '(' Iconst ')'
  				{
--- 10463,10470 ----
  					 * See comments for CURRENT_DATE.
  					 */
  					Node *n;
! 					n = makeStringConstCast("now", @1.begins, @1.length, SystemTypeName("text"));
! 					$$ = makeTypeCast(n, SystemTypeName("timetz"), -1, -1);
  				}
  			| CURRENT_TIME '(' Iconst ')'
  				{
*************** func_expr:	func_name '(' ')' over_clause
*** 10474,10483 ****
  					 */
  					Node *n;
  					TypeName *d;
! 					n = makeStringConstCast("now", @1, SystemTypeName("text"));
  					d = SystemTypeName("timetz");
! 					d->typmods = list_make1(makeIntConst($3, @3));
! 					$$ = makeTypeCast(n, d, -1);
  				}
  			| CURRENT_TIMESTAMP
  				{
--- 10474,10483 ----
  					 */
  					Node *n;
  					TypeName *d;
! 					n = makeStringConstCast("now", @1.begins, @1.length, SystemTypeName("text"));
  					d = SystemTypeName("timetz");
! 					d->typmods = list_make1(makeIntConst($3, @3.begins, @3.length));
! 					$$ = makeTypeCast(n, d, -1, -1);
  				}
  			| CURRENT_TIMESTAMP
  				{
*************** func_expr:	func_name '(' ')' over_clause
*** 10493,10499 ****
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @1;
  					$$ = (Node *)n;
  				}
  			| CURRENT_TIMESTAMP '(' Iconst ')'
--- 10493,10499 ----
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @1.begins;
  					$$ = (Node *)n;
  				}
  			| CURRENT_TIMESTAMP '(' Iconst ')'
*************** func_expr:	func_name '(' ')' over_clause
*** 10504,10513 ****
  					 */
  					Node *n;
  					TypeName *d;
! 					n = makeStringConstCast("now", @1, SystemTypeName("text"));
  					d = SystemTypeName("timestamptz");
! 					d->typmods = list_make1(makeIntConst($3, @3));
! 					$$ = makeTypeCast(n, d, -1);
  				}
  			| LOCALTIME
  				{
--- 10504,10513 ----
  					 */
  					Node *n;
  					TypeName *d;
! 					n = makeStringConstCast("now", @1.begins, @1.length, SystemTypeName("text"));
  					d = SystemTypeName("timestamptz");
! 					d->typmods = list_make1(makeIntConst($3, @3.begins, @3.length));
! 					$$ = makeTypeCast(n, d, -1, -1);
  				}
  			| LOCALTIME
  				{
*************** func_expr:	func_name '(' ')' over_clause
*** 10516,10523 ****
  					 * See comments for CURRENT_DATE.
  					 */
  					Node *n;
! 					n = makeStringConstCast("now", @1, SystemTypeName("text"));
! 					$$ = makeTypeCast((Node *)n, SystemTypeName("time"), -1);
  				}
  			| LOCALTIME '(' Iconst ')'
  				{
--- 10516,10523 ----
  					 * See comments for CURRENT_DATE.
  					 */
  					Node *n;
! 					n = makeStringConstCast("now", @1.begins, @1.length, SystemTypeName("text"));
! 					$$ = makeTypeCast((Node *)n, SystemTypeName("time"), -1, -1);
  				}
  			| LOCALTIME '(' Iconst ')'
  				{
*************** func_expr:	func_name '(' ')' over_clause
*** 10527,10536 ****
  					 */
  					Node *n;
  					TypeName *d;
! 					n = makeStringConstCast("now", @1, SystemTypeName("text"));
  					d = SystemTypeName("time");
! 					d->typmods = list_make1(makeIntConst($3, @3));
! 					$$ = makeTypeCast((Node *)n, d, -1);
  				}
  			| LOCALTIMESTAMP
  				{
--- 10527,10536 ----
  					 */
  					Node *n;
  					TypeName *d;
! 					n = makeStringConstCast("now", @1.begins, @1.length, SystemTypeName("text"));
  					d = SystemTypeName("time");
! 					d->typmods = list_make1(makeIntConst($3, @3.begins, @3.length));
! 					$$ = makeTypeCast((Node *)n, d, -1, -1);
  				}
  			| LOCALTIMESTAMP
  				{
*************** func_expr:	func_name '(' ')' over_clause
*** 10539,10546 ****
  					 * See comments for CURRENT_DATE.
  					 */
  					Node *n;
! 					n = makeStringConstCast("now", @1, SystemTypeName("text"));
! 					$$ = makeTypeCast(n, SystemTypeName("timestamp"), -1);
  				}
  			| LOCALTIMESTAMP '(' Iconst ')'
  				{
--- 10539,10546 ----
  					 * See comments for CURRENT_DATE.
  					 */
  					Node *n;
! 					n = makeStringConstCast("now", @1.begins, @1.length, SystemTypeName("text"));
! 					$$ = makeTypeCast(n, SystemTypeName("timestamp"), -1, -1);
  				}
  			| LOCALTIMESTAMP '(' Iconst ')'
  				{
*************** func_expr:	func_name '(' ')' over_clause
*** 10550,10559 ****
  					 */
  					Node *n;
  					TypeName *d;
! 					n = makeStringConstCast("now", @1, SystemTypeName("text"));
  					d = SystemTypeName("timestamp");
! 					d->typmods = list_make1(makeIntConst($3, @3));
! 					$$ = makeTypeCast(n, d, -1);
  				}
  			| CURRENT_ROLE
  				{
--- 10550,10559 ----
  					 */
  					Node *n;
  					TypeName *d;
! 					n = makeStringConstCast("now", @1.begins, @1.length, SystemTypeName("text"));
  					d = SystemTypeName("timestamp");
! 					d->typmods = list_make1(makeIntConst($3, @3.begins, @3.length));
! 					$$ = makeTypeCast(n, d, -1, -1);
  				}
  			| CURRENT_ROLE
  				{
*************** func_expr:	func_name '(' ')' over_clause
*** 10565,10571 ****
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @1;
  					$$ = (Node *)n;
  				}
  			| CURRENT_USER
--- 10565,10571 ----
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @1.begins;
  					$$ = (Node *)n;
  				}
  			| CURRENT_USER
*************** func_expr:	func_name '(' ')' over_clause
*** 10578,10584 ****
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @1;
  					$$ = (Node *)n;
  				}
  			| SESSION_USER
--- 10578,10584 ----
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @1.begins;
  					$$ = (Node *)n;
  				}
  			| SESSION_USER
*************** func_expr:	func_name '(' ')' over_clause
*** 10591,10597 ****
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @1;
  					$$ = (Node *)n;
  				}
  			| USER
--- 10591,10597 ----
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @1.begins;
  					$$ = (Node *)n;
  				}
  			| USER
*************** func_expr:	func_name '(' ')' over_clause
*** 10604,10610 ****
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @1;
  					$$ = (Node *)n;
  				}
  			| CURRENT_CATALOG
--- 10604,10610 ----
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @1.begins;
  					$$ = (Node *)n;
  				}
  			| CURRENT_CATALOG
*************** func_expr:	func_name '(' ')' over_clause
*** 10617,10623 ****
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @1;
  					$$ = (Node *)n;
  				}
  			| CURRENT_SCHEMA
--- 10617,10623 ----
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @1.begins;
  					$$ = (Node *)n;
  				}
  			| CURRENT_SCHEMA
*************** func_expr:	func_name '(' ')' over_clause
*** 10630,10640 ****
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @1;
  					$$ = (Node *)n;
  				}
  			| CAST '(' a_expr AS Typename ')'
! 				{ $$ = makeTypeCast($3, $5, @1); }
  			| EXTRACT '(' extract_list ')'
  				{
  					FuncCall *n = makeNode(FuncCall);
--- 10630,10640 ----
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @1.begins;
  					$$ = (Node *)n;
  				}
  			| CAST '(' a_expr AS Typename ')'
! 				{ $$ = makeTypeCast($3, $5, @1.begins, @1.length); }
  			| EXTRACT '(' extract_list ')'
  				{
  					FuncCall *n = makeNode(FuncCall);
*************** func_expr:	func_name '(' ')' over_clause
*** 10645,10651 ****
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @1;
  					$$ = (Node *)n;
  				}
  			| OVERLAY '(' overlay_list ')'
--- 10645,10651 ----
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @1.begins;
  					$$ = (Node *)n;
  				}
  			| OVERLAY '(' overlay_list ')'
*************** func_expr:	func_name '(' ')' over_clause
*** 10663,10669 ****
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @1;
  					$$ = (Node *)n;
  				}
  			| POSITION '(' position_list ')'
--- 10663,10669 ----
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @1.begins;
  					$$ = (Node *)n;
  				}
  			| POSITION '(' position_list ')'
*************** func_expr:	func_name '(' ')' over_clause
*** 10677,10683 ****
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @1;
  					$$ = (Node *)n;
  				}
  			| SUBSTRING '(' substr_list ')'
--- 10677,10683 ----
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @1.begins;
  					$$ = (Node *)n;
  				}
  			| SUBSTRING '(' substr_list ')'
*************** func_expr:	func_name '(' ')' over_clause
*** 10693,10699 ****
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @1;
  					$$ = (Node *)n;
  				}
  			| TREAT '(' a_expr AS Typename ')'
--- 10693,10699 ----
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @1.begins;
  					$$ = (Node *)n;
  				}
  			| TREAT '(' a_expr AS Typename ')'
*************** func_expr:	func_name '(' ')' over_clause
*** 10715,10721 ****
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @1;
  					$$ = (Node *)n;
  				}
  			| TRIM '(' BOTH trim_list ')'
--- 10715,10721 ----
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @1.begins;
  					$$ = (Node *)n;
  				}
  			| TRIM '(' BOTH trim_list ')'
*************** func_expr:	func_name '(' ')' over_clause
*** 10731,10737 ****
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @1;
  					$$ = (Node *)n;
  				}
  			| TRIM '(' LEADING trim_list ')'
--- 10731,10737 ----
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @1.begins;
  					$$ = (Node *)n;
  				}
  			| TRIM '(' LEADING trim_list ')'
*************** func_expr:	func_name '(' ')' over_clause
*** 10744,10750 ****
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @1;
  					$$ = (Node *)n;
  				}
  			| TRIM '(' TRAILING trim_list ')'
--- 10744,10750 ----
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @1.begins;
  					$$ = (Node *)n;
  				}
  			| TRIM '(' TRAILING trim_list ')'
*************** func_expr:	func_name '(' ')' over_clause
*** 10757,10763 ****
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @1;
  					$$ = (Node *)n;
  				}
  			| TRIM '(' trim_list ')'
--- 10757,10763 ----
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @1.begins;
  					$$ = (Node *)n;
  				}
  			| TRIM '(' trim_list ')'
*************** func_expr:	func_name '(' ')' over_clause
*** 10770,10787 ****
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @1;
  					$$ = (Node *)n;
  				}
  			| NULLIF '(' a_expr ',' a_expr ')'
  				{
! 					$$ = (Node *) makeSimpleA_Expr(AEXPR_NULLIF, "=", $3, $5, @1);
  				}
  			| COALESCE '(' expr_list ')'
  				{
  					CoalesceExpr *c = makeNode(CoalesceExpr);
  					c->args = $3;
! 					c->location = @1;
  					$$ = (Node *)c;
  				}
  			| GREATEST '(' expr_list ')'
--- 10770,10787 ----
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @1.begins;
  					$$ = (Node *)n;
  				}
  			| NULLIF '(' a_expr ',' a_expr ')'
  				{
! 					$$ = (Node *) makeSimpleA_Expr(AEXPR_NULLIF, "=", $3, $5, @1.begins);
  				}
  			| COALESCE '(' expr_list ')'
  				{
  					CoalesceExpr *c = makeNode(CoalesceExpr);
  					c->args = $3;
! 					c->location = @1.begins;
  					$$ = (Node *)c;
  				}
  			| GREATEST '(' expr_list ')'
*************** func_expr:	func_name '(' ')' over_clause
*** 10789,10795 ****
  					MinMaxExpr *v = makeNode(MinMaxExpr);
  					v->args = $3;
  					v->op = IS_GREATEST;
! 					v->location = @1;
  					$$ = (Node *)v;
  				}
  			| LEAST '(' expr_list ')'
--- 10789,10795 ----
  					MinMaxExpr *v = makeNode(MinMaxExpr);
  					v->args = $3;
  					v->op = IS_GREATEST;
! 					v->location = @1.begins;
  					$$ = (Node *)v;
  				}
  			| LEAST '(' expr_list ')'
*************** func_expr:	func_name '(' ')' over_clause
*** 10797,10824 ****
  					MinMaxExpr *v = makeNode(MinMaxExpr);
  					v->args = $3;
  					v->op = IS_LEAST;
! 					v->location = @1;
  					$$ = (Node *)v;
  				}
  			| XMLCONCAT '(' expr_list ')'
  				{
! 					$$ = makeXmlExpr(IS_XMLCONCAT, NULL, NIL, $3, @1);
  				}
  			| XMLELEMENT '(' NAME_P ColLabel ')'
  				{
! 					$$ = makeXmlExpr(IS_XMLELEMENT, $4, NIL, NIL, @1);
  				}
  			| XMLELEMENT '(' NAME_P ColLabel ',' xml_attributes ')'
  				{
! 					$$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, NIL, @1);
  				}
  			| XMLELEMENT '(' NAME_P ColLabel ',' expr_list ')'
  				{
! 					$$ = makeXmlExpr(IS_XMLELEMENT, $4, NIL, $6, @1);
  				}
  			| XMLELEMENT '(' NAME_P ColLabel ',' xml_attributes ',' expr_list ')'
  				{
! 					$$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, $8, @1);
  				}
  			| XMLEXISTS '(' c_expr xmlexists_argument ')'
  				{
--- 10797,10824 ----
  					MinMaxExpr *v = makeNode(MinMaxExpr);
  					v->args = $3;
  					v->op = IS_LEAST;
! 					v->location = @1.begins;
  					$$ = (Node *)v;
  				}
  			| XMLCONCAT '(' expr_list ')'
  				{
! 					$$ = makeXmlExpr(IS_XMLCONCAT, NULL, NIL, $3, @1.begins);
  				}
  			| XMLELEMENT '(' NAME_P ColLabel ')'
  				{
! 					$$ = makeXmlExpr(IS_XMLELEMENT, $4, NIL, NIL, @1.begins);
  				}
  			| XMLELEMENT '(' NAME_P ColLabel ',' xml_attributes ')'
  				{
! 					$$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, NIL, @1.begins);
  				}
  			| XMLELEMENT '(' NAME_P ColLabel ',' expr_list ')'
  				{
! 					$$ = makeXmlExpr(IS_XMLELEMENT, $4, NIL, $6, @1.begins);
  				}
  			| XMLELEMENT '(' NAME_P ColLabel ',' xml_attributes ',' expr_list ')'
  				{
! 					$$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, $8, @1.begins);
  				}
  			| XMLEXISTS '(' c_expr xmlexists_argument ')'
  				{
*************** func_expr:	func_name '(' ')' over_clause
*** 10832,10865 ****
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @1;
  					$$ = (Node *)n;
  				}
  			| XMLFOREST '(' xml_attribute_list ')'
  				{
! 					$$ = makeXmlExpr(IS_XMLFOREST, NULL, $3, NIL, @1);
  				}
  			| XMLPARSE '(' document_or_content a_expr xml_whitespace_option ')'
  				{
  					XmlExpr *x = (XmlExpr *)
  						makeXmlExpr(IS_XMLPARSE, NULL, NIL,
! 									list_make2($4, makeBoolAConst($5, -1)),
! 									@1);
  					x->xmloption = $3;
  					$$ = (Node *)x;
  				}
  			| XMLPI '(' NAME_P ColLabel ')'
  				{
! 					$$ = makeXmlExpr(IS_XMLPI, $4, NULL, NIL, @1);
  				}
  			| XMLPI '(' NAME_P ColLabel ',' a_expr ')'
  				{
! 					$$ = makeXmlExpr(IS_XMLPI, $4, NULL, list_make1($6), @1);
  				}
  			| XMLROOT '(' a_expr ',' xml_root_version opt_xml_root_standalone ')'
  				{
  					$$ = makeXmlExpr(IS_XMLROOT, NULL, NIL,
! 									 list_make3($3, $5, $6), @1);
  				}
  			| XMLSERIALIZE '(' document_or_content a_expr AS SimpleTypename ')'
  				{
--- 10832,10865 ----
  					n->agg_distinct = FALSE;
  					n->func_variadic = FALSE;
  					n->over = NULL;
! 					n->location = @1.begins;
  					$$ = (Node *)n;
  				}
  			| XMLFOREST '(' xml_attribute_list ')'
  				{
! 					$$ = makeXmlExpr(IS_XMLFOREST, NULL, $3, NIL, @1.begins);
  				}
  			| XMLPARSE '(' document_or_content a_expr xml_whitespace_option ')'
  				{
  					XmlExpr *x = (XmlExpr *)
  						makeXmlExpr(IS_XMLPARSE, NULL, NIL,
! 									list_make2($4, makeBoolAConst($5, -1, -1)),
! 									@1.begins);
  					x->xmloption = $3;
  					$$ = (Node *)x;
  				}
  			| XMLPI '(' NAME_P ColLabel ')'
  				{
! 					$$ = makeXmlExpr(IS_XMLPI, $4, NULL, NIL, @1.begins);
  				}
  			| XMLPI '(' NAME_P ColLabel ',' a_expr ')'
  				{
! 					$$ = makeXmlExpr(IS_XMLPI, $4, NULL, list_make1($6), @1.begins);
  				}
  			| XMLROOT '(' a_expr ',' xml_root_version opt_xml_root_standalone ')'
  				{
  					$$ = makeXmlExpr(IS_XMLROOT, NULL, NIL,
! 									 list_make3($3, $5, $6), @1.begins);
  				}
  			| XMLSERIALIZE '(' document_or_content a_expr AS SimpleTypename ')'
  				{
*************** func_expr:	func_name '(' ')' over_clause
*** 10867,10873 ****
  					n->xmloption = $3;
  					n->expr = $4;
  					n->typeName = $6;
! 					n->location = @1;
  					$$ = (Node *)n;
  				}
  		;
--- 10867,10873 ----
  					n->xmloption = $3;
  					n->expr = $4;
  					n->typeName = $6;
! 					n->location = @1.begins;
  					$$ = (Node *)n;
  				}
  		;
*************** func_expr:	func_name '(' ')' over_clause
*** 10878,10894 ****
  xml_root_version: VERSION_P a_expr
  				{ $$ = $2; }
  			| VERSION_P NO VALUE_P
! 				{ $$ = makeNullAConst(-1); }
  		;
  
  opt_xml_root_standalone: ',' STANDALONE_P YES_P
! 				{ $$ = makeIntConst(XML_STANDALONE_YES, -1); }
  			| ',' STANDALONE_P NO
! 				{ $$ = makeIntConst(XML_STANDALONE_NO, -1); }
  			| ',' STANDALONE_P NO VALUE_P
! 				{ $$ = makeIntConst(XML_STANDALONE_NO_VALUE, -1); }
  			| /*EMPTY*/
! 				{ $$ = makeIntConst(XML_STANDALONE_OMITTED, -1); }
  		;
  
  xml_attributes: XMLATTRIBUTES '(' xml_attribute_list ')'	{ $$ = $3; }
--- 10878,10894 ----
  xml_root_version: VERSION_P a_expr
  				{ $$ = $2; }
  			| VERSION_P NO VALUE_P
! 				{ $$ = makeNullAConst(-1, -1); }
  		;
  
  opt_xml_root_standalone: ',' STANDALONE_P YES_P
! 				{ $$ = makeIntConst(XML_STANDALONE_YES, -1, -1); }
  			| ',' STANDALONE_P NO
! 				{ $$ = makeIntConst(XML_STANDALONE_NO, -1, -1); }
  			| ',' STANDALONE_P NO VALUE_P
! 				{ $$ = makeIntConst(XML_STANDALONE_NO_VALUE, -1, -1); }
  			| /*EMPTY*/
! 				{ $$ = makeIntConst(XML_STANDALONE_OMITTED, -1, -1); }
  		;
  
  xml_attributes: XMLATTRIBUTES '(' xml_attribute_list ')'	{ $$ = $3; }
*************** xml_attribute_el: a_expr AS ColLabel
*** 10904,10910 ****
  					$$->name = $3;
  					$$->indirection = NIL;
  					$$->val = (Node *) $1;
! 					$$->location = @1;
  				}
  			| a_expr
  				{
--- 10904,10910 ----
  					$$->name = $3;
  					$$->indirection = NIL;
  					$$->val = (Node *) $1;
! 					$$->location = @1.begins;
  				}
  			| a_expr
  				{
*************** xml_attribute_el: a_expr AS ColLabel
*** 10912,10918 ****
  					$$->name = NULL;
  					$$->indirection = NIL;
  					$$->val = (Node *) $1;
! 					$$->location = @1;
  				}
  		;
  
--- 10912,10918 ----
  					$$->name = NULL;
  					$$->indirection = NIL;
  					$$->val = (Node *) $1;
! 					$$->location = @1.begins;
  				}
  		;
  
*************** over_clause: OVER window_specification
*** 10981,10987 ****
  					n->frameOptions = FRAMEOPTION_DEFAULTS;
  					n->startOffset = NULL;
  					n->endOffset = NULL;
! 					n->location = @2;
  					$$ = n;
  				}
  			| /*EMPTY*/
--- 10981,10987 ----
  					n->frameOptions = FRAMEOPTION_DEFAULTS;
  					n->startOffset = NULL;
  					n->endOffset = NULL;
! 					n->location = @2.begins;
  					$$ = n;
  				}
  			| /*EMPTY*/
*************** window_specification: '(' opt_existing_w
*** 11000,11006 ****
  					n->frameOptions = $5->frameOptions;
  					n->startOffset = $5->startOffset;
  					n->endOffset = $5->endOffset;
! 					n->location = @1;
  					$$ = n;
  				}
  		;
--- 11000,11006 ----
  					n->frameOptions = $5->frameOptions;
  					n->startOffset = $5->startOffset;
  					n->endOffset = $5->endOffset;
! 					n->location = @1.begins;
  					$$ = n;
  				}
  		;
*************** opt_frame_clause:
*** 11040,11052 ****
  						ereport(ERROR,
  								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
  								 errmsg("RANGE PRECEDING is only supported with UNBOUNDED"),
! 								 parser_errposition(@1)));
  					if (n->frameOptions & (FRAMEOPTION_START_VALUE_FOLLOWING |
  										   FRAMEOPTION_END_VALUE_FOLLOWING))
  						ereport(ERROR,
  								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
  								 errmsg("RANGE FOLLOWING is only supported with UNBOUNDED"),
! 								 parser_errposition(@1)));
  					$$ = n;
  				}
  			| ROWS frame_extent
--- 11040,11052 ----
  						ereport(ERROR,
  								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
  								 errmsg("RANGE PRECEDING is only supported with UNBOUNDED"),
! 								 parser_errposition(@1.begins)));
  					if (n->frameOptions & (FRAMEOPTION_START_VALUE_FOLLOWING |
  										   FRAMEOPTION_END_VALUE_FOLLOWING))
  						ereport(ERROR,
  								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
  								 errmsg("RANGE FOLLOWING is only supported with UNBOUNDED"),
! 								 parser_errposition(@1.begins)));
  					$$ = n;
  				}
  			| ROWS frame_extent
*************** frame_extent: frame_bound
*** 11073,11084 ****
  						ereport(ERROR,
  								(errcode(ERRCODE_WINDOWING_ERROR),
  								 errmsg("frame start cannot be UNBOUNDED FOLLOWING"),
! 								 parser_errposition(@1)));
  					if (n->frameOptions & FRAMEOPTION_START_VALUE_FOLLOWING)
  						ereport(ERROR,
  								(errcode(ERRCODE_WINDOWING_ERROR),
  								 errmsg("frame starting from following row cannot end with current row"),
! 								 parser_errposition(@1)));
  					n->frameOptions |= FRAMEOPTION_END_CURRENT_ROW;
  					$$ = n;
  				}
--- 11073,11084 ----
  						ereport(ERROR,
  								(errcode(ERRCODE_WINDOWING_ERROR),
  								 errmsg("frame start cannot be UNBOUNDED FOLLOWING"),
! 								 parser_errposition(@1.begins)));
  					if (n->frameOptions & FRAMEOPTION_START_VALUE_FOLLOWING)
  						ereport(ERROR,
  								(errcode(ERRCODE_WINDOWING_ERROR),
  								 errmsg("frame starting from following row cannot end with current row"),
! 								 parser_errposition(@1.begins)));
  					n->frameOptions |= FRAMEOPTION_END_CURRENT_ROW;
  					$$ = n;
  				}
*************** frame_extent: frame_bound
*** 11096,11120 ****
  						ereport(ERROR,
  								(errcode(ERRCODE_WINDOWING_ERROR),
  								 errmsg("frame start cannot be UNBOUNDED FOLLOWING"),
! 								 parser_errposition(@2)));
  					if (frameOptions & FRAMEOPTION_END_UNBOUNDED_PRECEDING)
  						ereport(ERROR,
  								(errcode(ERRCODE_WINDOWING_ERROR),
  								 errmsg("frame end cannot be UNBOUNDED PRECEDING"),
! 								 parser_errposition(@4)));
  					if ((frameOptions & FRAMEOPTION_START_CURRENT_ROW) &&
  						(frameOptions & FRAMEOPTION_END_VALUE_PRECEDING))
  						ereport(ERROR,
  								(errcode(ERRCODE_WINDOWING_ERROR),
  								 errmsg("frame starting from current row cannot have preceding rows"),
! 								 parser_errposition(@4)));
  					if ((frameOptions & FRAMEOPTION_START_VALUE_FOLLOWING) &&
  						(frameOptions & (FRAMEOPTION_END_VALUE_PRECEDING |
  										 FRAMEOPTION_END_CURRENT_ROW)))
  						ereport(ERROR,
  								(errcode(ERRCODE_WINDOWING_ERROR),
  								 errmsg("frame starting from following row cannot have preceding rows"),
! 								 parser_errposition(@4)));
  					n1->frameOptions = frameOptions;
  					n1->endOffset = n2->startOffset;
  					$$ = n1;
--- 11096,11120 ----
  						ereport(ERROR,
  								(errcode(ERRCODE_WINDOWING_ERROR),
  								 errmsg("frame start cannot be UNBOUNDED FOLLOWING"),
! 								 parser_errposition(@2.begins)));
  					if (frameOptions & FRAMEOPTION_END_UNBOUNDED_PRECEDING)
  						ereport(ERROR,
  								(errcode(ERRCODE_WINDOWING_ERROR),
  								 errmsg("frame end cannot be UNBOUNDED PRECEDING"),
! 								 parser_errposition(@4.begins)));
  					if ((frameOptions & FRAMEOPTION_START_CURRENT_ROW) &&
  						(frameOptions & FRAMEOPTION_END_VALUE_PRECEDING))
  						ereport(ERROR,
  								(errcode(ERRCODE_WINDOWING_ERROR),
  								 errmsg("frame starting from current row cannot have preceding rows"),
! 								 parser_errposition(@4.begins)));
  					if ((frameOptions & FRAMEOPTION_START_VALUE_FOLLOWING) &&
  						(frameOptions & (FRAMEOPTION_END_VALUE_PRECEDING |
  										 FRAMEOPTION_END_CURRENT_ROW)))
  						ereport(ERROR,
  								(errcode(ERRCODE_WINDOWING_ERROR),
  								 errmsg("frame starting from following row cannot have preceding rows"),
! 								 parser_errposition(@4.begins)));
  					n1->frameOptions = frameOptions;
  					n1->endOffset = n2->startOffset;
  					$$ = n1;
*************** func_arg_expr:  a_expr
*** 11272,11278 ****
  					na->name = $1;
  					na->arg = (Expr *) $3;
  					na->argnumber = -1;		/* until determined */
! 					na->location = @1;
  					$$ = (Node *) na;
  				}
  		;
--- 11272,11278 ----
  					na->name = $1;
  					na->arg = (Expr *) $3;
  					na->argnumber = -1;		/* until determined */
! 					na->location = @1.begins;
  					$$ = (Node *) na;
  				}
  		;
*************** type_list:	Typename								{ $$ = list_m
*** 11283,11297 ****
  
  array_expr: '[' expr_list ']'
  				{
! 					$$ = makeAArrayExpr($2, @1);
  				}
  			| '[' array_expr_list ']'
  				{
! 					$$ = makeAArrayExpr($2, @1);
  				}
  			| '[' ']'
  				{
! 					$$ = makeAArrayExpr(NIL, @1);
  				}
  		;
  
--- 11283,11297 ----
  
  array_expr: '[' expr_list ']'
  				{
! 					$$ = makeAArrayExpr($2, @1.begins);
  				}
  			| '[' array_expr_list ']'
  				{
! 					$$ = makeAArrayExpr($2, @1.begins);
  				}
  			| '[' ']'
  				{
! 					$$ = makeAArrayExpr(NIL, @1.begins);
  				}
  		;
  
*************** array_expr_list: array_expr							{ $$ =
*** 11303,11309 ****
  extract_list:
  			extract_arg FROM a_expr
  				{
! 					$$ = list_make2(makeStringConst($1, @1), $3);
  				}
  			| /*EMPTY*/								{ $$ = NIL; }
  		;
--- 11303,11309 ----
  extract_list:
  			extract_arg FROM a_expr
  				{
! 					$$ = list_make2(makeStringConst($1, @1.begins, @1.length), $3);
  				}
  			| /*EMPTY*/								{ $$ = NIL; }
  		;
*************** substr_list:
*** 11388,11396 ****
  					 * which it is likely to do if the second argument
  					 * is unknown or doesn't have an implicit cast to int4.
  					 */
! 					$$ = list_make3($1, makeIntConst(1, -1),
  									makeTypeCast($2,
! 												 SystemTypeName("int4"), -1));
  				}
  			| expr_list
  				{
--- 11388,11396 ----
  					 * which it is likely to do if the second argument
  					 * is unknown or doesn't have an implicit cast to int4.
  					 */
! 					$$ = list_make3($1, makeIntConst(1, -1, -1),
  									makeTypeCast($2,
! 												 SystemTypeName("int4"), -1, -1));
  				}
  			| expr_list
  				{
*************** case_expr:	CASE case_arg when_clause_lis
*** 11436,11442 ****
  					c->arg = (Expr *) $2;
  					c->args = $3;
  					c->defresult = (Expr *) $4;
! 					c->location = @1;
  					$$ = (Node *)c;
  				}
  		;
--- 11436,11442 ----
  					c->arg = (Expr *) $2;
  					c->args = $3;
  					c->defresult = (Expr *) $4;
! 					c->location = @1.begins;
  					$$ = (Node *)c;
  				}
  		;
*************** when_clause:
*** 11453,11459 ****
  					CaseWhen *w = makeNode(CaseWhen);
  					w->expr = (Expr *) $2;
  					w->result = (Expr *) $4;
! 					w->location = @1;
  					$$ = (Node *)w;
  				}
  		;
--- 11453,11459 ----
  					CaseWhen *w = makeNode(CaseWhen);
  					w->expr = (Expr *) $2;
  					w->result = (Expr *) $4;
! 					w->location = @1.begins;
  					$$ = (Node *)w;
  				}
  		;
*************** case_arg:	a_expr									{ $$ = $1; }
*** 11469,11479 ****
  
  columnref:	ColId
  				{
! 					$$ = makeColumnRef($1, NIL, @1, yyscanner);
  				}
  			| ColId indirection
  				{
! 					$$ = makeColumnRef($1, $2, @1, yyscanner);
  				}
  		;
  
--- 11469,11479 ----
  
  columnref:	ColId
  				{
! 					$$ = makeColumnRef($1, NIL, @1.begins, yyscanner);
  				}
  			| ColId indirection
  				{
! 					$$ = makeColumnRef($1, $2, @1.begins, yyscanner);
  				}
  		;
  
*************** ctext_expr:
*** 11528,11534 ****
  			| DEFAULT
  				{
  					SetToDefault *n = makeNode(SetToDefault);
! 					n->location = @1;
  					$$ = (Node *) n;
  				}
  		;
--- 11528,11534 ----
  			| DEFAULT
  				{
  					SetToDefault *n = makeNode(SetToDefault);
! 					n->location = @1.begins;
  					$$ = (Node *) n;
  				}
  		;
*************** target_el:	a_expr AS ColLabel
*** 11564,11570 ****
  					$$->name = $3;
  					$$->indirection = NIL;
  					$$->val = (Node *)$1;
! 					$$->location = @1;
  				}
  			/*
  			 * We support omitting AS only for column labels that aren't
--- 11564,11570 ----
  					$$->name = $3;
  					$$->indirection = NIL;
  					$$->val = (Node *)$1;
! 					$$->location = @1.begins;
  				}
  			/*
  			 * We support omitting AS only for column labels that aren't
*************** target_el:	a_expr AS ColLabel
*** 11580,11586 ****
  					$$->name = $2;
  					$$->indirection = NIL;
  					$$->val = (Node *)$1;
! 					$$->location = @1;
  				}
  			| a_expr
  				{
--- 11580,11586 ----
  					$$->name = $2;
  					$$->indirection = NIL;
  					$$->val = (Node *)$1;
! 					$$->location = @1.begins;
  				}
  			| a_expr
  				{
*************** target_el:	a_expr AS ColLabel
*** 11588,11606 ****
  					$$->name = NULL;
  					$$->indirection = NIL;
  					$$->val = (Node *)$1;
! 					$$->location = @1;
  				}
  			| '*'
  				{
  					ColumnRef *n = makeNode(ColumnRef);
  					n->fields = list_make1(makeNode(A_Star));
! 					n->location = @1;
  
  					$$ = makeNode(ResTarget);
  					$$->name = NULL;
  					$$->indirection = NIL;
  					$$->val = (Node *)n;
! 					$$->location = @1;
  				}
  		;
  
--- 11588,11606 ----
  					$$->name = NULL;
  					$$->indirection = NIL;
  					$$->val = (Node *)$1;
! 					$$->location = @1.begins;
  				}
  			| '*'
  				{
  					ColumnRef *n = makeNode(ColumnRef);
  					n->fields = list_make1(makeNode(A_Star));
! 					n->location = @1.begins;
  
  					$$ = makeNode(ResTarget);
  					$$->name = NULL;
  					$$->indirection = NIL;
  					$$->val = (Node *)n;
! 					$$->location = @1.begins;
  				}
  		;
  
*************** qualified_name_list:
*** 11626,11637 ****
  qualified_name:
  			ColId
  				{
! 					$$ = makeRangeVar(NULL, $1, @1);
  				}
  			| ColId indirection
  				{
  					check_qualified_name($2, yyscanner);
! 					$$ = makeRangeVar(NULL, NULL, @1);
  					switch (list_length($2))
  					{
  						case 1:
--- 11626,11637 ----
  qualified_name:
  			ColId
  				{
! 					$$ = makeRangeVar(NULL, $1, @1.begins);
  				}
  			| ColId indirection
  				{
  					check_qualified_name($2, yyscanner);
! 					$$ = makeRangeVar(NULL, NULL, @1.begins);
  					switch (list_length($2))
  					{
  						case 1:
*************** qualified_name:
*** 11649,11655 ****
  									(errcode(ERRCODE_SYNTAX_ERROR),
  									 errmsg("improper qualified name (too many dotted names): %s",
  											NameListToString(lcons(makeString($1), $2))),
! 									 parser_errposition(@1)));
  							break;
  					}
  				}
--- 11649,11655 ----
  									(errcode(ERRCODE_SYNTAX_ERROR),
  									 errmsg("improper qualified name (too many dotted names): %s",
  											NameListToString(lcons(makeString($1), $2))),
! 									 parser_errposition(@1.begins)));
  							break;
  					}
  				}
*************** func_name:	type_function_name
*** 11699,11717 ****
   */
  AexprConst: Iconst
  				{
! 					$$ = makeIntConst($1, @1);
  				}
  			| FCONST
  				{
! 					$$ = makeFloatConst($1, @1);
  				}
  			| Sconst
  				{
! 					$$ = makeStringConst($1, @1);
  				}
  			| BCONST
  				{
! 					$$ = makeBitStringConst($1, @1);
  				}
  			| XCONST
  				{
--- 11699,11717 ----
   */
  AexprConst: Iconst
  				{
! 					$$ = makeIntConst($1, @1.begins, @1.length);
  				}
  			| FCONST
  				{
! 					$$ = makeFloatConst($1, @1.begins, @1.length);
  				}
  			| Sconst
  				{
! 					$$ = makeStringConst($1, @1.begins, @1.length);
  				}
  			| BCONST
  				{
! 					$$ = makeBitStringConst($1, @1.begins, @1.length);
  				}
  			| XCONST
  				{
*************** AexprConst: Iconst
*** 11720,11733 ****
  					 * a <general literal> shall not be a
  					 * <bit string literal> or a <hex string literal>.
  					 */
! 					$$ = makeBitStringConst($1, @1);
  				}
  			| func_name Sconst
  				{
  					/* generic type 'literal' syntax */
  					TypeName *t = makeTypeNameFromNameList($1);
! 					t->location = @1;
! 					$$ = makeStringConstCast($2, @2, t);
  				}
  			| func_name '(' func_arg_list ')' Sconst
  				{
--- 11720,11733 ----
  					 * a <general literal> shall not be a
  					 * <bit string literal> or a <hex string literal>.
  					 */
! 					$$ = makeBitStringConst($1, @1.begins, @1.length);
  				}
  			| func_name Sconst
  				{
  					/* generic type 'literal' syntax */
  					TypeName *t = makeTypeNameFromNameList($1);
! 					t->location = @1.begins;
! 					$$ = makeStringConstCast($2, @2.begins, @2.length, t);
  				}
  			| func_name '(' func_arg_list ')' Sconst
  				{
*************** AexprConst: Iconst
*** 11751,11768 ****
  									 parser_errposition(arg->location)));
  					}
  					t->typmods = $3;
! 					t->location = @1;
! 					$$ = makeStringConstCast($5, @5, t);
  				}
  			| ConstTypename Sconst
  				{
! 					$$ = makeStringConstCast($2, @2, $1);
  				}
  			| ConstInterval Sconst opt_interval
  				{
  					TypeName *t = $1;
  					t->typmods = $3;
! 					$$ = makeStringConstCast($2, @2, t);
  				}
  			| ConstInterval '(' Iconst ')' Sconst opt_interval
  				{
--- 11751,11768 ----
  									 parser_errposition(arg->location)));
  					}
  					t->typmods = $3;
! 					t->location = @1.begins;
! 					$$ = makeStringConstCast($5, @5.begins, @5.length, t);
  				}
  			| ConstTypename Sconst
  				{
! 					$$ = makeStringConstCast($2, @2.begins, @2.length, $1);
  				}
  			| ConstInterval Sconst opt_interval
  				{
  					TypeName *t = $1;
  					t->typmods = $3;
! 					$$ = makeStringConstCast($2, @2.begins, @2.length, t);
  				}
  			| ConstInterval '(' Iconst ')' Sconst opt_interval
  				{
*************** AexprConst: Iconst
*** 11773,11797 ****
  							ereport(ERROR,
  									(errcode(ERRCODE_SYNTAX_ERROR),
  									 errmsg("interval precision specified twice"),
! 									 parser_errposition(@1)));
! 						t->typmods = lappend($6, makeIntConst($3, @3));
  					}
  					else
! 						t->typmods = list_make2(makeIntConst(INTERVAL_FULL_RANGE, -1),
! 												makeIntConst($3, @3));
! 					$$ = makeStringConstCast($5, @5, t);
  				}
  			| TRUE_P
  				{
! 					$$ = makeBoolAConst(TRUE, @1);
  				}
  			| FALSE_P
  				{
! 					$$ = makeBoolAConst(FALSE, @1);
  				}
  			| NULL_P
  				{
! 					$$ = makeNullAConst(@1);
  				}
  		;
  
--- 11773,11797 ----
  							ereport(ERROR,
  									(errcode(ERRCODE_SYNTAX_ERROR),
  									 errmsg("interval precision specified twice"),
! 									 parser_errposition(@1.begins)));
! 						t->typmods = lappend($6, makeIntConst($3, @3.begins, @3.length));
  					}
  					else
! 						t->typmods = list_make2(makeIntConst(INTERVAL_FULL_RANGE, -1, -1),
! 												makeIntConst($3, @3.begins, @3.length));
! 					$$ = makeStringConstCast($5, @5.begins, @5.length, t);
  				}
  			| TRUE_P
  				{
! 					$$ = makeBoolAConst(TRUE, @1.begins, @1.length);
  				}
  			| FALSE_P
  				{
! 					$$ = makeBoolAConst(FALSE, @1.begins, @1.length);
  				}
  			| NULL_P
  				{
! 					$$ = makeNullAConst(@1.begins, @1.length);
  				}
  		;
  
*************** makeColumnRef(char *colname, List *indir
*** 12352,12451 ****
  }
  
  static Node *
! makeTypeCast(Node *arg, TypeName *typename, int location)
  {
  	TypeCast *n = makeNode(TypeCast);
  	n->arg = arg;
  	n->typeName = typename;
  	n->location = location;
  	return (Node *) n;
  }
  
  static Node *
! makeStringConst(char *str, int location)
  {
  	A_Const *n = makeNode(A_Const);
  
  	n->val.type = T_String;
  	n->val.val.str = str;
  	n->location = location;
  
  	return (Node *)n;
  }
  
  static Node *
! makeStringConstCast(char *str, int location, TypeName *typename)
  {
! 	Node *s = makeStringConst(str, location);
  
! 	return makeTypeCast(s, typename, -1);
  }
  
  static Node *
! makeIntConst(int val, int location)
  {
  	A_Const *n = makeNode(A_Const);
  
  	n->val.type = T_Integer;
  	n->val.val.ival = val;
  	n->location = location;
  
  	return (Node *)n;
  }
  
  static Node *
! makeFloatConst(char *str, int location)
  {
  	A_Const *n = makeNode(A_Const);
  
  	n->val.type = T_Float;
  	n->val.val.str = str;
  	n->location = location;
  
  	return (Node *)n;
  }
  
  static Node *
! makeBitStringConst(char *str, int location)
  {
  	A_Const *n = makeNode(A_Const);
  
  	n->val.type = T_BitString;
  	n->val.val.str = str;
  	n->location = location;
  
  	return (Node *)n;
  }
  
  static Node *
! makeNullAConst(int location)
  {
  	A_Const *n = makeNode(A_Const);
  
  	n->val.type = T_Null;
  	n->location = location;
  
  	return (Node *)n;
  }
  
  static Node *
! makeAConst(Value *v, int location)
  {
  	Node *n;
  
  	switch (v->type)
  	{
  		case T_Float:
! 			n = makeFloatConst(v->val.str, location);
  			break;
  
  		case T_Integer:
! 			n = makeIntConst(v->val.ival, location);
  			break;
  
  		case T_String:
  		default:
! 			n = makeStringConst(v->val.str, location);
  			break;
  	}
  
--- 12352,12457 ----
  }
  
  static Node *
! makeTypeCast(Node *arg, TypeName *typename, int location, int length)
  {
  	TypeCast *n = makeNode(TypeCast);
  	n->arg = arg;
  	n->typeName = typename;
  	n->location = location;
+ 	n->tok_len = length;
  	return (Node *) n;
  }
  
  static Node *
! makeStringConst(char *str, int location, int length)
  {
  	A_Const *n = makeNode(A_Const);
  
  	n->val.type = T_String;
  	n->val.val.str = str;
  	n->location = location;
+ 	n->tok_len = length;
  
  	return (Node *)n;
  }
  
  static Node *
! makeStringConstCast(char *str, int location, int length, TypeName *typename)
  {
! 	Node *s = makeStringConst(str, location, length);
  
! 	return makeTypeCast(s, typename, location, length);
  }
  
  static Node *
! makeIntConst(int val, int location, int length)
  {
  	A_Const *n = makeNode(A_Const);
  
  	n->val.type = T_Integer;
  	n->val.val.ival = val;
  	n->location = location;
+ 	n->tok_len = length;
  
  	return (Node *)n;
  }
  
  static Node *
! makeFloatConst(char *str, int location, int length)
  {
  	A_Const *n = makeNode(A_Const);
  
  	n->val.type = T_Float;
  	n->val.val.str = str;
  	n->location = location;
+ 	n->tok_len = length;
  
  	return (Node *)n;
  }
  
  static Node *
! makeBitStringConst(char *str, int location, int length)
  {
  	A_Const *n = makeNode(A_Const);
  
  	n->val.type = T_BitString;
  	n->val.val.str = str;
  	n->location = location;
+ 	n->tok_len = length;
  
  	return (Node *)n;
  }
  
  static Node *
! makeNullAConst(int location, int length)
  {
  	A_Const *n = makeNode(A_Const);
  
  	n->val.type = T_Null;
  	n->location = location;
+ 	n->tok_len = length;
  
  	return (Node *)n;
  }
  
  static Node *
! makeAConst(Value *v, int location, int length)
  {
  	Node *n;
  
  	switch (v->type)
  	{
  		case T_Float:
! 			n = makeFloatConst(v->val.str, location, length);
  			break;
  
  		case T_Integer:
! 			n = makeIntConst(v->val.ival, location, length);
  			break;
  
  		case T_String:
  		default:
! 			n = makeStringConst(v->val.str, location, length);
  			break;
  	}
  
*************** makeAConst(Value *v, int location)
*** 12456,12470 ****
   * Create an A_Const string node and put it inside a boolean cast.
   */
  static Node *
! makeBoolAConst(bool state, int location)
  {
  	A_Const *n = makeNode(A_Const);
  
  	n->val.type = T_String;
  	n->val.val.str = (state ? "t" : "f");
  	n->location = location;
  
! 	return makeTypeCast((Node *)n, SystemTypeName("bool"), -1);
  }
  
  /* makeOverlaps()
--- 12462,12477 ----
   * Create an A_Const string node and put it inside a boolean cast.
   */
  static Node *
! makeBoolAConst(bool state, int location, int length)
  {
  	A_Const *n = makeNode(A_Const);
  
  	n->val.type = T_String;
  	n->val.val.str = (state ? "t" : "f");
  	n->location = location;
+ 	n->tok_len = length;
  
! 	return makeTypeCast((Node *)n, SystemTypeName("bool"), -1, -1);
  }
  
  /* makeOverlaps()
*************** SystemTypeName(char *name)
*** 12696,12702 ****
   * until we know what the desired type is.
   */
  static Node *
! doNegate(Node *n, int location)
  {
  	if (IsA(n, A_Const))
  	{
--- 12703,12709 ----
   * until we know what the desired type is.
   */
  static Node *
! doNegate(Node *n, int location, int length)
  {
  	if (IsA(n, A_Const))
  	{
*************** doNegate(Node *n, int location)
*** 12704,12718 ****
--- 12711,12729 ----
  
  		/* report the constant's location as that of the '-' sign */
  		con->location = location;
+ 		/* TODO: A more elegant job of calculating length than this */
+ 		/*con->tok_len = length; */
  
  		if (con->val.type == T_Integer)
  		{
  			con->val.val.ival = -con->val.val.ival;
+ 			con->tok_len = (con->val.val.ival==0? 2: ((int) log10(fabs(con->val.val.ival)) + 2 ) );
  			return n;
  		}
  		if (con->val.type == T_Float)
  		{
  			doNegateFloat(&con->val);
+ 			con->tok_len = strlen(con->val.val.str);
  			return n;
  		}
  	}
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index e8177bc..6aaa4d2 100644
*** a/src/backend/parser/parse_clause.c
--- b/src/backend/parser/parse_clause.c
*************** buildMergedJoinVar(ParseState *pstate, J
*** 1073,1079 ****
  	if (l_colvar->vartype != outcoltype)
  		l_node = coerce_type(pstate, (Node *) l_colvar, l_colvar->vartype,
  							 outcoltype, outcoltypmod,
! 							 COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1);
  	else if (l_colvar->vartypmod != outcoltypmod)
  		l_node = (Node *) makeRelabelType((Expr *) l_colvar,
  										  outcoltype, outcoltypmod,
--- 1073,1079 ----
  	if (l_colvar->vartype != outcoltype)
  		l_node = coerce_type(pstate, (Node *) l_colvar, l_colvar->vartype,
  							 outcoltype, outcoltypmod,
! 							 COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1, -1);
  	else if (l_colvar->vartypmod != outcoltypmod)
  		l_node = (Node *) makeRelabelType((Expr *) l_colvar,
  										  outcoltype, outcoltypmod,
*************** buildMergedJoinVar(ParseState *pstate, J
*** 1085,1091 ****
  	if (r_colvar->vartype != outcoltype)
  		r_node = coerce_type(pstate, (Node *) r_colvar, r_colvar->vartype,
  							 outcoltype, outcoltypmod,
! 							 COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1);
  	else if (r_colvar->vartypmod != outcoltypmod)
  		r_node = (Node *) makeRelabelType((Expr *) r_colvar,
  										  outcoltype, outcoltypmod,
--- 1085,1091 ----
  	if (r_colvar->vartype != outcoltype)
  		r_node = coerce_type(pstate, (Node *) r_colvar, r_colvar->vartype,
  							 outcoltype, outcoltypmod,
! 							 COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1, -1);
  	else if (r_colvar->vartypmod != outcoltypmod)
  		r_node = (Node *) makeRelabelType((Expr *) r_colvar,
  										  outcoltype, outcoltypmod,
*************** addTargetToSortList(ParseState *pstate,
*** 1965,1971 ****
  										 restype, TEXTOID, -1,
  										 COERCION_IMPLICIT,
  										 COERCE_IMPLICIT_CAST,
! 										 -1);
  		restype = TEXTOID;
  	}
  
--- 1965,1971 ----
  										 restype, TEXTOID, -1,
  										 COERCION_IMPLICIT,
  										 COERCE_IMPLICIT_CAST,
! 										 -1, -1);
  		restype = TEXTOID;
  	}
  
*************** addTargetToGroupList(ParseState *pstate,
*** 2108,2114 ****
  										 restype, TEXTOID, -1,
  										 COERCION_IMPLICIT,
  										 COERCE_IMPLICIT_CAST,
! 										 -1);
  		restype = TEXTOID;
  	}
  
--- 2108,2114 ----
  										 restype, TEXTOID, -1,
  										 COERCION_IMPLICIT,
  										 COERCE_IMPLICIT_CAST,
! 										 -1, -1);
  		restype = TEXTOID;
  	}
  
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index c072325..004cea9 100644
*** a/src/backend/parser/parse_coerce.c
--- b/src/backend/parser/parse_coerce.c
*************** coerce_to_target_type(ParseState *pstate
*** 76,82 ****
  					  Oid targettype, int32 targettypmod,
  					  CoercionContext ccontext,
  					  CoercionForm cformat,
! 					  int location)
  {
  	Node	   *result;
  
--- 76,83 ----
  					  Oid targettype, int32 targettypmod,
  					  CoercionContext ccontext,
  					  CoercionForm cformat,
! 					  int location,
! 					  int tok_len)
  {
  	Node	   *result;
  
*************** coerce_to_target_type(ParseState *pstate
*** 85,91 ****
  
  	result = coerce_type(pstate, expr, exprtype,
  						 targettype, targettypmod,
! 						 ccontext, cformat, location);
  
  	/*
  	 * If the target is a fixed-length type, it may need a length coercion as
--- 86,92 ----
  
  	result = coerce_type(pstate, expr, exprtype,
  						 targettype, targettypmod,
! 						 ccontext, cformat, location, tok_len);
  
  	/*
  	 * If the target is a fixed-length type, it may need a length coercion as
*************** coerce_to_target_type(ParseState *pstate
*** 127,133 ****
  Node *
  coerce_type(ParseState *pstate, Node *node,
  			Oid inputTypeId, Oid targetTypeId, int32 targetTypeMod,
! 			CoercionContext ccontext, CoercionForm cformat, int location)
  {
  	Node	   *result;
  	CoercionPathType pathtype;
--- 128,134 ----
  Node *
  coerce_type(ParseState *pstate, Node *node,
  			Oid inputTypeId, Oid targetTypeId, int32 targetTypeMod,
! 			CoercionContext ccontext, CoercionForm cformat, int location, int tok_len)
  {
  	Node	   *result;
  	CoercionPathType pathtype;
*************** coerce_type(ParseState *pstate, Node *no
*** 256,266 ****
--- 257,276 ----
  		newcon->constisnull = con->constisnull;
  		/* Use the leftmost of the constant's and coercion's locations */
  		if (location < 0)
+ 		{
  			newcon->location = con->location;
+ 			newcon->tok_len = con->tok_len;
+ 		}
  		else if (con->location >= 0 && con->location < location)
+ 		{
  			newcon->location = con->location;
+ 			newcon->tok_len = con->tok_len;
+ 		}
  		else
+ 		{
  			newcon->location = location;
+ 			newcon->tok_len = tok_len;
+ 		}
  
  		/*
  		 * Set up to point at the constant's text if the input routine throws
*************** coerce_type(ParseState *pstate, Node *no
*** 326,332 ****
  		newcoll->arg = (Expr *)
  			coerce_type(pstate, (Node *) coll->arg,
  						inputTypeId, targetTypeId, targetTypeMod,
! 						ccontext, cformat, location);
  		newcoll->collOid = coll->collOid;
  		newcoll->location = coll->location;
  		return (Node *) newcoll;
--- 336,342 ----
  		newcoll->arg = (Expr *)
  			coerce_type(pstate, (Node *) coll->arg,
  						inputTypeId, targetTypeId, targetTypeMod,
! 						ccontext, cformat, location, tok_len);
  		newcoll->collOid = coll->collOid;
  		newcoll->location = coll->location;
  		return (Node *) newcoll;
*************** coerce_record_to_complex(ParseState *pst
*** 947,953 ****
  									  tupdesc->attrs[i]->atttypmod,
  									  ccontext,
  									  COERCE_IMPLICIT_CAST,
! 									  -1);
  		if (cexpr == NULL)
  			ereport(ERROR,
  					(errcode(ERRCODE_CANNOT_COERCE),
--- 957,963 ----
  									  tupdesc->attrs[i]->atttypmod,
  									  ccontext,
  									  COERCE_IMPLICIT_CAST,
! 									  -1, -1);
  		if (cexpr == NULL)
  			ereport(ERROR,
  					(errcode(ERRCODE_CANNOT_COERCE),
*************** coerce_to_boolean(ParseState *pstate, No
*** 1007,1013 ****
  										BOOLOID, -1,
  										COERCION_ASSIGNMENT,
  										COERCE_IMPLICIT_CAST,
! 										-1);
  		if (newnode == NULL)
  			ereport(ERROR,
  					(errcode(ERRCODE_DATATYPE_MISMATCH),
--- 1017,1023 ----
  										BOOLOID, -1,
  										COERCION_ASSIGNMENT,
  										COERCE_IMPLICIT_CAST,
! 										-1, -1);
  		if (newnode == NULL)
  			ereport(ERROR,
  					(errcode(ERRCODE_DATATYPE_MISMATCH),
*************** coerce_to_specific_type(ParseState *psta
*** 1054,1060 ****
  										targetTypeId, -1,
  										COERCION_ASSIGNMENT,
  										COERCE_IMPLICIT_CAST,
! 										-1);
  		if (newnode == NULL)
  			ereport(ERROR,
  					(errcode(ERRCODE_DATATYPE_MISMATCH),
--- 1064,1070 ----
  										targetTypeId, -1,
  										COERCION_ASSIGNMENT,
  										COERCE_IMPLICIT_CAST,
! 										-1, -1);
  		if (newnode == NULL)
  			ereport(ERROR,
  					(errcode(ERRCODE_DATATYPE_MISMATCH),
*************** coerce_to_common_type(ParseState *pstate
*** 1254,1260 ****
  		return node;			/* no work */
  	if (can_coerce_type(1, &inputTypeId, &targetTypeId, COERCION_IMPLICIT))
  		node = coerce_type(pstate, node, inputTypeId, targetTypeId, -1,
! 						   COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1);
  	else
  		ereport(ERROR,
  				(errcode(ERRCODE_CANNOT_COERCE),
--- 1264,1270 ----
  		return node;			/* no work */
  	if (can_coerce_type(1, &inputTypeId, &targetTypeId, COERCION_IMPLICIT))
  		node = coerce_type(pstate, node, inputTypeId, targetTypeId, -1,
! 						   COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1, -1);
  	else
  		ereport(ERROR,
  				(errcode(ERRCODE_CANNOT_COERCE),
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 75236c7..5849900 100644
*** a/src/backend/parser/parse_expr.c
--- b/src/backend/parser/parse_expr.c
*************** transformExpr(ParseState *pstate, Node *
*** 125,131 ****
  				A_Const    *con = (A_Const *) expr;
  				Value	   *val = &con->val;
  
! 				result = (Node *) make_const(pstate, val, con->location);
  				break;
  			}
  
--- 125,131 ----
  				A_Const    *con = (A_Const *) expr;
  				Value	   *val = &con->val;
  
! 				result = (Node *) make_const(pstate, val, con->location, con->tok_len);
  				break;
  			}
  
*************** transformCaseExpr(ParseState *pstate, Ca
*** 1347,1352 ****
--- 1347,1353 ----
  
  		n->val.type = T_Null;
  		n->location = -1;
+ 		n->tok_len = -1;
  		defresult = (Node *) n;
  	}
  	newc->defresult = (Expr *) transformExpr(pstate, defresult);
*************** transformArrayExpr(ParseState *pstate, A
*** 1663,1669 ****
  										 typmod,
  										 COERCION_EXPLICIT,
  										 COERCE_EXPLICIT_CAST,
! 										 -1);
  			if (newe == NULL)
  				ereport(ERROR,
  						(errcode(ERRCODE_CANNOT_COERCE),
--- 1664,1670 ----
  										 typmod,
  										 COERCION_EXPLICIT,
  										 COERCE_EXPLICIT_CAST,
! 										 -1, -1);
  			if (newe == NULL)
  				ereport(ERROR,
  						(errcode(ERRCODE_CANNOT_COERCE),
*************** transformXmlSerialize(ParseState *pstate
*** 1942,1948 ****
  								   TEXTOID, targetType, targetTypmod,
  								   COERCION_IMPLICIT,
  								   COERCE_IMPLICIT_CAST,
! 								   -1);
  	if (result == NULL)
  		ereport(ERROR,
  				(errcode(ERRCODE_CANNOT_COERCE),
--- 1943,1949 ----
  								   TEXTOID, targetType, targetTypmod,
  								   COERCION_IMPLICIT,
  								   COERCE_IMPLICIT_CAST,
! 								   -1, -1);
  	if (result == NULL)
  		ereport(ERROR,
  				(errcode(ERRCODE_CANNOT_COERCE),
*************** transformTypeCast(ParseState *pstate, Ty
*** 2092,2098 ****
  	Oid			inputType = exprType(expr);
  	Oid			targetType;
  	int32		targetTypmod;
! 	int			location;
  
  	typenameTypeIdAndMod(pstate, tc->typeName, &targetType, &targetTypmod);
  
--- 2093,2099 ----
  	Oid			inputType = exprType(expr);
  	Oid			targetType;
  	int32		targetTypmod;
! 	int			location, tok_len;
  
  	typenameTypeIdAndMod(pstate, tc->typeName, &targetType, &targetTypmod);
  
*************** transformTypeCast(ParseState *pstate, Ty
*** 2105,2110 ****
--- 2106,2112 ----
  	 * name (this can happen in TypeName 'string' syntax, for instance).
  	 */
  	location = tc->location;
+ 	tok_len = tc->tok_len;
  	if (location < 0)
  		location = tc->typeName->location;
  
*************** transformTypeCast(ParseState *pstate, Ty
*** 2112,2118 ****
  								   targetType, targetTypmod,
  								   COERCION_EXPLICIT,
  								   COERCE_EXPLICIT_CAST,
! 								   location);
  	if (result == NULL)
  		ereport(ERROR,
  				(errcode(ERRCODE_CANNOT_COERCE),
--- 2114,2120 ----
  								   targetType, targetTypmod,
  								   COERCION_EXPLICIT,
  								   COERCE_EXPLICIT_CAST,
! 								   location, tok_len);
  	if (result == NULL)
  		ereport(ERROR,
  				(errcode(ERRCODE_CANNOT_COERCE),
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index 01ed85b..ccebc9f 100644
*** a/src/backend/parser/parse_func.c
--- b/src/backend/parser/parse_func.c
*************** ParseFuncOrColumn(ParseState *pstate, Li
*** 222,228 ****
  		 */
  		return coerce_type(pstate, linitial(fargs),
  						   actual_arg_types[0], rettype, -1,
! 						   COERCION_EXPLICIT, COERCE_EXPLICIT_CALL, location);
  	}
  	else if (fdresult == FUNCDETAIL_NORMAL)
  	{
--- 222,228 ----
  		 */
  		return coerce_type(pstate, linitial(fargs),
  						   actual_arg_types[0], rettype, -1,
! 						   COERCION_EXPLICIT, COERCE_EXPLICIT_CALL, location, -1);
  	}
  	else if (fdresult == FUNCDETAIL_NORMAL)
  	{
*************** make_fn_arguments(ParseState *pstate,
*** 1356,1362 ****
  								   declared_arg_types[i], -1,
  								   COERCION_IMPLICIT,
  								   COERCE_IMPLICIT_CAST,
! 								   -1);
  				na->arg = (Expr *) node;
  			}
  			else
--- 1356,1362 ----
  								   declared_arg_types[i], -1,
  								   COERCION_IMPLICIT,
  								   COERCE_IMPLICIT_CAST,
! 								   -1, -1);
  				na->arg = (Expr *) node;
  			}
  			else
*************** make_fn_arguments(ParseState *pstate,
*** 1367,1373 ****
  								   declared_arg_types[i], -1,
  								   COERCION_IMPLICIT,
  								   COERCE_IMPLICIT_CAST,
! 								   -1);
  				lfirst(current_fargs) = node;
  			}
  		}
--- 1367,1373 ----
  								   declared_arg_types[i], -1,
  								   COERCION_IMPLICIT,
  								   COERCE_IMPLICIT_CAST,
! 								   -1, -1);
  				lfirst(current_fargs) = node;
  			}
  		}
diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c
index 7b5c040..2d0e610 100644
*** a/src/backend/parser/parse_node.c
--- b/src/backend/parser/parse_node.c
*************** transformArraySubscripts(ParseState *pst
*** 335,341 ****
  												INT4OID, -1,
  												COERCION_ASSIGNMENT,
  												COERCE_IMPLICIT_CAST,
! 												-1);
  				if (subexpr == NULL)
  					ereport(ERROR,
  							(errcode(ERRCODE_DATATYPE_MISMATCH),
--- 335,341 ----
  												INT4OID, -1,
  												COERCION_ASSIGNMENT,
  												COERCE_IMPLICIT_CAST,
! 												-1, -1);
  				if (subexpr == NULL)
  					ereport(ERROR,
  							(errcode(ERRCODE_DATATYPE_MISMATCH),
*************** transformArraySubscripts(ParseState *pst
*** 362,368 ****
  										INT4OID, -1,
  										COERCION_ASSIGNMENT,
  										COERCE_IMPLICIT_CAST,
! 										-1);
  		if (subexpr == NULL)
  			ereport(ERROR,
  					(errcode(ERRCODE_DATATYPE_MISMATCH),
--- 362,368 ----
  										INT4OID, -1,
  										COERCION_ASSIGNMENT,
  										COERCE_IMPLICIT_CAST,
! 										-1, -1);
  		if (subexpr == NULL)
  			ereport(ERROR,
  					(errcode(ERRCODE_DATATYPE_MISMATCH),
*************** transformArraySubscripts(ParseState *pst
*** 386,392 ****
  										typeneeded, arrayTypMod,
  										COERCION_ASSIGNMENT,
  										COERCE_IMPLICIT_CAST,
! 										-1);
  		if (newFrom == NULL)
  			ereport(ERROR,
  					(errcode(ERRCODE_DATATYPE_MISMATCH),
--- 386,392 ----
  										typeneeded, arrayTypMod,
  										COERCION_ASSIGNMENT,
  										COERCE_IMPLICIT_CAST,
! 										-1, -1);
  		if (newFrom == NULL)
  			ereport(ERROR,
  					(errcode(ERRCODE_DATATYPE_MISMATCH),
*************** transformArraySubscripts(ParseState *pst
*** 434,440 ****
   *	too many examples that fail if we try.
   */
  Const *
! make_const(ParseState *pstate, Value *value, int location)
  {
  	Const	   *con;
  	Datum		val;
--- 434,440 ----
   *	too many examples that fail if we try.
   */
  Const *
! make_const(ParseState *pstate, Value *value, int location, int tok_len)
  {
  	Const	   *con;
  	Datum		val;
*************** make_const(ParseState *pstate, Value *va
*** 533,538 ****
--- 533,539 ----
  							true,
  							false);
  			con->location = location;
+ 			con->tok_len = tok_len;
  			return con;
  
  		default:
*************** make_const(ParseState *pstate, Value *va
*** 548,553 ****
--- 549,555 ----
  					false,
  					typebyval);
  	con->location = location;
+ 	con->tok_len = tok_len;
  
  	return con;
  }
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index 2f2e87f..651f72a 100644
*** a/src/backend/parser/parse_target.c
--- b/src/backend/parser/parse_target.c
*************** transformAssignedExpr(ParseState *pstate
*** 478,484 ****
  								  attrtype, attrtypmod,
  								  COERCION_ASSIGNMENT,
  								  COERCE_IMPLICIT_CAST,
! 								  -1);
  		if (expr == NULL)
  			ereport(ERROR,
  					(errcode(ERRCODE_DATATYPE_MISMATCH),
--- 478,484 ----
  								  attrtype, attrtypmod,
  								  COERCION_ASSIGNMENT,
  								  COERCE_IMPLICIT_CAST,
! 								  -1, -1);
  		if (expr == NULL)
  			ereport(ERROR,
  					(errcode(ERRCODE_DATATYPE_MISMATCH),
*************** transformAssignmentIndirection(ParseStat
*** 722,728 ****
  								   targetTypeId, targetTypMod,
  								   COERCION_ASSIGNMENT,
  								   COERCE_IMPLICIT_CAST,
! 								   -1);
  	if (result == NULL)
  	{
  		if (targetIsArray)
--- 722,728 ----
  								   targetTypeId, targetTypMod,
  								   COERCION_ASSIGNMENT,
  								   COERCE_IMPLICIT_CAST,
! 								   -1, -1);
  	if (result == NULL)
  	{
  		if (targetIsArray)
*************** transformAssignmentSubscripts(ParseState
*** 822,828 ****
  									   targetTypeId, targetTypMod,
  									   COERCION_ASSIGNMENT,
  									   COERCE_IMPLICIT_CAST,
! 									   -1);
  		/* probably shouldn't fail, but check */
  		if (result == NULL)
  			ereport(ERROR,
--- 822,828 ----
  									   targetTypeId, targetTypMod,
  									   COERCION_ASSIGNMENT,
  									   COERCE_IMPLICIT_CAST,
! 									   -1, -1);
  		/* probably shouldn't fail, but check */
  		if (result == NULL)
  			ereport(ERROR,
diff --git a/src/backend/parser/scan.l b/src/backend/parser/scan.l
index 12db190..329a15b 100644
*** a/src/backend/parser/scan.l
--- b/src/backend/parser/scan.l
*************** bool			standard_conforming_strings = tru
*** 73,84 ****
   * this should be done in the first such rule, else yylloc will point
   * into the middle of the token.
   */
! #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, core_yyscan_t yyscanner);
--- 73,86 ----
   * this should be done in the first such rule, else yylloc will point
   * into the middle of the token.
   */
! #define SET_YYLLOC_BEGINS() yylloc->length = 0; yylloc->begins = yytext - yyextra->scanbuf;
! #define SET_YYLLOC_LEN()  yylloc->length += strlen(yytext);
! 
  
  /*
   * Advance yylloc by the given number of bytes.
   */
! #define ADVANCE_YYLLOC(delta)  ( yylloc->begins += (delta) )
  
  #define startlit()  ( yyextra->literallen = 0 )
  static void addlit(char *ytext, int yleng, core_yyscan_t yyscanner);
*************** static void addunicode(pg_wchar c, yysca
*** 94,100 ****
  
  #define yyerror(msg)  scanner_yyerror(msg, yyscanner)
  
! #define lexer_errposition()  scanner_errposition(*(yylloc), yyscanner)
  
  static void check_string_escape_warning(unsigned char ychar, core_yyscan_t yyscanner);
  static void check_escape_warning(core_yyscan_t yyscanner);
--- 96,102 ----
  
  #define yyerror(msg)  scanner_yyerror(msg, yyscanner)
  
! #define lexer_errposition()  scanner_errposition(yylloc->begins, yyscanner)
  
  static void check_string_escape_warning(unsigned char ychar, core_yyscan_t yyscanner);
  static void check_escape_warning(core_yyscan_t yyscanner);
*************** other			.
*** 377,393 ****
  
  {xcstart}		{
  					/* Set location in case of syntax error in comment */
! 					SET_YYLLOC();
  					yyextra->xcdepth = 0;
  					BEGIN(xc);
  					/* Put back any characters past slash-star; see above */
  					yyless(2);
  				}
  
  <xc>{xcstart}	{
  					(yyextra->xcdepth)++;
  					/* Put back any characters past slash-star; see above */
  					yyless(2);
  				}
  
  <xc>{xcstop}	{
--- 379,397 ----
  
  {xcstart}		{
  					/* Set location in case of syntax error in comment */
! 					SET_YYLLOC_BEGINS();
  					yyextra->xcdepth = 0;
  					BEGIN(xc);
  					/* Put back any characters past slash-star; see above */
  					yyless(2);
+ 					SET_YYLLOC_LEN();
  				}
  
  <xc>{xcstart}	{
  					(yyextra->xcdepth)++;
  					/* Put back any characters past slash-star; see above */
  					yyless(2);
+ 					SET_YYLLOC_LEN();
  				}
  
  <xc>{xcstop}	{
*************** other			.
*** 395,400 ****
--- 399,405 ----
  						BEGIN(INITIAL);
  					else
  						(yyextra->xcdepth)--;
+ 					SET_YYLLOC_LEN();
  				}
  
  <xc>{xcinside}	{
*************** other			.
*** 418,438 ****
  					 * In the meantime, place a leading "b" on the string
  					 * to mark it for the input routine as a binary string.
  					 */
! 					SET_YYLLOC();
  					BEGIN(xb);
  					startlit();
  					addlitchar('b', yyscanner);
  				}
  <xb>{quotestop}	|
  <xb>{quotefail} {
  					yyless(1);
  					BEGIN(INITIAL);
  					yylval->str = litbufdup(yyscanner);
  					return BCONST;
  				}
  <xh>{xhinside}	|
  <xb>{xbinside}	{
  					addlit(yytext, yyleng, yyscanner);
  				}
  <xh>{quotecontinue}	|
  <xb>{quotecontinue}	{
--- 423,446 ----
  					 * In the meantime, place a leading "b" on the string
  					 * to mark it for the input routine as a binary string.
  					 */
! 					SET_YYLLOC_BEGINS();
  					BEGIN(xb);
  					startlit();
  					addlitchar('b', yyscanner);
+ 					SET_YYLLOC_LEN();
  				}
  <xb>{quotestop}	|
  <xb>{quotefail} {
  					yyless(1);
  					BEGIN(INITIAL);
  					yylval->str = litbufdup(yyscanner);
+ 					SET_YYLLOC_LEN();
  					return BCONST;
  				}
  <xh>{xhinside}	|
  <xb>{xbinside}	{
  					addlit(yytext, yyleng, yyscanner);
+ 					SET_YYLLOC_LEN();
  				}
  <xh>{quotecontinue}	|
  <xb>{quotecontinue}	{
*************** other			.
*** 447,462 ****
  					 * In the meantime, place a leading "x" on the string
  					 * to mark it for the input routine as a hex string.
  					 */
! 					SET_YYLLOC();
  					BEGIN(xh);
  					startlit();
  					addlitchar('x', yyscanner);
  				}
  <xh>{quotestop}	|
  <xh>{quotefail} {
  					yyless(1);
  					BEGIN(INITIAL);
  					yylval->str = litbufdup(yyscanner);
  					return XCONST;
  				}
  <xh><<EOF>>		{ yyerror("unterminated hexadecimal string literal"); }
--- 455,472 ----
  					 * In the meantime, place a leading "x" on the string
  					 * to mark it for the input routine as a hex string.
  					 */
! 					SET_YYLLOC_BEGINS();
  					BEGIN(xh);
  					startlit();
  					addlitchar('x', yyscanner);
+ 					SET_YYLLOC_LEN();
  				}
  <xh>{quotestop}	|
  <xh>{quotefail} {
  					yyless(1);
  					BEGIN(INITIAL);
  					yylval->str = litbufdup(yyscanner);
+ 					SET_YYLLOC_LEN();
  					return XCONST;
  				}
  <xh><<EOF>>		{ yyerror("unterminated hexadecimal string literal"); }
*************** other			.
*** 468,474 ****
  					 */
  					const ScanKeyword *keyword;
  
! 					SET_YYLLOC();
  					yyless(1);				/* eat only 'n' this time */
  
  					keyword = ScanKeywordLookup("nchar",
--- 478,485 ----
  					 */
  					const ScanKeyword *keyword;
  
! 					SET_YYLLOC_BEGINS();
! 					SET_YYLLOC_LEN();
  					yyless(1);				/* eat only 'n' this time */
  
  					keyword = ScanKeywordLookup("nchar",
*************** other			.
*** 490,511 ****
  {xqstart}		{
  					yyextra->warn_on_first_escape = true;
  					yyextra->saw_non_ascii = false;
! 					SET_YYLLOC();
  					if (standard_conforming_strings)
  						BEGIN(xq);
  					else
  						BEGIN(xe);
  					startlit();
  				}
  {xestart}		{
  					yyextra->warn_on_first_escape = false;
  					yyextra->saw_non_ascii = false;
! 					SET_YYLLOC();
  					BEGIN(xe);
  					startlit();
  				}
  {xusstart}		{
! 					SET_YYLLOC();
  					if (!standard_conforming_strings)
  						ereport(ERROR,
  								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
--- 501,525 ----
  {xqstart}		{
  					yyextra->warn_on_first_escape = true;
  					yyextra->saw_non_ascii = false;
! 					SET_YYLLOC_BEGINS();
  					if (standard_conforming_strings)
  						BEGIN(xq);
  					else
  						BEGIN(xe);
  					startlit();
+ 					yylloc->length = 0;
+ 					SET_YYLLOC_LEN();
  				}
  {xestart}		{
  					yyextra->warn_on_first_escape = false;
  					yyextra->saw_non_ascii = false;
! 					SET_YYLLOC_BEGINS();
  					BEGIN(xe);
  					startlit();
+ 					SET_YYLLOC_LEN();
  				}
  {xusstart}		{
! 					SET_YYLLOC_BEGINS();
  					if (!standard_conforming_strings)
  						ereport(ERROR,
  								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
*************** other			.
*** 513,518 ****
--- 527,533 ----
  								 errdetail("String constants with Unicode escapes cannot be used when standard_conforming_strings is off."),
  								 lexer_errposition()));
  					BEGIN(xus);
+ 					SET_YYLLOC_LEN();
  					startlit();
  				}
  <xq,xe>{quotestop}	|
*************** other			.
*** 528,533 ****
--- 543,549 ----
  									   yyextra->literallen,
  									   false);
  					yylval->str = litbufdup(yyscanner);
+ 					SET_YYLLOC_LEN();
  					return SCONST;
  				}
  <xus>{xusstop1} {
*************** other			.
*** 535,555 ****
--- 551,576 ----
  					yyless(1);
  					BEGIN(INITIAL);
  					yylval->str = litbuf_udeescape('\\', yyscanner);
+ 					SET_YYLLOC_LEN();
  					return SCONST;
  				}
  <xus>{xusstop2} {
  					BEGIN(INITIAL);
  					yylval->str = litbuf_udeescape(yytext[yyleng-2], yyscanner);
+ 					SET_YYLLOC_LEN();
  					return SCONST;
  				}
  <xq,xe,xus>{xqdouble} {
  					addlitchar('\'', yyscanner);
+ 					SET_YYLLOC_LEN();
  				}
  <xq,xus>{xqinside}  {
  					addlit(yytext, yyleng, yyscanner);
+ 					SET_YYLLOC_LEN();
  				}
  <xe>{xeinside}  {
  					addlit(yytext, yyleng, yyscanner);
+ 					SET_YYLLOC_LEN();
  				}
  <xe>{xeunicode} {
  					pg_wchar c = strtoul(yytext+2, NULL, 16);
*************** other			.
*** 565,570 ****
--- 586,592 ----
  						yyerror("invalid Unicode surrogate pair");
  					else
  						addunicode(c, yyscanner);
+ 					SET_YYLLOC_LEN();
  				}
  <xeu>{xeunicode} {
  					pg_wchar c = strtoul(yytext+2, NULL, 16);
*************** other			.
*** 577,582 ****
--- 599,605 ----
  					addunicode(c, yyscanner);
  
  					BEGIN(xe);
+ 					SET_YYLLOC_LEN();
  				}
  <xeu>.			{ yyerror("invalid Unicode surrogate pair"); }
  <xeu>\n			{ yyerror("invalid Unicode surrogate pair"); }
*************** other			.
*** 603,608 ****
--- 626,632 ----
  					check_string_escape_warning(yytext[1], yyscanner);
  					addlitchar(unescape_single_char(yytext[1], yyscanner),
  							   yyscanner);
+ 					SET_YYLLOC_LEN();
  				}
  <xe>{xeoctesc}  {
  					unsigned char c = strtoul(yytext+1, NULL, 8);
*************** other			.
*** 611,616 ****
--- 635,641 ----
  					addlitchar(c, yyscanner);
  					if (c == '\0' || IS_HIGHBIT_SET(c))
  						yyextra->saw_non_ascii = true;
+ 					SET_YYLLOC_LEN();
  				}
  <xe>{xehexesc}  {
  					unsigned char c = strtoul(yytext+2, NULL, 16);
*************** other			.
*** 619,624 ****
--- 644,650 ----
  					addlitchar(c, yyscanner);
  					if (c == '\0' || IS_HIGHBIT_SET(c))
  						yyextra->saw_non_ascii = true;
+ 					SET_YYLLOC_LEN();
  				}
  <xq,xe,xus>{quotecontinue} {
  					/* ignore */
*************** other			.
*** 626,644 ****
  <xe>.			{
  					/* This is only needed for \ just before EOF */
  					addlitchar(yytext[0], yyscanner);
  				}
  <xq,xe,xus><<EOF>>		{ yyerror("unterminated quoted string"); }
  
  {dolqdelim}		{
! 					SET_YYLLOC();
  					yyextra->dolqstart = pstrdup(yytext);
  					BEGIN(xdolq);
  					startlit();
  				}
  {dolqfailed}	{
! 					SET_YYLLOC();
  					/* throw back all but the initial "$" */
  					yyless(1);
  					/* and treat it as {other} */
  					return yytext[0];
  				}
--- 652,674 ----
  <xe>.			{
  					/* This is only needed for \ just before EOF */
  					addlitchar(yytext[0], yyscanner);
+ 					SET_YYLLOC_LEN();
  				}
  <xq,xe,xus><<EOF>>		{ yyerror("unterminated quoted string"); }
  
  {dolqdelim}		{
! 					SET_YYLLOC_BEGINS();
  					yyextra->dolqstart = pstrdup(yytext);
  					BEGIN(xdolq);
  					startlit();
+ 					yylloc->length = 0;
+ 					SET_YYLLOC_LEN();
  				}
  {dolqfailed}	{
! 					SET_YYLLOC_BEGINS();
  					/* throw back all but the initial "$" */
  					yyless(1);
+ 					SET_YYLLOC_LEN();
  					/* and treat it as {other} */
  					return yytext[0];
  				}
*************** other			.
*** 649,654 ****
--- 679,685 ----
  						yyextra->dolqstart = NULL;
  						BEGIN(INITIAL);
  						yylval->str = litbufdup(yyscanner);
+ 						SET_YYLLOC_LEN();
  						return SCONST;
  					}
  					else
*************** other			.
*** 660,688 ****
  						 */
  						addlit(yytext, yyleng-1, yyscanner);
  						yyless(yyleng-1);
  					}
  				}
  <xdolq>{dolqinside} {
  					addlit(yytext, yyleng, yyscanner);
  				}
  <xdolq>{dolqfailed} {
  					addlit(yytext, yyleng, yyscanner);
  				}
  <xdolq>.		{
  					/* This is only needed for $ inside the quoted text */
  					addlitchar(yytext[0], yyscanner);
  				}
  <xdolq><<EOF>>	{ yyerror("unterminated dollar-quoted string"); }
  
  {xdstart}		{
! 					SET_YYLLOC();
  					BEGIN(xd);
  					startlit();
  				}
  {xuistart}		{
! 					SET_YYLLOC();
  					BEGIN(xui);
  					startlit();
  				}
  <xd>{xdstop}	{
  					char		   *ident;
--- 691,725 ----
  						 */
  						addlit(yytext, yyleng-1, yyscanner);
  						yyless(yyleng-1);
+ 						SET_YYLLOC_LEN();
  					}
  				}
  <xdolq>{dolqinside} {
  					addlit(yytext, yyleng, yyscanner);
+ 					SET_YYLLOC_LEN();
  				}
  <xdolq>{dolqfailed} {
  					addlit(yytext, yyleng, yyscanner);
+ 					SET_YYLLOC_LEN();
  				}
  <xdolq>.		{
  					/* This is only needed for $ inside the quoted text */
  					addlitchar(yytext[0], yyscanner);
+ 					SET_YYLLOC_LEN();
  				}
  <xdolq><<EOF>>	{ yyerror("unterminated dollar-quoted string"); }
  
  {xdstart}		{
! 					SET_YYLLOC_BEGINS();
  					BEGIN(xd);
  					startlit();
+ 					SET_YYLLOC_LEN();
  				}
  {xuistart}		{
! 					SET_YYLLOC_BEGINS();
  					BEGIN(xui);
  					startlit();
+ 					SET_YYLLOC_LEN();
  				}
  <xd>{xdstop}	{
  					char		   *ident;
*************** other			.
*** 694,699 ****
--- 731,737 ----
  					if (yyextra->literallen >= NAMEDATALEN)
  						truncate_identifier(ident, yyextra->literallen, true);
  					yylval->str = ident;
+ 					SET_YYLLOC_LEN();
  					return IDENT;
  				}
  <xui>{xuistop1}	{
*************** other			.
*** 708,713 ****
--- 746,752 ----
  					yylval->str = ident;
  					/* throw back all but the quote */
  					yyless(1);
+ 					SET_YYLLOC_LEN();
  					return IDENT;
  				}
  <xui>{xuistop2}	{
*************** other			.
*** 720,764 ****
  					if (yyextra->literallen >= NAMEDATALEN)
  						truncate_identifier(ident, yyextra->literallen, true);
  					yylval->str = ident;
  					return IDENT;
  				}
  <xd,xui>{xddouble}	{
  					addlitchar('"', yyscanner);
  				}
  <xd,xui>{xdinside}	{
  					addlit(yytext, yyleng, yyscanner);
  				}
  <xd,xui><<EOF>>		{ yyerror("unterminated quoted identifier"); }
  
  {xufailed}	{
  					char		   *ident;
  
! 					SET_YYLLOC();
  					/* throw back all but the initial u/U */
  					yyless(1);
  					/* and treat it as {identifier} */
  					ident = downcase_truncate_identifier(yytext, yyleng, true);
  					yylval->str = ident;
  					return IDENT;
  				}
  
  {typecast}		{
! 					SET_YYLLOC();
  					return TYPECAST;
  				}
  
  {dot_dot}		{
! 					SET_YYLLOC();
  					return DOT_DOT;
  				}
  
  {colon_equals}	{
! 					SET_YYLLOC();
  					return COLON_EQUALS;
  				}
  
  {self}			{
! 					SET_YYLLOC();
  					return yytext[0];
  				}
  
--- 759,811 ----
  					if (yyextra->literallen >= NAMEDATALEN)
  						truncate_identifier(ident, yyextra->literallen, true);
  					yylval->str = ident;
+ 					SET_YYLLOC_LEN();
  					return IDENT;
  				}
  <xd,xui>{xddouble}	{
  					addlitchar('"', yyscanner);
+ 					SET_YYLLOC_LEN();
  				}
  <xd,xui>{xdinside}	{
  					addlit(yytext, yyleng, yyscanner);
+ 					SET_YYLLOC_LEN();
  				}
  <xd,xui><<EOF>>		{ yyerror("unterminated quoted identifier"); }
  
  {xufailed}	{
  					char		   *ident;
  
! 					SET_YYLLOC_BEGINS();
  					/* throw back all but the initial u/U */
  					yyless(1);
  					/* and treat it as {identifier} */
  					ident = downcase_truncate_identifier(yytext, yyleng, true);
  					yylval->str = ident;
+ 					SET_YYLLOC_LEN();
  					return IDENT;
  				}
  
  {typecast}		{
! 					SET_YYLLOC_BEGINS();
! 					SET_YYLLOC_LEN();
  					return TYPECAST;
  				}
  
  {dot_dot}		{
! 					SET_YYLLOC_BEGINS();
! 					SET_YYLLOC_LEN();
  					return DOT_DOT;
  				}
  
  {colon_equals}	{
! 					SET_YYLLOC_BEGINS();
! 					SET_YYLLOC_LEN();
  					return COLON_EQUALS;
  				}
  
  {self}			{
! 					SET_YYLLOC_BEGINS();
! 					SET_YYLLOC_LEN();
  					return yytext[0];
  				}
  
*************** other			.
*** 808,814 ****
  						nchars--; /* else remove the +/-, and check again */
  					}
  
! 					SET_YYLLOC();
  
  					if (nchars < yyleng)
  					{
--- 855,861 ----
  						nchars--; /* else remove the +/-, and check again */
  					}
  
! 					SET_YYLLOC_BEGINS();
  
  					if (nchars < yyleng)
  					{
*************** other			.
*** 839,871 ****
  						yylval->str = pstrdup("<>");
  					else
  						yylval->str = pstrdup(yytext);
  					return Op;
  				}
  
  {param}			{
! 					SET_YYLLOC();
  					yylval->ival = atol(yytext + 1);
  					return PARAM;
  				}
  
  {integer}		{
! 					SET_YYLLOC();
  					return process_integer_literal(yytext, yylval);
  				}
  {decimal}		{
! 					SET_YYLLOC();
  					yylval->str = pstrdup(yytext);
  					return FCONST;
  				}
  {decimalfail}	{
  					/* throw back the .., and treat as integer */
  					yyless(yyleng-2);
! 					SET_YYLLOC();
  					return process_integer_literal(yytext, yylval);
  				}
  {real}			{
! 					SET_YYLLOC();
  					yylval->str = pstrdup(yytext);
  					return FCONST;
  				}
  {realfail1}		{
--- 886,924 ----
  						yylval->str = pstrdup("<>");
  					else
  						yylval->str = pstrdup(yytext);
+ 					SET_YYLLOC_LEN();
  					return Op;
  				}
  
  {param}			{
! 					SET_YYLLOC_BEGINS();
  					yylval->ival = atol(yytext + 1);
+ 					SET_YYLLOC_LEN();
  					return PARAM;
  				}
  
  {integer}		{
! 					SET_YYLLOC_BEGINS();
! 					SET_YYLLOC_LEN();
  					return process_integer_literal(yytext, yylval);
  				}
  {decimal}		{
! 					SET_YYLLOC_BEGINS();
  					yylval->str = pstrdup(yytext);
+ 					SET_YYLLOC_LEN();
  					return FCONST;
  				}
  {decimalfail}	{
  					/* throw back the .., and treat as integer */
  					yyless(yyleng-2);
! 					SET_YYLLOC_BEGINS();
! 					SET_YYLLOC_LEN();
  					return process_integer_literal(yytext, yylval);
  				}
  {real}			{
! 					SET_YYLLOC_BEGINS();
  					yylval->str = pstrdup(yytext);
+ 					SET_YYLLOC_LEN();
  					return FCONST;
  				}
  {realfail1}		{
*************** other			.
*** 876,890 ****
  					 * syntax error anyway, we don't bother to distinguish.
  					 */
  					yyless(yyleng-1);
! 					SET_YYLLOC();
  					yylval->str = pstrdup(yytext);
  					return FCONST;
  				}
  {realfail2}		{
  					/* throw back the [Ee][+-], and proceed as above */
  					yyless(yyleng-2);
! 					SET_YYLLOC();
  					yylval->str = pstrdup(yytext);
  					return FCONST;
  				}
  
--- 929,945 ----
  					 * syntax error anyway, we don't bother to distinguish.
  					 */
  					yyless(yyleng-1);
! 					SET_YYLLOC_BEGINS();
  					yylval->str = pstrdup(yytext);
+ 					SET_YYLLOC_LEN();
  					return FCONST;
  				}
  {realfail2}		{
  					/* throw back the [Ee][+-], and proceed as above */
  					yyless(yyleng-2);
! 					SET_YYLLOC_BEGINS();
  					yylval->str = pstrdup(yytext);
+ 					SET_YYLLOC_LEN();
  					return FCONST;
  				}
  
*************** other			.
*** 893,904 ****
  					const ScanKeyword *keyword;
  					char		   *ident;
  
! 					SET_YYLLOC();
  
  					/* Is it a keyword? */
  					keyword = ScanKeywordLookup(yytext,
  												yyextra->keywords,
  												yyextra->num_keywords);
  					if (keyword != NULL)
  					{
  						yylval->keyword = keyword->name;
--- 948,961 ----
  					const ScanKeyword *keyword;
  					char		   *ident;
  
! 					SET_YYLLOC_BEGINS();
  
+ 					yylloc->length = 0;
  					/* Is it a keyword? */
  					keyword = ScanKeywordLookup(yytext,
  												yyextra->keywords,
  												yyextra->num_keywords);
+ 					SET_YYLLOC_LEN();
  					if (keyword != NULL)
  					{
  						yylval->keyword = keyword->name;
*************** other			.
*** 915,926 ****
  				}
  
  {other}			{
! 					SET_YYLLOC();
  					return yytext[0];
  				}
  
  <<EOF>>			{
! 					SET_YYLLOC();
  					yyterminate();
  				}
  
--- 972,985 ----
  				}
  
  {other}			{
! 					SET_YYLLOC_BEGINS();
! 					SET_YYLLOC_LEN();
  					return yytext[0];
  				}
  
  <<EOF>>			{
! 					SET_YYLLOC_BEGINS();
! 					SET_YYLLOC_LEN();
  					yyterminate();
  				}
  
*************** scanner_errposition(int location, core_y
*** 982,988 ****
  void
  scanner_yyerror(const char *message, core_yyscan_t yyscanner)
  {
! 	const char *loc = yyextra->scanbuf + *yylloc;
  
  	if (*loc == YY_END_OF_BUFFER_CHAR)
  	{
--- 1041,1047 ----
  void
  scanner_yyerror(const char *message, core_yyscan_t yyscanner)
  {
! 	const char *loc = yyextra->scanbuf + yylloc->begins;
  
  	if (*loc == YY_END_OF_BUFFER_CHAR)
  	{
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index a6f4141..5763991 100644
*** a/src/backend/rewrite/rewriteHandler.c
--- b/src/backend/rewrite/rewriteHandler.c
*************** build_column_default(Relation rel, int a
*** 1023,1029 ****
  								 atttype, atttypmod,
  								 COERCION_ASSIGNMENT,
  								 COERCE_IMPLICIT_CAST,
! 								 -1);
  	if (expr == NULL)
  		ereport(ERROR,
  				(errcode(ERRCODE_DATATYPE_MISMATCH),
--- 1023,1029 ----
  								 atttype, atttypmod,
  								 COERCION_ASSIGNMENT,
  								 COERCE_IMPLICIT_CAST,
! 								 -1, -1);
  	if (expr == NULL)
  		ereport(ERROR,
  				(errcode(ERRCODE_DATATYPE_MISMATCH),
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 9e277c5..2de221e 100644
*** a/src/include/nodes/parsenodes.h
--- b/src/include/nodes/parsenodes.h
*************** typedef struct A_Const
*** 252,257 ****
--- 252,258 ----
  	NodeTag		type;
  	Value		val;			/* value (includes type info, see value.h) */
  	int			location;		/* token location, or -1 if unknown */
+ 	int			tok_len;		/* token length (in bytes) */
  } A_Const;
  
  /*
*************** typedef struct TypeCast
*** 263,268 ****
--- 264,270 ----
  	Node	   *arg;			/* the expression being casted */
  	TypeName   *typeName;		/* the target type */
  	int			location;		/* token location, or -1 if unknown */
+ 	int			tok_len;		/* token length (in bytes) */
  } TypeCast;
  
  /*
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index 28a2b12..c164a55 100644
*** a/src/include/nodes/primnodes.h
--- b/src/include/nodes/primnodes.h
*************** typedef struct Const
*** 171,176 ****
--- 171,177 ----
  								 * in the Datum. If false, then the Datum
  								 * contains a pointer to the information. */
  	int			location;		/* token location, or -1 if unknown */
+ 	int			tok_len;		/* token length (in bytes) */
  } Const;
  
  /* ----------------
diff --git a/src/include/parser/parse_coerce.h b/src/include/parser/parse_coerce.h
index ceaff2f..85f3fdd 100644
*** a/src/include/parser/parse_coerce.h
--- b/src/include/parser/parse_coerce.h
*************** extern Node *coerce_to_target_type(Parse
*** 40,51 ****
  					  Oid targettype, int32 targettypmod,
  					  CoercionContext ccontext,
  					  CoercionForm cformat,
! 					  int location);
  extern bool can_coerce_type(int nargs, Oid *input_typeids, Oid *target_typeids,
  				CoercionContext ccontext);
  extern Node *coerce_type(ParseState *pstate, Node *node,
  			Oid inputTypeId, Oid targetTypeId, int32 targetTypeMod,
! 			CoercionContext ccontext, CoercionForm cformat, int location);
  extern Node *coerce_to_domain(Node *arg, Oid baseTypeId, int32 baseTypeMod,
  				 Oid typeId,
  				 CoercionForm cformat, int location,
--- 40,52 ----
  					  Oid targettype, int32 targettypmod,
  					  CoercionContext ccontext,
  					  CoercionForm cformat,
! 					  int location,
! 					  int tok_len);
  extern bool can_coerce_type(int nargs, Oid *input_typeids, Oid *target_typeids,
  				CoercionContext ccontext);
  extern Node *coerce_type(ParseState *pstate, Node *node,
  			Oid inputTypeId, Oid targetTypeId, int32 targetTypeMod,
! 			CoercionContext ccontext, CoercionForm cformat, int location, int tok_len);
  extern Node *coerce_to_domain(Node *arg, Oid baseTypeId, int32 baseTypeMod,
  				 Oid typeId,
  				 CoercionForm cformat, int location,
diff --git a/src/include/parser/parse_node.h b/src/include/parser/parse_node.h
index 0ca7914..fde2a93 100644
*** a/src/include/parser/parse_node.h
--- b/src/include/parser/parse_node.h
*************** extern ArrayRef *transformArraySubscript
*** 148,153 ****
  						 int32 arrayTypMod,
  						 List *indirection,
  						 Node *assignFrom);
! extern Const *make_const(ParseState *pstate, Value *value, int location);
  
  #endif   /* PARSE_NODE_H */
--- 148,153 ----
  						 int32 arrayTypMod,
  						 List *indirection,
  						 Node *assignFrom);
! extern Const *make_const(ParseState *pstate, Value *value, int location, int tok_len);
  
  #endif   /* PARSE_NODE_H */
diff --git a/src/include/parser/scanner.h b/src/include/parser/scanner.h
index 2a88e97..e12ccf4 100644
*** a/src/include/parser/scanner.h
--- b/src/include/parser/scanner.h
*************** typedef union core_YYSTYPE
*** 36,47 ****
  /*
   * We track token locations in terms of byte offsets from the start of the
   * source string, not the column number/line number representation that
!  * bison uses by default.  Also, to minimize overhead we track only one
!  * location (usually the first token location) for each construct, not
!  * the beginning and ending locations as bison does by default.  It's
!  * therefore sufficient to make YYLTYPE an int.
   */
! #define YYLTYPE  int
  
  /*
   * Another important component of the scanner's API is the token code numbers.
--- 36,51 ----
  /*
   * We track token locations in terms of byte offsets from the start of the
   * source string, not the column number/line number representation that
!  * bison uses by default. We track the beginning of the token, as well
!  * as its total length.
   */
! typedef struct my_yyltype
! {
! 	int begins;
! 	int length;
! } my_yyltype;
! 
! #define YYLTYPE my_yyltype
  
  /*
   * Another important component of the scanner's API is the token code numbers.
diff --git a/src/pl/plpgsql/src/gram.y b/src/pl/plpgsql/src/gram.y
index 8c4c2f7..ce932c4 100644
*** a/src/pl/plpgsql/src/gram.y
--- b/src/pl/plpgsql/src/gram.y
*************** pl_block		: decl_sect K_BEGIN proc_sect
*** 367,380 ****
  						new = palloc0(sizeof(PLpgSQL_stmt_block));
  
  						new->cmd_type	= PLPGSQL_STMT_BLOCK;
! 						new->lineno		= plpgsql_location_to_lineno(@2);
  						new->label		= $1.label;
  						new->n_initvars = $1.n_initvars;
  						new->initvarnos = $1.initvarnos;
  						new->body		= $3;
  						new->exceptions	= $4;
  
! 						check_labels($1.label, $6, @6);
  						plpgsql_ns_pop();
  
  						$$ = (PLpgSQL_stmt *)new;
--- 367,380 ----
  						new = palloc0(sizeof(PLpgSQL_stmt_block));
  
  						new->cmd_type	= PLPGSQL_STMT_BLOCK;
! 						new->lineno		= plpgsql_location_to_lineno(@2.begins);
  						new->label		= $1.label;
  						new->n_initvars = $1.n_initvars;
  						new->initvarnos = $1.initvarnos;
  						new->body		= $3;
  						new->exceptions	= $4;
  
! 						check_labels($1.label, $6, @6.begins);
  						plpgsql_ns_pop();
  
  						$$ = (PLpgSQL_stmt *)new;
*************** decl_stmt		: decl_statement
*** 436,442 ****
  						ereport(ERROR,
  								(errcode(ERRCODE_SYNTAX_ERROR),
  								 errmsg("block label must be placed before DECLARE, not after"),
! 								 parser_errposition(@1)));
  					}
  				;
  
--- 436,442 ----
  						ereport(ERROR,
  								(errcode(ERRCODE_SYNTAX_ERROR),
  								 errmsg("block label must be placed before DECLARE, not after"),
! 								 parser_errposition(@1.begins)));
  					}
  				;
  
*************** decl_statement	: decl_varname decl_const
*** 457,463 ****
  										(errcode(ERRCODE_DATATYPE_MISMATCH),
  										 errmsg("collations are not supported by type %s",
  												format_type_be($3->typoid)),
! 										 parser_errposition(@4)));
  							$3->collation = $4;
  						}
  
--- 457,463 ----
  										(errcode(ERRCODE_DATATYPE_MISMATCH),
  										 errmsg("collations are not supported by type %s",
  												format_type_be($3->typoid)),
! 										 parser_errposition(@4.begins)));
  							$3->collation = $4;
  						}
  
*************** decl_statement	: decl_varname decl_const
*** 471,477 ****
  								ereport(ERROR,
  										(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
  										 errmsg("row or record variable cannot be CONSTANT"),
! 										 parser_errposition(@2)));
  						}
  						if ($5)
  						{
--- 471,477 ----
  								ereport(ERROR,
  										(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
  										 errmsg("row or record variable cannot be CONSTANT"),
! 										 parser_errposition(@2.begins)));
  						}
  						if ($5)
  						{
*************** decl_statement	: decl_varname decl_const
*** 481,487 ****
  								ereport(ERROR,
  										(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
  										 errmsg("row or record variable cannot be NOT NULL"),
! 										 parser_errposition(@4)));
  
  						}
  						if ($6 != NULL)
--- 481,487 ----
  								ereport(ERROR,
  										(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
  										 errmsg("row or record variable cannot be NOT NULL"),
! 										 parser_errposition(@4.begins)));
  
  						}
  						if ($6 != NULL)
*************** decl_statement	: decl_varname decl_const
*** 492,498 ****
  								ereport(ERROR,
  										(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
  										 errmsg("default value for row or record variable is not supported"),
! 										 parser_errposition(@5)));
  						}
  					}
  				| decl_varname K_ALIAS K_FOR decl_aliasitem ';'
--- 492,498 ----
  								ereport(ERROR,
  										(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
  										 errmsg("default value for row or record variable is not supported"),
! 										 parser_errposition(@5.begins)));
  						}
  					}
  				| decl_varname K_ALIAS K_FOR decl_aliasitem ';'
*************** decl_cursor_args :
*** 584,590 ****
  
  						new = palloc0(sizeof(PLpgSQL_row));
  						new->dtype = PLPGSQL_DTYPE_ROW;
! 						new->lineno = plpgsql_location_to_lineno(@1);
  						new->rowtupdesc = NULL;
  						new->nfields = list_length($2);
  						new->fieldnames = palloc(new->nfields * sizeof(char *));
--- 584,590 ----
  
  						new = palloc0(sizeof(PLpgSQL_row));
  						new->dtype = PLPGSQL_DTYPE_ROW;
! 						new->lineno = plpgsql_location_to_lineno(@1.begins);
  						new->rowtupdesc = NULL;
  						new->nfields = list_length($2);
  						new->fieldnames = palloc(new->nfields * sizeof(char *));
*************** decl_aliasitem	: T_WORD
*** 638,644 ****
  									(errcode(ERRCODE_UNDEFINED_OBJECT),
  									 errmsg("variable \"%s\" does not exist",
  											$1.ident),
! 									 parser_errposition(@1)));
  						$$ = nsi;
  					}
  				| T_CWORD
--- 638,644 ----
  									(errcode(ERRCODE_UNDEFINED_OBJECT),
  									 errmsg("variable \"%s\" does not exist",
  											$1.ident),
! 									 parser_errposition(@1.begins)));
  						$$ = nsi;
  					}
  				| T_CWORD
*************** decl_aliasitem	: T_WORD
*** 664,670 ****
  									(errcode(ERRCODE_UNDEFINED_OBJECT),
  									 errmsg("variable \"%s\" does not exist",
  											NameListToString($1.idents)),
! 									 parser_errposition(@1)));
  						$$ = nsi;
  					}
  				;
--- 664,670 ----
  									(errcode(ERRCODE_UNDEFINED_OBJECT),
  									 errmsg("variable \"%s\" does not exist",
  											NameListToString($1.idents)),
! 									 parser_errposition(@1.begins)));
  						$$ = nsi;
  					}
  				;
*************** decl_aliasitem	: T_WORD
*** 672,678 ****
  decl_varname	: T_WORD
  					{
  						$$.name = $1.ident;
! 						$$.lineno = plpgsql_location_to_lineno(@1);
  						/*
  						 * Check to make sure name isn't already declared
  						 * in the current block.
--- 672,678 ----
  decl_varname	: T_WORD
  					{
  						$$.name = $1.ident;
! 						$$.lineno = plpgsql_location_to_lineno(@1.begins);
  						/*
  						 * Check to make sure name isn't already declared
  						 * in the current block.
*************** decl_varname	: T_WORD
*** 685,691 ****
  				| unreserved_keyword
  					{
  						$$.name = pstrdup($1);
! 						$$.lineno = plpgsql_location_to_lineno(@1);
  						/*
  						 * Check to make sure name isn't already declared
  						 * in the current block.
--- 685,691 ----
  				| unreserved_keyword
  					{
  						$$.name = pstrdup($1);
! 						$$.lineno = plpgsql_location_to_lineno(@1.begins);
  						/*
  						 * Check to make sure name isn't already declared
  						 * in the current block.
*************** stmt_perform	: K_PERFORM expr_until_semi
*** 819,825 ****
  
  						new = palloc0(sizeof(PLpgSQL_stmt_perform));
  						new->cmd_type = PLPGSQL_STMT_PERFORM;
! 						new->lineno   = plpgsql_location_to_lineno(@1);
  						new->expr  = $2;
  
  						$$ = (PLpgSQL_stmt *)new;
--- 819,825 ----
  
  						new = palloc0(sizeof(PLpgSQL_stmt_perform));
  						new->cmd_type = PLPGSQL_STMT_PERFORM;
! 						new->lineno   = plpgsql_location_to_lineno(@1.begins);
  						new->expr  = $2;
  
  						$$ = (PLpgSQL_stmt *)new;
*************** stmt_assign		: assign_var assign_operato
*** 832,838 ****
  
  						new = palloc0(sizeof(PLpgSQL_stmt_assign));
  						new->cmd_type = PLPGSQL_STMT_ASSIGN;
! 						new->lineno   = plpgsql_location_to_lineno(@1);
  						new->varno = $1;
  						new->expr  = $3;
  
--- 832,838 ----
  
  						new = palloc0(sizeof(PLpgSQL_stmt_assign));
  						new->cmd_type = PLPGSQL_STMT_ASSIGN;
! 						new->lineno   = plpgsql_location_to_lineno(@1.begins);
  						new->varno = $1;
  						new->expr  = $3;
  
*************** stmt_getdiag	: K_GET getdiag_area_opt K_
*** 847,853 ****
  
  						new = palloc0(sizeof(PLpgSQL_stmt_getdiag));
  						new->cmd_type = PLPGSQL_STMT_GETDIAG;
! 						new->lineno   = plpgsql_location_to_lineno(@1);
  						new->is_stacked = $2;
  						new->diag_items = $4;
  
--- 847,853 ----
  
  						new = palloc0(sizeof(PLpgSQL_stmt_getdiag));
  						new->cmd_type = PLPGSQL_STMT_GETDIAG;
! 						new->lineno   = plpgsql_location_to_lineno(@1.begins);
  						new->is_stacked = $2;
  						new->diag_items = $4;
  
*************** stmt_getdiag	: K_GET getdiag_area_opt K_
*** 868,874 ****
  												(errcode(ERRCODE_SYNTAX_ERROR),
  												 errmsg("diagnostics item %s is not allowed in GET STACKED DIAGNOSTICS",
  														plpgsql_getdiag_kindname(ditem->kind)),
! 												 parser_errposition(@1)));
  									break;
  								/* these fields are disallowed in current case */
  								case PLPGSQL_GETDIAG_ERROR_CONTEXT:
--- 868,874 ----
  												(errcode(ERRCODE_SYNTAX_ERROR),
  												 errmsg("diagnostics item %s is not allowed in GET STACKED DIAGNOSTICS",
  														plpgsql_getdiag_kindname(ditem->kind)),
! 												 parser_errposition(@1.begins)));
  									break;
  								/* these fields are disallowed in current case */
  								case PLPGSQL_GETDIAG_ERROR_CONTEXT:
*************** stmt_getdiag	: K_GET getdiag_area_opt K_
*** 881,887 ****
  												(errcode(ERRCODE_SYNTAX_ERROR),
  												 errmsg("diagnostics item %s is not allowed in GET CURRENT DIAGNOSTICS",
  														plpgsql_getdiag_kindname(ditem->kind)),
! 												 parser_errposition(@1)));
  									break;
  								default:
  									elog(ERROR, "unrecognized diagnostic item kind: %d",
--- 881,887 ----
  												(errcode(ERRCODE_SYNTAX_ERROR),
  												 errmsg("diagnostics item %s is not allowed in GET CURRENT DIAGNOSTICS",
  														plpgsql_getdiag_kindname(ditem->kind)),
! 												 parser_errposition(@1.begins)));
  									break;
  								default:
  									elog(ERROR, "unrecognized diagnostic item kind: %d",
*************** getdiag_item :
*** 962,993 ****
  
  getdiag_target	: T_DATUM
  					{
! 						check_assignable($1.datum, @1);
  						if ($1.datum->dtype == PLPGSQL_DTYPE_ROW ||
  							$1.datum->dtype == PLPGSQL_DTYPE_REC)
  							ereport(ERROR,
  									(errcode(ERRCODE_SYNTAX_ERROR),
  									 errmsg("\"%s\" is not a scalar variable",
  											NameOfDatum(&($1))),
! 									 parser_errposition(@1)));
  						$$ = $1.datum->dno;
  					}
  				| T_WORD
  					{
  						/* just to give a better message than "syntax error" */
! 						word_is_not_variable(&($1), @1);
  					}
  				| T_CWORD
  					{
  						/* just to give a better message than "syntax error" */
! 						cword_is_not_variable(&($1), @1);
  					}
  				;
  
  
  assign_var		: T_DATUM
  					{
! 						check_assignable($1.datum, @1);
  						$$ = $1.datum->dno;
  					}
  				| assign_var '[' expr_until_rightbracket
--- 962,993 ----
  
  getdiag_target	: T_DATUM
  					{
! 						check_assignable($1.datum, @1.begins);
  						if ($1.datum->dtype == PLPGSQL_DTYPE_ROW ||
  							$1.datum->dtype == PLPGSQL_DTYPE_REC)
  							ereport(ERROR,
  									(errcode(ERRCODE_SYNTAX_ERROR),
  									 errmsg("\"%s\" is not a scalar variable",
  											NameOfDatum(&($1))),
! 									 parser_errposition(@1.begins)));
  						$$ = $1.datum->dno;
  					}
  				| T_WORD
  					{
  						/* just to give a better message than "syntax error" */
! 						word_is_not_variable(&($1), @1.begins);
  					}
  				| T_CWORD
  					{
  						/* just to give a better message than "syntax error" */
! 						cword_is_not_variable(&($1), @1.begins);
  					}
  				;
  
  
  assign_var		: T_DATUM
  					{
! 						check_assignable($1.datum, @1.begins);
  						$$ = $1.datum->dno;
  					}
  				| assign_var '[' expr_until_rightbracket
*************** stmt_if			: K_IF expr_until_then proc_se
*** 1013,1019 ****
  
  						new = palloc0(sizeof(PLpgSQL_stmt_if));
  						new->cmd_type	= PLPGSQL_STMT_IF;
! 						new->lineno		= plpgsql_location_to_lineno(@1);
  						new->cond		= $2;
  						new->then_body	= $3;
  						new->elsif_list = $4;
--- 1013,1019 ----
  
  						new = palloc0(sizeof(PLpgSQL_stmt_if));
  						new->cmd_type	= PLPGSQL_STMT_IF;
! 						new->lineno		= plpgsql_location_to_lineno(@1.begins);
  						new->cond		= $2;
  						new->then_body	= $3;
  						new->elsif_list = $4;
*************** stmt_elsifs		:
*** 1032,1038 ****
  						PLpgSQL_if_elsif *new;
  
  						new = palloc0(sizeof(PLpgSQL_if_elsif));
! 						new->lineno = plpgsql_location_to_lineno(@2);
  						new->cond   = $3;
  						new->stmts  = $4;
  
--- 1032,1038 ----
  						PLpgSQL_if_elsif *new;
  
  						new = palloc0(sizeof(PLpgSQL_if_elsif));
! 						new->lineno = plpgsql_location_to_lineno(@2.begins);
  						new->cond   = $3;
  						new->stmts  = $4;
  
*************** stmt_else		:
*** 1052,1058 ****
  
  stmt_case		: K_CASE opt_expr_until_when case_when_list opt_case_else K_END K_CASE ';'
  					{
! 						$$ = make_case(@1, $2, $3, $4);
  					}
  				;
  
--- 1052,1058 ----
  
  stmt_case		: K_CASE opt_expr_until_when case_when_list opt_case_else K_END K_CASE ';'
  					{
! 						$$ = make_case(@1.begins, $2, $3, $4);
  					}
  				;
  
*************** case_when		: K_WHEN expr_until_then proc
*** 1085,1091 ****
  					{
  						PLpgSQL_case_when *new = palloc(sizeof(PLpgSQL_case_when));
  
! 						new->lineno	= plpgsql_location_to_lineno(@1);
  						new->expr	= $2;
  						new->stmts	= $3;
  						$$ = new;
--- 1085,1091 ----
  					{
  						PLpgSQL_case_when *new = palloc(sizeof(PLpgSQL_case_when));
  
! 						new->lineno	= plpgsql_location_to_lineno(@1.begins);
  						new->expr	= $2;
  						new->stmts	= $3;
  						$$ = new;
*************** stmt_loop		: opt_block_label K_LOOP loop
*** 1117,1123 ****
  
  						new = palloc0(sizeof(PLpgSQL_stmt_loop));
  						new->cmd_type = PLPGSQL_STMT_LOOP;
! 						new->lineno   = plpgsql_location_to_lineno(@2);
  						new->label	  = $1;
  						new->body	  = $3.stmts;
  
--- 1117,1123 ----
  
  						new = palloc0(sizeof(PLpgSQL_stmt_loop));
  						new->cmd_type = PLPGSQL_STMT_LOOP;
! 						new->lineno   = plpgsql_location_to_lineno(@2.begins);
  						new->label	  = $1;
  						new->body	  = $3.stmts;
  
*************** stmt_while		: opt_block_label K_WHILE ex
*** 1134,1140 ****
  
  						new = palloc0(sizeof(PLpgSQL_stmt_while));
  						new->cmd_type = PLPGSQL_STMT_WHILE;
! 						new->lineno   = plpgsql_location_to_lineno(@2);
  						new->label	  = $1;
  						new->cond	  = $3;
  						new->body	  = $4.stmts;
--- 1134,1140 ----
  
  						new = palloc0(sizeof(PLpgSQL_stmt_while));
  						new->cmd_type = PLPGSQL_STMT_WHILE;
! 						new->lineno   = plpgsql_location_to_lineno(@2.begins);
  						new->label	  = $1;
  						new->cond	  = $3;
  						new->body	  = $4.stmts;
*************** stmt_for		: opt_block_label K_FOR for_co
*** 1154,1160 ****
  							PLpgSQL_stmt_fori		*new;
  
  							new = (PLpgSQL_stmt_fori *) $3;
! 							new->lineno   = plpgsql_location_to_lineno(@2);
  							new->label	  = $1;
  							new->body	  = $4.stmts;
  							$$ = (PLpgSQL_stmt *) new;
--- 1154,1160 ----
  							PLpgSQL_stmt_fori		*new;
  
  							new = (PLpgSQL_stmt_fori *) $3;
! 							new->lineno   = plpgsql_location_to_lineno(@2.begins);
  							new->label	  = $1;
  							new->body	  = $4.stmts;
  							$$ = (PLpgSQL_stmt *) new;
*************** stmt_for		: opt_block_label K_FOR for_co
*** 1168,1174 ****
  								   $3->cmd_type == PLPGSQL_STMT_DYNFORS);
  							/* forq is the common supertype of all three */
  							new = (PLpgSQL_stmt_forq *) $3;
! 							new->lineno   = plpgsql_location_to_lineno(@2);
  							new->label	  = $1;
  							new->body	  = $4.stmts;
  							$$ = (PLpgSQL_stmt *) new;
--- 1168,1174 ----
  								   $3->cmd_type == PLPGSQL_STMT_DYNFORS);
  							/* forq is the common supertype of all three */
  							new = (PLpgSQL_stmt_forq *) $3;
! 							new->lineno   = plpgsql_location_to_lineno(@2.begins);
  							new->label	  = $1;
  							new->body	  = $4.stmts;
  							$$ = (PLpgSQL_stmt *) new;
*************** stmt_for		: opt_block_label K_FOR for_co
*** 1183,1189 ****
  for_control		: for_variable K_IN
  					{
  						int			tok = yylex();
! 						int			tokloc = yylloc;
  
  						if (tok == K_EXECUTE)
  						{
--- 1183,1189 ----
  for_control		: for_variable K_IN
  					{
  						int			tok = yylex();
! 						int			tokloc = yylloc.begins;
  
  						if (tok == K_EXECUTE)
  						{
*************** for_control		: for_variable K_IN
*** 1201,1218 ****
  							if ($1.rec)
  							{
  								new->rec = $1.rec;
! 								check_assignable((PLpgSQL_datum *) new->rec, @1);
  							}
  							else if ($1.row)
  							{
  								new->row = $1.row;
! 								check_assignable((PLpgSQL_datum *) new->row, @1);
  							}
  							else if ($1.scalar)
  							{
  								/* convert single scalar to list */
  								new->row = make_scalar_list1($1.name, $1.scalar,
! 															 $1.lineno, @1);
  								/* no need for check_assignable */
  							}
  							else
--- 1201,1218 ----
  							if ($1.rec)
  							{
  								new->rec = $1.rec;
! 								check_assignable((PLpgSQL_datum *) new->rec, @1.begins);
  							}
  							else if ($1.row)
  							{
  								new->row = $1.row;
! 								check_assignable((PLpgSQL_datum *) new->row, @1.begins);
  							}
  							else if ($1.scalar)
  							{
  								/* convert single scalar to list */
  								new->row = make_scalar_list1($1.name, $1.scalar,
! 															 $1.lineno, @1.begins);
  								/* no need for check_assignable */
  							}
  							else
*************** for_control		: for_variable K_IN
*** 1220,1226 ****
  								ereport(ERROR,
  										(errcode(ERRCODE_DATATYPE_MISMATCH),
  										 errmsg("loop variable of loop over rows must be a record or row variable or list of scalar variables"),
! 										 parser_errposition(@1)));
  							}
  							new->query = expr;
  
--- 1220,1226 ----
  								ereport(ERROR,
  										(errcode(ERRCODE_DATATYPE_MISMATCH),
  										 errmsg("loop variable of loop over rows must be a record or row variable or list of scalar variables"),
! 										 parser_errposition(@1.begins)));
  							}
  							new->query = expr;
  
*************** for_control		: for_variable K_IN
*** 1254,1260 ****
  								ereport(ERROR,
  										(errcode(ERRCODE_SYNTAX_ERROR),
  										 errmsg("cursor FOR loop must have only one target variable"),
! 										 parser_errposition(@1)));
  
  							/* can't use an unbound cursor this way */
  							if (cursor->cursor_explicit_expr == NULL)
--- 1254,1260 ----
  								ereport(ERROR,
  										(errcode(ERRCODE_SYNTAX_ERROR),
  										 errmsg("cursor FOR loop must have only one target variable"),
! 										 parser_errposition(@1.begins)));
  
  							/* can't use an unbound cursor this way */
  							if (cursor->cursor_explicit_expr == NULL)
*************** for_control		: for_variable K_IN
*** 1344,1350 ****
  									ereport(ERROR,
  											(errcode(ERRCODE_SYNTAX_ERROR),
  											 errmsg("integer FOR loop must have only one target variable"),
! 											 parser_errposition(@1)));
  
  								/* create loop's private variable */
  								fvar = (PLpgSQL_var *)
--- 1344,1350 ----
  									ereport(ERROR,
  											(errcode(ERRCODE_SYNTAX_ERROR),
  											 errmsg("integer FOR loop must have only one target variable"),
! 											 parser_errposition(@1.begins)));
  
  								/* create loop's private variable */
  								fvar = (PLpgSQL_var *)
*************** for_control		: for_variable K_IN
*** 1394,1411 ****
  								if ($1.rec)
  								{
  									new->rec = $1.rec;
! 									check_assignable((PLpgSQL_datum *) new->rec, @1);
  								}
  								else if ($1.row)
  								{
  									new->row = $1.row;
! 									check_assignable((PLpgSQL_datum *) new->row, @1);
  								}
  								else if ($1.scalar)
  								{
  									/* convert single scalar to list */
  									new->row = make_scalar_list1($1.name, $1.scalar,
! 																 $1.lineno, @1);
  									/* no need for check_assignable */
  								}
  								else
--- 1394,1411 ----
  								if ($1.rec)
  								{
  									new->rec = $1.rec;
! 									check_assignable((PLpgSQL_datum *) new->rec, @1.begins);
  								}
  								else if ($1.row)
  								{
  									new->row = $1.row;
! 									check_assignable((PLpgSQL_datum *) new->row, @1.begins);
  								}
  								else if ($1.scalar)
  								{
  									/* convert single scalar to list */
  									new->row = make_scalar_list1($1.name, $1.scalar,
! 																 $1.lineno, @1.begins);
  									/* no need for check_assignable */
  								}
  								else
*************** for_control		: for_variable K_IN
*** 1413,1419 ****
  									ereport(ERROR,
  											(errcode(ERRCODE_SYNTAX_ERROR),
  											 errmsg("loop variable of loop over rows must be a record or row variable or list of scalar variables"),
! 											 parser_errposition(@1)));
  								}
  
  								new->query = expr1;
--- 1413,1419 ----
  									ereport(ERROR,
  											(errcode(ERRCODE_SYNTAX_ERROR),
  											 errmsg("loop variable of loop over rows must be a record or row variable or list of scalar variables"),
! 											 parser_errposition(@1.begins)));
  								}
  
  								new->query = expr1;
*************** for_control		: for_variable K_IN
*** 1444,1450 ****
  for_variable	: T_DATUM
  					{
  						$$.name = NameOfDatum(&($1));
! 						$$.lineno = plpgsql_location_to_lineno(@1);
  						if ($1.datum->dtype == PLPGSQL_DTYPE_ROW)
  						{
  							$$.scalar = NULL;
--- 1444,1450 ----
  for_variable	: T_DATUM
  					{
  						$$.name = NameOfDatum(&($1));
! 						$$.lineno = plpgsql_location_to_lineno(@1.begins);
  						if ($1.datum->dtype == PLPGSQL_DTYPE_ROW)
  						{
  							$$.scalar = NULL;
*************** for_variable	: T_DATUM
*** 1470,1476 ****
  							if (tok == ',')
  								$$.row = read_into_scalar_list($$.name,
  															   $$.scalar,
! 															   @1);
  						}
  					}
  				| T_WORD
--- 1470,1476 ----
  							if (tok == ',')
  								$$.row = read_into_scalar_list($$.name,
  															   $$.scalar,
! 															   @1.begins);
  						}
  					}
  				| T_WORD
*************** for_variable	: T_DATUM
*** 1478,1484 ****
  						int			tok;
  
  						$$.name = $1.ident;
! 						$$.lineno = plpgsql_location_to_lineno(@1);
  						$$.scalar = NULL;
  						$$.rec = NULL;
  						$$.row = NULL;
--- 1478,1484 ----
  						int			tok;
  
  						$$.name = $1.ident;
! 						$$.lineno = plpgsql_location_to_lineno(@1.begins);
  						$$.scalar = NULL;
  						$$.rec = NULL;
  						$$.row = NULL;
*************** for_variable	: T_DATUM
*** 1486,1497 ****
  						tok = yylex();
  						plpgsql_push_back_token(tok);
  						if (tok == ',')
! 							word_is_not_variable(&($1), @1);
  					}
  				| T_CWORD
  					{
  						/* just to give a better message than "syntax error" */
! 						cword_is_not_variable(&($1), @1);
  					}
  				;
  
--- 1486,1497 ----
  						tok = yylex();
  						plpgsql_push_back_token(tok);
  						if (tok == ',')
! 							word_is_not_variable(&($1), @1.begins);
  					}
  				| T_CWORD
  					{
  						/* just to give a better message than "syntax error" */
! 						cword_is_not_variable(&($1), @1.begins);
  					}
  				;
  
*************** stmt_foreach_a	: opt_block_label K_FOREA
*** 1501,1507 ****
  
  						new = palloc0(sizeof(PLpgSQL_stmt_foreach_a));
  						new->cmd_type = PLPGSQL_STMT_FOREACH_A;
! 						new->lineno = plpgsql_location_to_lineno(@2);
  						new->label = $1;
  						new->slice = $4;
  						new->expr = $7;
--- 1501,1507 ----
  
  						new = palloc0(sizeof(PLpgSQL_stmt_foreach_a));
  						new->cmd_type = PLPGSQL_STMT_FOREACH_A;
! 						new->lineno = plpgsql_location_to_lineno(@2.begins);
  						new->label = $1;
  						new->slice = $4;
  						new->expr = $7;
*************** stmt_foreach_a	: opt_block_label K_FOREA
*** 1510,1533 ****
  						if ($3.rec)
  						{
  							new->varno = $3.rec->dno;
! 							check_assignable((PLpgSQL_datum *) $3.rec, @3);
  						}
  						else if ($3.row)
  						{
  							new->varno = $3.row->dno;
! 							check_assignable((PLpgSQL_datum *) $3.row, @3);
  						}
  						else if ($3.scalar)
  						{
  							new->varno = $3.scalar->dno;
! 							check_assignable($3.scalar, @3);
  						}
  						else
  						{
  							ereport(ERROR,
  									(errcode(ERRCODE_SYNTAX_ERROR),
  									 errmsg("loop variable of FOREACH must be a known variable or list of variables"),
! 											 parser_errposition(@3)));
  						}
  
  						check_labels($1, $8.end_label, $8.end_label_location);
--- 1510,1533 ----
  						if ($3.rec)
  						{
  							new->varno = $3.rec->dno;
! 							check_assignable((PLpgSQL_datum *) $3.rec, @3.begins);
  						}
  						else if ($3.row)
  						{
  							new->varno = $3.row->dno;
! 							check_assignable((PLpgSQL_datum *) $3.row, @3.begins);
  						}
  						else if ($3.scalar)
  						{
  							new->varno = $3.scalar->dno;
! 							check_assignable($3.scalar, @3.begins);
  						}
  						else
  						{
  							ereport(ERROR,
  									(errcode(ERRCODE_SYNTAX_ERROR),
  									 errmsg("loop variable of FOREACH must be a known variable or list of variables"),
! 											 parser_errposition(@3.begins)));
  						}
  
  						check_labels($1, $8.end_label, $8.end_label_location);
*************** stmt_exit		: exit_type opt_label opt_exi
*** 1554,1560 ****
  						new = palloc0(sizeof(PLpgSQL_stmt_exit));
  						new->cmd_type = PLPGSQL_STMT_EXIT;
  						new->is_exit  = $1;
! 						new->lineno	  = plpgsql_location_to_lineno(@1);
  						new->label	  = $2;
  						new->cond	  = $3;
  
--- 1554,1560 ----
  						new = palloc0(sizeof(PLpgSQL_stmt_exit));
  						new->cmd_type = PLPGSQL_STMT_EXIT;
  						new->is_exit  = $1;
! 						new->lineno	  = plpgsql_location_to_lineno(@1.begins);
  						new->label	  = $2;
  						new->cond	  = $3;
  
*************** stmt_return		: K_RETURN
*** 1583,1599 ****
  						if (tok_is_keyword(tok, &yylval,
  										   K_NEXT, "next"))
  						{
! 							$$ = make_return_next_stmt(@1);
  						}
  						else if (tok_is_keyword(tok, &yylval,
  												K_QUERY, "query"))
  						{
! 							$$ = make_return_query_stmt(@1);
  						}
  						else
  						{
  							plpgsql_push_back_token(tok);
! 							$$ = make_return_stmt(@1);
  						}
  					}
  				;
--- 1583,1599 ----
  						if (tok_is_keyword(tok, &yylval,
  										   K_NEXT, "next"))
  						{
! 							$$ = make_return_next_stmt(@1.begins);
  						}
  						else if (tok_is_keyword(tok, &yylval,
  												K_QUERY, "query"))
  						{
! 							$$ = make_return_query_stmt(@1.begins);
  						}
  						else
  						{
  							plpgsql_push_back_token(tok);
! 							$$ = make_return_stmt(@1.begins);
  						}
  					}
  				;
*************** stmt_raise		: K_RAISE
*** 1606,1612 ****
  						new = palloc(sizeof(PLpgSQL_stmt_raise));
  
  						new->cmd_type	= PLPGSQL_STMT_RAISE;
! 						new->lineno		= plpgsql_location_to_lineno(@1);
  						new->elog_level = ERROR;	/* default */
  						new->condname	= NULL;
  						new->message	= NULL;
--- 1606,1612 ----
  						new = palloc(sizeof(PLpgSQL_stmt_raise));
  
  						new->cmd_type	= PLPGSQL_STMT_RAISE;
! 						new->lineno		= plpgsql_location_to_lineno(@1.begins);
  						new->elog_level = ERROR;	/* default */
  						new->condname	= NULL;
  						new->message	= NULL;
*************** loop_body		: proc_sect K_END K_LOOP opt_
*** 1741,1747 ****
  					{
  						$$.stmts = $1;
  						$$.end_label = $4;
! 						$$.end_label_location = @4;
  					}
  				;
  
--- 1741,1747 ----
  					{
  						$$.stmts = $1;
  						$$.end_label = $4;
! 						$$.end_label_location = @4.begins;
  					}
  				;
  
*************** loop_body		: proc_sect K_END K_LOOP opt_
*** 1757,1763 ****
   */
  stmt_execsql	: K_INSERT
  					{
! 						$$ = make_execsql_stmt(K_INSERT, @1);
  					}
  				| T_WORD
  					{
--- 1757,1763 ----
   */
  stmt_execsql	: K_INSERT
  					{
! 						$$ = make_execsql_stmt(K_INSERT, @1.begins);
  					}
  				| T_WORD
  					{
*************** stmt_execsql	: K_INSERT
*** 1766,1773 ****
  						tok = yylex();
  						plpgsql_push_back_token(tok);
  						if (tok == '=' || tok == COLON_EQUALS || tok == '[')
! 							word_is_not_variable(&($1), @1);
! 						$$ = make_execsql_stmt(T_WORD, @1);
  					}
  				| T_CWORD
  					{
--- 1766,1773 ----
  						tok = yylex();
  						plpgsql_push_back_token(tok);
  						if (tok == '=' || tok == COLON_EQUALS || tok == '[')
! 							word_is_not_variable(&($1), @1.begins);
! 						$$ = make_execsql_stmt(T_WORD, @1.begins);
  					}
  				| T_CWORD
  					{
*************** stmt_execsql	: K_INSERT
*** 1776,1783 ****
  						tok = yylex();
  						plpgsql_push_back_token(tok);
  						if (tok == '=' || tok == COLON_EQUALS || tok == '[')
! 							cword_is_not_variable(&($1), @1);
! 						$$ = make_execsql_stmt(T_CWORD, @1);
  					}
  				;
  
--- 1776,1783 ----
  						tok = yylex();
  						plpgsql_push_back_token(tok);
  						if (tok == '=' || tok == COLON_EQUALS || tok == '[')
! 							cword_is_not_variable(&($1), @1.begins);
! 						$$ = make_execsql_stmt(T_CWORD, @1.begins);
  					}
  				;
  
*************** stmt_dynexecute : K_EXECUTE
*** 1795,1801 ****
  
  						new = palloc(sizeof(PLpgSQL_stmt_dynexecute));
  						new->cmd_type = PLPGSQL_STMT_DYNEXECUTE;
! 						new->lineno = plpgsql_location_to_lineno(@1);
  						new->query = expr;
  						new->into = false;
  						new->strict = false;
--- 1795,1801 ----
  
  						new = palloc(sizeof(PLpgSQL_stmt_dynexecute));
  						new->cmd_type = PLPGSQL_STMT_DYNEXECUTE;
! 						new->lineno = plpgsql_location_to_lineno(@1.begins);
  						new->query = expr;
  						new->into = false;
  						new->strict = false;
*************** stmt_open		: K_OPEN cursor_variable
*** 1852,1858 ****
  
  						new = palloc0(sizeof(PLpgSQL_stmt_open));
  						new->cmd_type = PLPGSQL_STMT_OPEN;
! 						new->lineno = plpgsql_location_to_lineno(@1);
  						new->curvar = $2->dno;
  						new->cursor_options = CURSOR_OPT_FAST_PLAN;
  
--- 1852,1858 ----
  
  						new = palloc0(sizeof(PLpgSQL_stmt_open));
  						new->cmd_type = PLPGSQL_STMT_OPEN;
! 						new->lineno = plpgsql_location_to_lineno(@1.begins);
  						new->curvar = $2->dno;
  						new->cursor_options = CURSOR_OPT_FAST_PLAN;
  
*************** stmt_fetch		: K_FETCH opt_fetch_directio
*** 1942,1950 ****
  							ereport(ERROR,
  									(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
  									 errmsg("FETCH statement cannot return multiple rows"),
! 									 parser_errposition(@1)));
  
! 						fetch->lineno = plpgsql_location_to_lineno(@1);
  						fetch->rec		= rec;
  						fetch->row		= row;
  						fetch->curvar	= $3->dno;
--- 1942,1950 ----
  							ereport(ERROR,
  									(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
  									 errmsg("FETCH statement cannot return multiple rows"),
! 									 parser_errposition(@1.begins)));
  
! 						fetch->lineno = plpgsql_location_to_lineno(@1.begins);
  						fetch->rec		= rec;
  						fetch->row		= row;
  						fetch->curvar	= $3->dno;
*************** stmt_move		: K_MOVE opt_fetch_direction
*** 1958,1964 ****
  					{
  						PLpgSQL_stmt_fetch *fetch = $2;
  
! 						fetch->lineno = plpgsql_location_to_lineno(@1);
  						fetch->curvar	= $3->dno;
  						fetch->is_move	= true;
  
--- 1958,1964 ----
  					{
  						PLpgSQL_stmt_fetch *fetch = $2;
  
! 						fetch->lineno = plpgsql_location_to_lineno(@1.begins);
  						fetch->curvar	= $3->dno;
  						fetch->is_move	= true;
  
*************** stmt_close		: K_CLOSE cursor_variable ';
*** 1978,1984 ****
  
  						new = palloc(sizeof(PLpgSQL_stmt_close));
  						new->cmd_type = PLPGSQL_STMT_CLOSE;
! 						new->lineno = plpgsql_location_to_lineno(@1);
  						new->curvar = $2->dno;
  
  						$$ = (PLpgSQL_stmt *)new;
--- 1978,1984 ----
  
  						new = palloc(sizeof(PLpgSQL_stmt_close));
  						new->cmd_type = PLPGSQL_STMT_CLOSE;
! 						new->lineno = plpgsql_location_to_lineno(@1.begins);
  						new->curvar = $2->dno;
  
  						$$ = (PLpgSQL_stmt *)new;
*************** cursor_variable	: T_DATUM
*** 1998,2022 ****
  							ereport(ERROR,
  									(errcode(ERRCODE_DATATYPE_MISMATCH),
  									 errmsg("cursor variable must be a simple variable"),
! 									 parser_errposition(@1)));
  
  						if (((PLpgSQL_var *) $1.datum)->datatype->typoid != REFCURSOROID)
  							ereport(ERROR,
  									(errcode(ERRCODE_DATATYPE_MISMATCH),
  									 errmsg("variable \"%s\" must be of type cursor or refcursor",
  											((PLpgSQL_var *) $1.datum)->refname),
! 									 parser_errposition(@1)));
  						$$ = (PLpgSQL_var *) $1.datum;
  					}
  				| T_WORD
  					{
  						/* just to give a better message than "syntax error" */
! 						word_is_not_variable(&($1), @1);
  					}
  				| T_CWORD
  					{
  						/* just to give a better message than "syntax error" */
! 						cword_is_not_variable(&($1), @1);
  					}
  				;
  
--- 1998,2022 ----
  							ereport(ERROR,
  									(errcode(ERRCODE_DATATYPE_MISMATCH),
  									 errmsg("cursor variable must be a simple variable"),
! 									 parser_errposition(@1.begins)));
  
  						if (((PLpgSQL_var *) $1.datum)->datatype->typoid != REFCURSOROID)
  							ereport(ERROR,
  									(errcode(ERRCODE_DATATYPE_MISMATCH),
  									 errmsg("variable \"%s\" must be of type cursor or refcursor",
  											((PLpgSQL_var *) $1.datum)->refname),
! 									 parser_errposition(@1.begins)));
  						$$ = (PLpgSQL_var *) $1.datum;
  					}
  				| T_WORD
  					{
  						/* just to give a better message than "syntax error" */
! 						word_is_not_variable(&($1), @1.begins);
  					}
  				| T_CWORD
  					{
  						/* just to give a better message than "syntax error" */
! 						cword_is_not_variable(&($1), @1.begins);
  					}
  				;
  
*************** exception_sect	:
*** 2031,2037 ****
  						 * scope of the names extends to the end of the
  						 * current block.
  						 */
! 						int			lineno = plpgsql_location_to_lineno(@1);
  						PLpgSQL_exception_block *new = palloc(sizeof(PLpgSQL_exception_block));
  						PLpgSQL_variable *var;
  
--- 2031,2037 ----
  						 * scope of the names extends to the end of the
  						 * current block.
  						 */
! 						int			lineno = plpgsql_location_to_lineno(@1.begins);
  						PLpgSQL_exception_block *new = palloc(sizeof(PLpgSQL_exception_block));
  						PLpgSQL_variable *var;
  
*************** proc_exception	: K_WHEN proc_conditions
*** 2077,2083 ****
  						PLpgSQL_exception *new;
  
  						new = palloc0(sizeof(PLpgSQL_exception));
! 						new->lineno = plpgsql_location_to_lineno(@1);
  						new->conditions = $2;
  						new->action = $4;
  
--- 2077,2083 ----
  						PLpgSQL_exception *new;
  
  						new = palloc0(sizeof(PLpgSQL_exception));
! 						new->lineno = plpgsql_location_to_lineno(@1.begins);
  						new->conditions = $2;
  						new->action = $4;
  
*************** static void
*** 2310,2318 ****
  current_token_is_not_variable(int tok)
  {
  	if (tok == T_WORD)
! 		word_is_not_variable(&(yylval.word), yylloc);
  	else if (tok == T_CWORD)
! 		cword_is_not_variable(&(yylval.cword), yylloc);
  	else
  		yyerror("syntax error");
  }
--- 2310,2318 ----
  current_token_is_not_variable(int tok)
  {
  	if (tok == T_WORD)
! 		word_is_not_variable(&(yylval.word), yylloc.begins);
  	else if (tok == T_CWORD)
! 		cword_is_not_variable(&(yylval.cword), yylloc.begins);
  	else
  		yyerror("syntax error");
  }
*************** read_sql_construct(int until,
*** 2385,2391 ****
  	{
  		tok = yylex();
  		if (startlocation < 0)			/* remember loc of first token */
! 			startlocation = yylloc;
  		if (tok == until && parenlevel == 0)
  			break;
  		if (tok == until2 && parenlevel == 0)
--- 2385,2391 ----
  	{
  		tok = yylex();
  		if (startlocation < 0)			/* remember loc of first token */
! 			startlocation = yylloc.begins;
  		if (tok == until && parenlevel == 0)
  			break;
  		if (tok == until2 && parenlevel == 0)
*************** read_sql_construct(int until,
*** 2414,2426 ****
  						(errcode(ERRCODE_SYNTAX_ERROR),
  						 errmsg("missing \"%s\" at end of SQL expression",
  								expected),
! 						 parser_errposition(yylloc)));
  			else
  				ereport(ERROR,
  						(errcode(ERRCODE_SYNTAX_ERROR),
  						 errmsg("missing \"%s\" at end of SQL statement",
  								expected),
! 						 parser_errposition(yylloc)));
  		}
  	}
  
--- 2414,2426 ----
  						(errcode(ERRCODE_SYNTAX_ERROR),
  						 errmsg("missing \"%s\" at end of SQL expression",
  								expected),
! 						 parser_errposition(yylloc.begins)));
  			else
  				ereport(ERROR,
  						(errcode(ERRCODE_SYNTAX_ERROR),
  						 errmsg("missing \"%s\" at end of SQL statement",
  								expected),
! 						 parser_errposition(yylloc.begins)));
  		}
  	}
  
*************** read_sql_construct(int until,
*** 2432,2438 ****
  		*endtoken = tok;
  
  	/* give helpful complaint about empty input */
! 	if (startlocation >= yylloc)
  	{
  		if (isexpression)
  			yyerror("missing expression");
--- 2432,2438 ----
  		*endtoken = tok;
  
  	/* give helpful complaint about empty input */
! 	if (startlocation >= yylloc.begins)
  	{
  		if (isexpression)
  			yyerror("missing expression");
*************** read_sql_construct(int until,
*** 2440,2446 ****
  			yyerror("missing SQL statement");
  	}
  
! 	plpgsql_append_source_text(&ds, startlocation, yylloc);
  
  	/* trim any trailing whitespace, for neatness */
  	while (ds.len > 0 && scanner_isspace(ds.data[ds.len - 1]))
--- 2440,2446 ----
  			yyerror("missing SQL statement");
  	}
  
! 	plpgsql_append_source_text(&ds, startlocation, yylloc.begins);
  
  	/* trim any trailing whitespace, for neatness */
  	while (ds.len > 0 && scanner_isspace(ds.data[ds.len - 1]))
*************** read_datatype(int tok)
*** 2476,2482 ****
  	if (tok == YYEMPTY)
  		tok = yylex();
  
! 	startlocation = yylloc;
  
  	/*
  	 * If we have a simple or composite identifier, check for %TYPE
--- 2476,2482 ----
  	if (tok == YYEMPTY)
  		tok = yylex();
  
! 	startlocation = yylloc.begins;
  
  	/*
  	 * If we have a simple or composite identifier, check for %TYPE
*************** read_datatype(int tok)
*** 2557,2563 ****
  
  	/* set up ds to contain complete typename text */
  	initStringInfo(&ds);
! 	plpgsql_append_source_text(&ds, startlocation, yylloc);
  	type_name = ds.data;
  
  	if (type_name[0] == '\0')
--- 2557,2563 ----
  
  	/* set up ds to contain complete typename text */
  	initStringInfo(&ds);
! 	plpgsql_append_source_text(&ds, startlocation, yylloc.begins);
  	type_name = ds.data;
  
  	if (type_name[0] == '\0')
*************** make_execsql_stmt(int firsttoken, int lo
*** 2608,2614 ****
  		prev_tok = tok;
  		tok = yylex();
  		if (have_into && into_end_loc < 0)
! 			into_end_loc = yylloc;		/* token after the INTO part */
  		if (tok == ';')
  			break;
  		if (tok == 0)
--- 2608,2614 ----
  		prev_tok = tok;
  		tok = yylex();
  		if (have_into && into_end_loc < 0)
! 			into_end_loc = yylloc.begins;		/* token after the INTO part */
  		if (tok == ';')
  			break;
  		if (tok == 0)
*************** make_execsql_stmt(int firsttoken, int lo
*** 2619,2625 ****
  			if (have_into)
  				yyerror("INTO specified more than once");
  			have_into = true;
! 			into_start_loc = yylloc;
  			plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL;
  			read_into_target(&rec, &row, &have_strict);
  			plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_EXPR;
--- 2619,2625 ----
  			if (have_into)
  				yyerror("INTO specified more than once");
  			have_into = true;
! 			into_start_loc = yylloc.begins;
  			plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL;
  			read_into_target(&rec, &row, &have_strict);
  			plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_EXPR;
*************** make_execsql_stmt(int firsttoken, int lo
*** 2637,2646 ****
  		 */
  		plpgsql_append_source_text(&ds, location, into_start_loc);
  		appendStringInfoSpaces(&ds, into_end_loc - into_start_loc);
! 		plpgsql_append_source_text(&ds, into_end_loc, yylloc);
  	}
  	else
! 		plpgsql_append_source_text(&ds, location, yylloc);
  
  	/* trim any trailing whitespace, for neatness */
  	while (ds.len > 0 && scanner_isspace(ds.data[ds.len - 1]))
--- 2637,2646 ----
  		 */
  		plpgsql_append_source_text(&ds, location, into_start_loc);
  		appendStringInfoSpaces(&ds, into_end_loc - into_start_loc);
! 		plpgsql_append_source_text(&ds, into_end_loc, yylloc.begins);
  	}
  	else
! 		plpgsql_append_source_text(&ds, location, yylloc.begins);
  
  	/* trim any trailing whitespace, for neatness */
  	while (ds.len > 0 && scanner_isspace(ds.data[ds.len - 1]))
*************** make_return_stmt(int location)
*** 2847,2853 ****
  					(errcode(ERRCODE_DATATYPE_MISMATCH),
  					 errmsg("RETURN cannot have a parameter in function returning set"),
  					 errhint("Use RETURN NEXT or RETURN QUERY."),
! 					 parser_errposition(yylloc)));
  	}
  	else if (plpgsql_curr_compile->out_param_varno >= 0)
  	{
--- 2847,2853 ----
  					(errcode(ERRCODE_DATATYPE_MISMATCH),
  					 errmsg("RETURN cannot have a parameter in function returning set"),
  					 errhint("Use RETURN NEXT or RETURN QUERY."),
! 					 parser_errposition(yylloc.begins)));
  	}
  	else if (plpgsql_curr_compile->out_param_varno >= 0)
  	{
*************** make_return_stmt(int location)
*** 2855,2861 ****
  			ereport(ERROR,
  					(errcode(ERRCODE_DATATYPE_MISMATCH),
  					 errmsg("RETURN cannot have a parameter in function with OUT parameters"),
! 					 parser_errposition(yylloc)));
  		new->retvarno = plpgsql_curr_compile->out_param_varno;
  	}
  	else if (plpgsql_curr_compile->fn_rettype == VOIDOID)
--- 2855,2861 ----
  			ereport(ERROR,
  					(errcode(ERRCODE_DATATYPE_MISMATCH),
  					 errmsg("RETURN cannot have a parameter in function with OUT parameters"),
! 					 parser_errposition(yylloc.begins)));
  		new->retvarno = plpgsql_curr_compile->out_param_varno;
  	}
  	else if (plpgsql_curr_compile->fn_rettype == VOIDOID)
*************** make_return_stmt(int location)
*** 2864,2870 ****
  			ereport(ERROR,
  					(errcode(ERRCODE_DATATYPE_MISMATCH),
  					 errmsg("RETURN cannot have a parameter in function returning void"),
! 					 parser_errposition(yylloc)));
  	}
  	else if (plpgsql_curr_compile->fn_retistuple)
  	{
--- 2864,2870 ----
  			ereport(ERROR,
  					(errcode(ERRCODE_DATATYPE_MISMATCH),
  					 errmsg("RETURN cannot have a parameter in function returning void"),
! 					 parser_errposition(yylloc.begins)));
  	}
  	else if (plpgsql_curr_compile->fn_retistuple)
  	{
*************** make_return_stmt(int location)
*** 2882,2895 ****
  					ereport(ERROR,
  							(errcode(ERRCODE_DATATYPE_MISMATCH),
  							 errmsg("RETURN must specify a record or row variable in function returning row"),
! 							 parser_errposition(yylloc)));
  				break;
  
  			default:
  				ereport(ERROR,
  						(errcode(ERRCODE_DATATYPE_MISMATCH),
  						 errmsg("RETURN must specify a record or row variable in function returning row"),
! 						 parser_errposition(yylloc)));
  				break;
  		}
  		if (yylex() != ';')
--- 2882,2895 ----
  					ereport(ERROR,
  							(errcode(ERRCODE_DATATYPE_MISMATCH),
  							 errmsg("RETURN must specify a record or row variable in function returning row"),
! 							 parser_errposition(yylloc.begins)));
  				break;
  
  			default:
  				ereport(ERROR,
  						(errcode(ERRCODE_DATATYPE_MISMATCH),
  						 errmsg("RETURN must specify a record or row variable in function returning row"),
! 						 parser_errposition(yylloc.begins)));
  				break;
  		}
  		if (yylex() != ';')
*************** make_return_next_stmt(int location)
*** 2931,2937 ****
  			ereport(ERROR,
  					(errcode(ERRCODE_DATATYPE_MISMATCH),
  					 errmsg("RETURN NEXT cannot have a parameter in function with OUT parameters"),
! 					 parser_errposition(yylloc)));
  		new->retvarno = plpgsql_curr_compile->out_param_varno;
  	}
  	else if (plpgsql_curr_compile->fn_retistuple)
--- 2931,2937 ----
  			ereport(ERROR,
  					(errcode(ERRCODE_DATATYPE_MISMATCH),
  					 errmsg("RETURN NEXT cannot have a parameter in function with OUT parameters"),
! 					 parser_errposition(yylloc.begins)));
  		new->retvarno = plpgsql_curr_compile->out_param_varno;
  	}
  	else if (plpgsql_curr_compile->fn_retistuple)
*************** make_return_next_stmt(int location)
*** 2946,2959 ****
  					ereport(ERROR,
  							(errcode(ERRCODE_DATATYPE_MISMATCH),
  							 errmsg("RETURN NEXT must specify a record or row variable in function returning row"),
! 							 parser_errposition(yylloc)));
  				break;
  
  			default:
  				ereport(ERROR,
  						(errcode(ERRCODE_DATATYPE_MISMATCH),
  						 errmsg("RETURN NEXT must specify a record or row variable in function returning row"),
! 						 parser_errposition(yylloc)));
  				break;
  		}
  		if (yylex() != ';')
--- 2946,2959 ----
  					ereport(ERROR,
  							(errcode(ERRCODE_DATATYPE_MISMATCH),
  							 errmsg("RETURN NEXT must specify a record or row variable in function returning row"),
! 							 parser_errposition(yylloc.begins)));
  				break;
  
  			default:
  				ereport(ERROR,
  						(errcode(ERRCODE_DATATYPE_MISMATCH),
  						 errmsg("RETURN NEXT must specify a record or row variable in function returning row"),
! 						 parser_errposition(yylloc.begins)));
  				break;
  		}
  		if (yylex() != ';')
*************** read_into_target(PLpgSQL_rec **rec, PLpg
*** 3087,3118 ****
  		case T_DATUM:
  			if (yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_ROW)
  			{
! 				check_assignable(yylval.wdatum.datum, yylloc);
  				*row = (PLpgSQL_row *) yylval.wdatum.datum;
  
  				if ((tok = yylex()) == ',')
  					ereport(ERROR,
  							(errcode(ERRCODE_SYNTAX_ERROR),
  							 errmsg("record or row variable cannot be part of multiple-item INTO list"),
! 							 parser_errposition(yylloc)));
  				plpgsql_push_back_token(tok);
  			}
  			else if (yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_REC)
  			{
! 				check_assignable(yylval.wdatum.datum, yylloc);
  				*rec = (PLpgSQL_rec *) yylval.wdatum.datum;
  
  				if ((tok = yylex()) == ',')
  					ereport(ERROR,
  							(errcode(ERRCODE_SYNTAX_ERROR),
  							 errmsg("record or row variable cannot be part of multiple-item INTO list"),
! 							 parser_errposition(yylloc)));
  				plpgsql_push_back_token(tok);
  			}
  			else
  			{
  				*row = read_into_scalar_list(NameOfDatum(&(yylval.wdatum)),
! 											 yylval.wdatum.datum, yylloc);
  			}
  			break;
  
--- 3087,3118 ----
  		case T_DATUM:
  			if (yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_ROW)
  			{
! 				check_assignable(yylval.wdatum.datum, yylloc.begins);
  				*row = (PLpgSQL_row *) yylval.wdatum.datum;
  
  				if ((tok = yylex()) == ',')
  					ereport(ERROR,
  							(errcode(ERRCODE_SYNTAX_ERROR),
  							 errmsg("record or row variable cannot be part of multiple-item INTO list"),
! 							 parser_errposition(yylloc.begins)));
  				plpgsql_push_back_token(tok);
  			}
  			else if (yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_REC)
  			{
! 				check_assignable(yylval.wdatum.datum, yylloc.begins);
  				*rec = (PLpgSQL_rec *) yylval.wdatum.datum;
  
  				if ((tok = yylex()) == ',')
  					ereport(ERROR,
  							(errcode(ERRCODE_SYNTAX_ERROR),
  							 errmsg("record or row variable cannot be part of multiple-item INTO list"),
! 							 parser_errposition(yylloc.begins)));
  				plpgsql_push_back_token(tok);
  			}
  			else
  			{
  				*row = read_into_scalar_list(NameOfDatum(&(yylval.wdatum)),
! 											 yylval.wdatum.datum, yylloc.begins);
  			}
  			break;
  
*************** read_into_scalar_list(char *initial_name
*** 3151,3170 ****
  			ereport(ERROR,
  					(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
  					 errmsg("too many INTO variables specified"),
! 					 parser_errposition(yylloc)));
  
  		tok = yylex();
  		switch (tok)
  		{
  			case T_DATUM:
! 				check_assignable(yylval.wdatum.datum, yylloc);
  				if (yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_ROW ||
  					yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_REC)
  					ereport(ERROR,
  							(errcode(ERRCODE_SYNTAX_ERROR),
  							 errmsg("\"%s\" is not a scalar variable",
  									NameOfDatum(&(yylval.wdatum))),
! 							 parser_errposition(yylloc)));
  				fieldnames[nfields] = NameOfDatum(&(yylval.wdatum));
  				varnos[nfields++]	= yylval.wdatum.datum->dno;
  				break;
--- 3151,3170 ----
  			ereport(ERROR,
  					(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
  					 errmsg("too many INTO variables specified"),
! 					 parser_errposition(yylloc.begins)));
  
  		tok = yylex();
  		switch (tok)
  		{
  			case T_DATUM:
! 				check_assignable(yylval.wdatum.datum, yylloc.begins);
  				if (yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_ROW ||
  					yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_REC)
  					ereport(ERROR,
  							(errcode(ERRCODE_SYNTAX_ERROR),
  							 errmsg("\"%s\" is not a scalar variable",
  									NameOfDatum(&(yylval.wdatum))),
! 							 parser_errposition(yylloc.begins)));
  				fieldnames[nfields] = NameOfDatum(&(yylval.wdatum));
  				varnos[nfields++]	= yylval.wdatum.datum->dno;
  				break;
*************** read_cursor_args(PLpgSQL_var *cursor, in
*** 3394,3400 ****
  					(errcode(ERRCODE_SYNTAX_ERROR),
  					 errmsg("cursor \"%s\" has no arguments",
  							cursor->refname),
! 					 parser_errposition(yylloc)));
  
  		if (tok != until)
  			yyerror("syntax error");
--- 3394,3400 ----
  					(errcode(ERRCODE_SYNTAX_ERROR),
  					 errmsg("cursor \"%s\" has no arguments",
  							cursor->refname),
! 					 parser_errposition(yylloc.begins)));
  
  		if (tok != until)
  			yyerror("syntax error");
*************** read_cursor_args(PLpgSQL_var *cursor, in
*** 3408,3414 ****
  				(errcode(ERRCODE_SYNTAX_ERROR),
  				 errmsg("cursor \"%s\" has arguments",
  						cursor->refname),
! 				 parser_errposition(yylloc)));
  
  	/*
  	 * Read expressions until the matching ')'.
--- 3408,3414 ----
  				(errcode(ERRCODE_SYNTAX_ERROR),
  				 errmsg("cursor \"%s\" has arguments",
  						cursor->refname),
! 				 parser_errposition(yylloc.begins)));
  
  	/*
  	 * Read expressions until the matching ')'.
diff --git a/src/pl/plpgsql/src/pl_scanner.c b/src/pl/plpgsql/src/pl_scanner.c
index 76e8436..7f18560 100644
*** a/src/pl/plpgsql/src/pl_scanner.c
--- b/src/pl/plpgsql/src/pl_scanner.c
*************** plpgsql_yylex(void)
*** 283,289 ****
  				push_back_token(tok3, &aux3);
  				push_back_token(tok2, &aux2);
  				if (plpgsql_parse_word(aux1.lval.str,
! 									   core_yy.scanbuf + aux1.lloc,
  									   &aux1.lval.wdatum,
  									   &aux1.lval.word))
  					tok1 = T_DATUM;
--- 283,289 ----
  				push_back_token(tok3, &aux3);
  				push_back_token(tok2, &aux2);
  				if (plpgsql_parse_word(aux1.lval.str,
! 									   core_yy.scanbuf + aux1.lloc.begins,
  									   &aux1.lval.wdatum,
  									   &aux1.lval.word))
  					tok1 = T_DATUM;
*************** plpgsql_yylex(void)
*** 304,310 ****
  			/* not A.B, so just process A */
  			push_back_token(tok2, &aux2);
  			if (plpgsql_parse_word(aux1.lval.str,
! 								   core_yy.scanbuf + aux1.lloc,
  								   &aux1.lval.wdatum,
  								   &aux1.lval.word))
  				tok1 = T_DATUM;
--- 304,310 ----
  			/* not A.B, so just process A */
  			push_back_token(tok2, &aux2);
  			if (plpgsql_parse_word(aux1.lval.str,
! 								   core_yy.scanbuf + aux1.lloc.begins,
  								   &aux1.lval.wdatum,
  								   &aux1.lval.word))
  				tok1 = T_DATUM;
*************** internal_yylex(TokenAuxData *auxdata)
*** 356,362 ****
  						   yyscanner);
  
  		/* remember the length of yytext before it gets changed */
! 		yytext = core_yy.scanbuf + auxdata->lloc;
  		auxdata->leng = strlen(yytext);
  
  		/* Check for << >> and #, which the core considers operators */
--- 356,362 ----
  						   yyscanner);
  
  		/* remember the length of yytext before it gets changed */
! 		yytext = core_yy.scanbuf + auxdata->lloc.begins;
  		auxdata->leng = strlen(yytext);
  
  		/* Check for << >> and #, which the core considers operators */
*************** plpgsql_scanner_errposition(int location
*** 464,470 ****
  void
  plpgsql_yyerror(const char *message)
  {
! 	char	   *yytext = core_yy.scanbuf + plpgsql_yylloc;
  
  	if (*yytext == '\0')
  	{
--- 464,470 ----
  void
  plpgsql_yyerror(const char *message)
  {
! 	char	   *yytext = core_yy.scanbuf + plpgsql_yylloc.begins;
  
  	if (*yytext == '\0')
  	{
*************** plpgsql_yyerror(const char *message)
*** 472,478 ****
  				(errcode(ERRCODE_SYNTAX_ERROR),
  		/* translator: %s is typically the translation of "syntax error" */
  				 errmsg("%s at end of input", _(message)),
! 				 plpgsql_scanner_errposition(plpgsql_yylloc)));
  	}
  	else
  	{
--- 472,478 ----
  				(errcode(ERRCODE_SYNTAX_ERROR),
  		/* translator: %s is typically the translation of "syntax error" */
  				 errmsg("%s at end of input", _(message)),
! 				 plpgsql_scanner_errposition(plpgsql_yylloc.begins)));
  	}
  	else
  	{
*************** plpgsql_yyerror(const char *message)
*** 488,494 ****
  				(errcode(ERRCODE_SYNTAX_ERROR),
  		/* translator: first %s is typically the translation of "syntax error" */
  				 errmsg("%s at or near \"%s\"", _(message), yytext),
! 				 plpgsql_scanner_errposition(plpgsql_yylloc)));
  	}
  }
  
--- 488,494 ----
  				(errcode(ERRCODE_SYNTAX_ERROR),
  		/* translator: first %s is typically the translation of "syntax error" */
  				 errmsg("%s at or near \"%s\"", _(message), yytext),
! 				 plpgsql_scanner_errposition(plpgsql_yylloc.begins)));
  	}
  }
  
