diff --git a/contrib/pg_stat_statements/expected/pg_stat_statements.out b/contrib/pg_stat_statements/expected/pg_stat_statements.out
index 3573c19..06f6ffe 100644
--- a/contrib/pg_stat_statements/expected/pg_stat_statements.out
+++ b/contrib/pg_stat_statements/expected/pg_stat_statements.out
@@ -1,21 +1,363 @@
 CREATE EXTENSION pg_stat_statements;
-CREATE TABLE test (a int, b char(20));
--- test the basic functionality of pg_stat_statements
+--
+--
+-- simple and compound statements
+--
+SET pg_stat_statements.track_utility = FALSE;
+SELECT pg_stat_statements_reset();
+ pg_stat_statements_reset 
+--------------------------
+ 
+(1 row)
+
+SELECT 1 AS "int";
+ int 
+-----
+   1
+(1 row)
+
+SELECT 'hello'
+  -- multiline
+  AS "text";
+ text  
+-------
+ hello
+(1 row)
+
+SELECT 'world' AS "text";
+ text  
+-------
+ world
+(1 row)
+
+-- transaction
+BEGIN;
+SELECT 1 AS "int";
+ int 
+-----
+   1
+(1 row)
+
+SELECT 'hello' AS "text";
+ text  
+-------
+ hello
+(1 row)
+
+COMMIT;
+-- compound transaction
+BEGIN \;
+SELECT 2.0 AS "float" \;
+SELECT 'world' AS "text" \;
+COMMIT;
+-- compound with empty statements and spurious leading spacing
+\;\;   SELECT 3 + 3 \;\;\;   SELECT ' ' || ' !' \;\;   SELECT 1 + 4 \;;
+ ?column? 
+----------
+        5
+(1 row)
+
+-- non ;-terminated statements
+SELECT 1 + 1 + 1 AS "add" \gset
+SELECT :add + 1 + 1 AS "add" \;
+SELECT :add + 1 + 1 AS "add" \gset
+-- set operator
+SELECT 1 AS i UNION SELECT 2 ORDER BY i;
+ i 
+---
+ 1
+ 2
+(2 rows)
+
+-- cte
+WITH t(f) AS (
+  VALUES (1.0), (2.0)
+)
+  SELECT f FROM t ORDER BY f;
+  f  
+-----
+ 1.0
+ 2.0
+(2 rows)
+
+SELECT query, calls, rows FROM pg_stat_statements ORDER BY rows, query;
+                  query                  | calls | rows 
+-----------------------------------------+-------+------
+ SELECT ? || ?                           |     1 |    1
+ SELECT ? AS "float"                     |     1 |    1
+ SELECT pg_stat_statements_reset()       |     1 |    1
+ SELECT ? + ?                            |     2 |    2
+ SELECT ? AS "int"                       |     2 |    2
+ SELECT ? AS i UNION SELECT ? ORDER BY i |     1 |    2
+ WITH t(f) AS (                         +|     1 |    2
+   VALUES (?), (?)                      +|       | 
+ )                                      +|       | 
+   SELECT f FROM t ORDER BY f            |       | 
+ SELECT ? + ? + ? AS "add"               |     3 |    3
+ SELECT ?                               +|     4 |    4
+                                        +|       | 
+   AS "text"                             |       | 
+(9 rows)
+
+--
+--
+-- CRUD: INSERT SELECT UPDATE DELETE on test table
+--
 SELECT pg_stat_statements_reset();
  pg_stat_statements_reset 
 --------------------------
  
 (1 row)
 
+-- utility "create table" must not show
+CREATE TABLE test (a int, b char(20));
 INSERT INTO test VALUES(generate_series(1, 10), 'aaa');
-UPDATE test SET b = 'bbb' WHERE a > 5;
-SELECT query, calls, rows from pg_stat_statements ORDER BY rows;
-                       query                        | calls | rows 
-----------------------------------------------------+-------+------
- SELECT pg_stat_statements_reset();                 |     1 |    1
- UPDATE test SET b = ? WHERE a > ?;                 |     1 |    5
- INSERT INTO test VALUES(generate_series(?, ?), ?); |     1 |   10
+UPDATE test SET b = 'bbb' WHERE a > 7;
+DELETE FROM test WHERE a > 9;
+-- explicit transaction
+BEGIN;
+UPDATE test SET b = '111' WHERE a = 1 ;
+COMMIT;
+BEGIN \;
+UPDATE test SET b = '222' WHERE a = 2 \;
+COMMIT ;
+UPDATE test SET b = '333' WHERE a = 3 \;
+UPDATE test SET b = '444' WHERE a = 4 ;
+BEGIN \;
+UPDATE test SET b = '555' WHERE a = 5 \;
+UPDATE test SET b = '666' WHERE a = 6 \;
+COMMIT ;
+-- SELECT with constants
+SELECT * FROM test WHERE a > 5 ORDER BY a ;
+ a |          b           
+---+----------------------
+ 6 | 666                 
+ 7 | aaa                 
+ 8 | bbb                 
+ 9 | bbb                 
+(4 rows)
+
+SELECT *
+  FROM test
+  WHERE a > 9
+  ORDER BY a ;
+ a | b 
+---+---
+(0 rows)
+
+-- SELECT without constants
+SELECT * FROM test ORDER BY a;
+ a |          b           
+---+----------------------
+ 1 | 111                 
+ 2 | 222                 
+ 3 | 333                 
+ 4 | 444                 
+ 5 | 555                 
+ 6 | 666                 
+ 7 | aaa                 
+ 8 | bbb                 
+ 9 | bbb                 
+(9 rows)
+
+SELECT query, calls, rows FROM pg_stat_statements ORDER BY rows, query;
+                       query                       | calls | rows 
+---------------------------------------------------+-------+------
+ DELETE FROM test WHERE a > ?                      |     1 |    1
+ SELECT pg_stat_statements_reset()                 |     1 |    1
+ UPDATE test SET b = ? WHERE a > ?                 |     1 |    3
+ SELECT * FROM test WHERE a > ? ORDER BY a         |     2 |    4
+ UPDATE test SET b = ? WHERE a = ?                 |     6 |    6
+ SELECT * FROM test ORDER BY a                     |     1 |    9
+ INSERT INTO test VALUES(generate_series(?, ?), ?) |     1 |   10
+(7 rows)
+
+--
+--
+-- pg_stat_statements.track = none
+--
+SET pg_stat_statements.track = 'none';
+SELECT pg_stat_statements_reset();
+ pg_stat_statements_reset 
+--------------------------
+ 
+(1 row)
+
+SELECT 1 AS "one";
+ one 
+-----
+   1
+(1 row)
+
+SELECT 1 + 1 AS "two";
+ two 
+-----
+   2
+(1 row)
+
+SELECT query, calls, rows FROM pg_stat_statements ORDER BY rows, query;
+ query | calls | rows 
+-------+-------+------
+(0 rows)
+
+--
+--
+-- pg_stat_statements.track = top
+--
+SELECT pg_stat_statements_reset();
+ pg_stat_statements_reset 
+--------------------------
+ 
+(1 row)
+
+SET pg_stat_statements.track = 'top';
+DO LANGUAGE plpgsql $$
+BEGIN
+  -- this is a SELECT
+  PERFORM 'hello world'::TEXT;
+END;
+$$;
+-- PL/pgSQL function
+CREATE FUNCTION PLUS_TWO(i INTEGER) RETURNS INTEGER AS $$
+DECLARE
+  r INTEGER;
+BEGIN
+  SELECT (i + 1 + 1.0)::INTEGER INTO r;
+  RETURN r;
+END; $$ LANGUAGE plpgsql;
+SELECT PLUS_TWO(3);
+ plus_two 
+----------
+        5
+(1 row)
+
+SELECT PLUS_TWO(7);
+ plus_two 
+----------
+        9
+(1 row)
+
+-- SQL function
+CREATE FUNCTION PLUS_ONE(i INTEGER) RETURNS INTEGER AS
+$$ SELECT (i + 1.0)::INTEGER $$ LANGUAGE SQL;
+SELECT PLUS_ONE(8);
+ plus_one 
+----------
+        9
+(1 row)
+
+SELECT PLUS_ONE(10);
+ plus_one 
+----------
+       11
+(1 row)
+
+DROP FUNCTION PLUS_ONE(INTEGER);
+DROP FUNCTION PLUS_TWO(INTEGER);
+SELECT query, calls, rows FROM pg_stat_statements ORDER BY rows, query;
+       query        | calls | rows 
+--------------------+-------+------
+ SELECT ?::TEXT     |     1 |    1
+ SELECT PLUS_ONE(?) |     2 |    2
+ SELECT PLUS_TWO(?) |     2 |    2
 (3 rows)
 
-DROP TABLE test;
+--
+--
+-- pg_stat_statements.track = all
+--
+SELECT pg_stat_statements_reset();
+ pg_stat_statements_reset 
+--------------------------
+ 
+(1 row)
+
+SET pg_stat_statements.track = 'all';
+-- recreate PL/pgSQL function
+CREATE FUNCTION PLUS_TWO(i INTEGER) RETURNS INTEGER AS $$
+DECLARE
+  r INTEGER;
+BEGIN
+  SELECT (i + 1 + 1.0)::INTEGER INTO r;
+  RETURN r;
+END; $$ LANGUAGE plpgsql;
+SELECT PLUS_TWO(-1);
+ plus_two 
+----------
+        1
+(1 row)
+
+SELECT PLUS_TWO(2);
+ plus_two 
+----------
+        4
+(1 row)
+
+-- SQL function nesting
+CREATE FUNCTION PLUS_ONE(i INTEGER) RETURNS INTEGER AS
+$$ SELECT (i + 1.0)::INTEGER $$ LANGUAGE SQL;
+SELECT PLUS_ONE(3);
+ plus_one 
+----------
+        4
+(1 row)
+
+SELECT PLUS_ONE(1);
+ plus_one 
+----------
+        2
+(1 row)
+
+-- bug? PLUS_ONE expansion is missing
+SELECT query, calls, rows FROM pg_stat_statements ORDER BY rows, query;
+               query               | calls | rows 
+-----------------------------------+-------+------
+ SELECT pg_stat_statements_reset() |     1 |    1
+ SELECT (i + ? + ?)::INTEGER       |     2 |    2
+ SELECT PLUS_ONE(?)                |     2 |    2
+ SELECT PLUS_TWO(?)                |     2 |    2
+(4 rows)
+
+--
+--
+-- utility commands
+--
+SELECT pg_stat_statements_reset();
+ pg_stat_statements_reset 
+--------------------------
+ 
+(1 row)
+
+SET pg_stat_statements.track_utility = TRUE;
+SELECT 1;
+ ?column? 
+----------
+        1
+(1 row)
+
+CREATE INDEX test_b ON test(b);
+DROP TABLE test \;
+DROP TABLE IF EXISTS test \;
+DROP FUNCTION PLUS_ONE(INTEGER);
+NOTICE:  table "test" does not exist, skipping
+DROP TABLE IF EXISTS test \;
+DROP TABLE IF EXISTS test \;
+DROP FUNCTION IF EXISTS PLUS_ONE(INTEGER);
+NOTICE:  table "test" does not exist, skipping
+NOTICE:  table "test" does not exist, skipping
+NOTICE:  function plus_one(pg_catalog.int4) does not exist, skipping
+DROP FUNCTION PLUS_TWO(INTEGER);
+SELECT query, calls, rows FROM pg_stat_statements ORDER BY rows, query;
+                   query                   | calls | rows 
+-------------------------------------------+-------+------
+ CREATE INDEX test_b ON test(b)            |     1 |    0
+ DROP FUNCTION IF EXISTS PLUS_ONE(INTEGER) |     1 |    0
+ DROP FUNCTION PLUS_ONE(INTEGER)           |     1 |    0
+ DROP FUNCTION PLUS_TWO(INTEGER)           |     1 |    0
+ DROP TABLE IF EXISTS test                 |     3 |    0
+ DROP TABLE test                           |     1 |    0
+ SELECT ?                                  |     1 |    1
+ SELECT pg_stat_statements_reset()         |     1 |    1
+(8 rows)
+
 DROP EXTENSION pg_stat_statements;
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 8ce24e0..471a24c 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -297,11 +297,10 @@ static void pgss_ProcessUtility(Node *parsetree, const char *queryString,
 					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 uint32 pgss_hash_string(const char *str);
-static void pgss_store(const char *query, uint32 queryId,
-		   double total_time, uint64 rows,
-		   const BufferUsage *bufusage,
-		   pgssJumbleState *jstate);
+static uint32 pgss_hash_string(char *str, int length);
+static void pgss_store(const char *query, int query_loc, int query_len,
+			   uint32 queryId, double total_time, uint64 rows,
+			   const BufferUsage *bufusage, pgssJumbleState *jstate);
 static void pg_stat_statements_internal(FunctionCallInfo fcinfo,
 							pgssVersion api_version,
 							bool showtext);
@@ -324,7 +323,7 @@ static void JumbleRangeTable(pgssJumbleState *jstate, List *rtable);
 static void JumbleExpr(pgssJumbleState *jstate, Node *node);
 static void RecordConstLocation(pgssJumbleState *jstate, int location);
 static char *generate_normalized_query(pgssJumbleState *jstate, const char *query,
-						  int *query_len_p, int encoding);
+							   int query_loc, int *query_len_p, int encoding);
 static void fill_in_constant_lengths(pgssJumbleState *jstate, const char *query);
 static int	comp_location(const void *a, const void *b);
 
@@ -820,7 +819,7 @@ pgss_post_parse_analyze(ParseState *pstate, Query *query)
 	 * there's no need for an early entry.
 	 */
 	if (jstate.clocations_count > 0)
-		pgss_store(pstate->p_sourcetext,
+		pgss_store(pstate->p_sourcetext, query->location, query->length,
 				   query->queryId,
 				   0,
 				   0,
@@ -925,6 +924,8 @@ pgss_ExecutorEnd(QueryDesc *queryDesc)
 		InstrEndLoop(queryDesc->totaltime);
 
 		pgss_store(queryDesc->sourceText,
+				   queryDesc->plannedstmt->location,
+				   queryDesc->plannedstmt->length,
 				   queryId,
 				   queryDesc->totaltime->total * 1000.0,		/* convert to msec */
 				   queryDesc->estate->es_processed,
@@ -971,6 +972,9 @@ pgss_ProcessUtility(Node *parsetree, const char *queryString,
 		BufferUsage bufusage_start,
 					bufusage;
 		uint32		queryId;
+		ParseNode  *parsenode = (ParseNode *) parsetree;
+
+		Assert(isParseNode(parsetree));
 
 		bufusage_start = pgBufferUsage;
 		INSTR_TIME_SET_CURRENT(start);
@@ -1031,10 +1035,11 @@ pgss_ProcessUtility(Node *parsetree, const char *queryString,
 		bufusage.blk_write_time = pgBufferUsage.blk_write_time;
 		INSTR_TIME_SUBTRACT(bufusage.blk_write_time, bufusage_start.blk_write_time);
 
-		/* For utility statements, we just hash the query string directly */
-		queryId = pgss_hash_string(queryString);
+		/* For utility statements, we just hash the relevant part of query string */
+		queryId = pgss_hash_string((char *) queryString + parsenode->location,
+								   parsenode->length);
 
-		pgss_store(queryString,
+		pgss_store(queryString, parsenode->location, parsenode->length,
 				   queryId,
 				   INSTR_TIME_GET_MILLISEC(duration),
 				   rows,
@@ -1084,15 +1089,18 @@ pgss_match_fn(const void *key1, const void *key2, Size keysize)
 		return 1;
 }
 
+
 /*
- * Given an arbitrarily long query string, produce a hash for the purposes of
- * identifying the query, without normalizing constants.  Used when hashing
- * utility statements.
+ * Given an arbitrarily query string, produce a hash for the purposes of
+ * identifying the query, without normalizing constants, and with some trimming.
+ * Used when hashing utility statements.
  */
 static uint32
-pgss_hash_string(const char *str)
+pgss_hash_string(char *str, int len)
 {
-	return hash_any((const unsigned char *) str, strlen(str));
+	while (isspace(*str))
+		str++, len--;
+	return hash_any((const unsigned char *) str, len);
 }
 
 /*
@@ -1103,7 +1111,7 @@ pgss_hash_string(const char *str)
  * query string.  total_time, rows, bufusage are ignored in this case.
  */
 static void
-pgss_store(const char *query, uint32 queryId,
+pgss_store(const char *query, int query_loc, int query_len, uint32 queryId,
 		   double total_time, uint64 rows,
 		   const BufferUsage *bufusage,
 		   pgssJumbleState *jstate)
@@ -1112,15 +1120,15 @@ pgss_store(const char *query, uint32 queryId,
 	pgssEntry  *entry;
 	char	   *norm_query = NULL;
 	int			encoding = GetDatabaseEncoding();
-	int			query_len;
 
-	Assert(query != NULL);
+	Assert(query != NULL && query_loc >= 0 && query_len >= 0);
 
 	/* Safety check... */
 	if (!pgss || !pgss_hash)
 		return;
 
-	query_len = strlen(query);
+	if (query_len == 0)
+		query_len = strlen(query);
 
 	/* Set up key for hashtable search */
 	key.userid = GetUserId();
@@ -1140,6 +1148,11 @@ pgss_store(const char *query, uint32 queryId,
 		bool		stored;
 		bool		do_gc;
 
+		/* skip leading spaces */
+		while (isspace(query[query_loc]))
+			query_loc++, query_len--;
+		/* should skip trailing spaces? encoding dependence? */
+
 		/*
 		 * Create a new, normalized query string if caller asked.  We don't
 		 * need to hold the lock while doing this work.  (Note: in any case,
@@ -1150,14 +1163,14 @@ pgss_store(const char *query, uint32 queryId,
 		if (jstate)
 		{
 			LWLockRelease(pgss->lock);
-			norm_query = generate_normalized_query(jstate, query,
+			norm_query = generate_normalized_query(jstate, query, query_loc,
 												   &query_len,
 												   encoding);
 			LWLockAcquire(pgss->lock, LW_SHARED);
 		}
 
 		/* Append new query text to file with only shared lock held */
-		stored = qtext_store(norm_query ? norm_query : query, query_len,
+		stored = qtext_store(norm_query ? norm_query : query + query_loc, query_len,
 							 &query_offset, &gc_count);
 
 		/*
@@ -1771,10 +1784,7 @@ entry_dealloc(void)
 
 /*
  * Given a null-terminated string, allocate a new entry in the external query
- * text file and store the string there.
- *
- * Although we could compute the string length via strlen(), callers already
- * have it handy, so we require them to pass it too.
+ * text file and store the string there, possibly truncated at query_len.
  *
  * If successful, returns true, and stores the new entry's offset in the file
  * into *query_offset.  Also, if gc_count isn't NULL, *gc_count is set to the
@@ -1822,7 +1832,9 @@ qtext_store(const char *query, int query_len,
 	if (lseek(fd, off, SEEK_SET) != off)
 		goto error;
 
-	if (write(fd, query, query_len + 1) != query_len + 1)
+	/* add truncated query and 0 termination */
+	if (write(fd, query, query_len) != query_len ||
+		write(fd, "\0", 1) != 1)
 		goto error;
 
 	CloseTransientFile(fd);
@@ -2882,15 +2894,15 @@ RecordConstLocation(pgssJumbleState *jstate, int location)
  */
 static char *
 generate_normalized_query(pgssJumbleState *jstate, const char *query,
-						  int *query_len_p, int encoding)
+						  int query_loc, int *query_len_p, int encoding)
 {
 	char	   *norm_query;
 	int			query_len = *query_len_p;
 	int			i,
 				len_to_wrt,		/* Length (in bytes) to write */
-				quer_loc = 0,	/* Source query byte location */
+				quer_loc = query_loc, /* Source query byte location */
 				n_quer_loc = 0, /* Normalized query byte location */
-				last_off = 0,	/* Offset from start for previous tok */
+				last_off = query_loc,	/* Offset from start for previous tok */
 				last_tok_len = 0;		/* Length (in bytes) of that tok */
 
 	/*
@@ -2933,7 +2945,7 @@ generate_normalized_query(pgssJumbleState *jstate, const char *query,
 	 * We've copied up until the last ignorable constant.  Copy over the
 	 * remaining bytes of the original query string.
 	 */
-	len_to_wrt = query_len - quer_loc;
+	len_to_wrt = query_loc + query_len - quer_loc;
 
 	Assert(len_to_wrt >= 0);
 	memcpy(norm_query + n_quer_loc, query + quer_loc, len_to_wrt);
diff --git a/contrib/pg_stat_statements/sql/pg_stat_statements.sql b/contrib/pg_stat_statements/sql/pg_stat_statements.sql
index 7e2b263..2a32f23 100644
--- a/contrib/pg_stat_statements/sql/pg_stat_statements.sql
+++ b/contrib/pg_stat_statements/sql/pg_stat_statements.sql
@@ -1,15 +1,188 @@
 CREATE EXTENSION pg_stat_statements;
 
-CREATE TABLE test (a int, b char(20));
+--
+--
+-- simple and compound statements
+--
+SET pg_stat_statements.track_utility = FALSE;
+SELECT pg_stat_statements_reset();
+
+SELECT 1 AS "int";
+
+
+SELECT 'hello'
+  -- multiline
+  AS "text";
+SELECT 'world' AS "text";
+
+-- transaction
+BEGIN;
+SELECT 1 AS "int";
+SELECT 'hello' AS "text";
+COMMIT;
+
+-- compound transaction
+BEGIN \;
+SELECT 2.0 AS "float" \;
+SELECT 'world' AS "text" \;
+COMMIT;
+
+-- compound with empty statements and spurious leading spacing
+\;\;   SELECT 3 + 3 \;\;\;   SELECT ' ' || ' !' \;\;   SELECT 1 + 4 \;;
+
+-- non ;-terminated statements
+SELECT 1 + 1 + 1 AS "add" \gset
+SELECT :add + 1 + 1 AS "add" \;
+SELECT :add + 1 + 1 AS "add" \gset
+
+-- set operator
+SELECT 1 AS i UNION SELECT 2 ORDER BY i;
+
+-- cte
+WITH t(f) AS (
+  VALUES (1.0), (2.0)
+)
+  SELECT f FROM t ORDER BY f;
 
--- test the basic functionality of pg_stat_statements
+SELECT query, calls, rows FROM pg_stat_statements ORDER BY rows, query;
+
+--
+--
+-- CRUD: INSERT SELECT UPDATE DELETE on test table
+--
 SELECT pg_stat_statements_reset();
 
+-- utility "create table" must not show
+CREATE TABLE test (a int, b char(20));
+
 INSERT INTO test VALUES(generate_series(1, 10), 'aaa');
-UPDATE test SET b = 'bbb' WHERE a > 5;
+UPDATE test SET b = 'bbb' WHERE a > 7;
+DELETE FROM test WHERE a > 9;
+
+-- explicit transaction
+BEGIN;
+UPDATE test SET b = '111' WHERE a = 1 ;
+COMMIT;
+
+BEGIN \;
+UPDATE test SET b = '222' WHERE a = 2 \;
+COMMIT ;
+
+UPDATE test SET b = '333' WHERE a = 3 \;
+UPDATE test SET b = '444' WHERE a = 4 ;
+
+BEGIN \;
+UPDATE test SET b = '555' WHERE a = 5 \;
+UPDATE test SET b = '666' WHERE a = 6 \;
+COMMIT ;
+
+-- SELECT with constants
+SELECT * FROM test WHERE a > 5 ORDER BY a ;
+SELECT *
+  FROM test
+  WHERE a > 9
+  ORDER BY a ;
+
+-- SELECT without constants
+SELECT * FROM test ORDER BY a;
+
+SELECT query, calls, rows FROM pg_stat_statements ORDER BY rows, query;
+
+--
+--
+-- pg_stat_statements.track = none
+--
+SET pg_stat_statements.track = 'none';
+SELECT pg_stat_statements_reset();
+SELECT 1 AS "one";
+SELECT 1 + 1 AS "two";
+SELECT query, calls, rows FROM pg_stat_statements ORDER BY rows, query;
+
+--
+--
+-- pg_stat_statements.track = top
+--
+SELECT pg_stat_statements_reset();
+SET pg_stat_statements.track = 'top';
+
+DO LANGUAGE plpgsql $$
+BEGIN
+  -- this is a SELECT
+  PERFORM 'hello world'::TEXT;
+END;
+$$;
+
+-- PL/pgSQL function
+CREATE FUNCTION PLUS_TWO(i INTEGER) RETURNS INTEGER AS $$
+DECLARE
+  r INTEGER;
+BEGIN
+  SELECT (i + 1 + 1.0)::INTEGER INTO r;
+  RETURN r;
+END; $$ LANGUAGE plpgsql;
+
+SELECT PLUS_TWO(3);
+SELECT PLUS_TWO(7);
+
+-- SQL function
+CREATE FUNCTION PLUS_ONE(i INTEGER) RETURNS INTEGER AS
+$$ SELECT (i + 1.0)::INTEGER $$ LANGUAGE SQL;
+
+SELECT PLUS_ONE(8);
+SELECT PLUS_ONE(10);
+
+DROP FUNCTION PLUS_ONE(INTEGER);
+DROP FUNCTION PLUS_TWO(INTEGER);
+
+SELECT query, calls, rows FROM pg_stat_statements ORDER BY rows, query;
+
+--
+--
+-- pg_stat_statements.track = all
+--
+SELECT pg_stat_statements_reset();
+SET pg_stat_statements.track = 'all';
+
+-- recreate PL/pgSQL function
+CREATE FUNCTION PLUS_TWO(i INTEGER) RETURNS INTEGER AS $$
+DECLARE
+  r INTEGER;
+BEGIN
+  SELECT (i + 1 + 1.0)::INTEGER INTO r;
+  RETURN r;
+END; $$ LANGUAGE plpgsql;
+
+SELECT PLUS_TWO(-1);
+SELECT PLUS_TWO(2);
+
+-- SQL function nesting
+CREATE FUNCTION PLUS_ONE(i INTEGER) RETURNS INTEGER AS
+$$ SELECT (i + 1.0)::INTEGER $$ LANGUAGE SQL;
+
+SELECT PLUS_ONE(3);
+SELECT PLUS_ONE(1);
+
+-- bug? PLUS_ONE expansion is missing
+SELECT query, calls, rows FROM pg_stat_statements ORDER BY rows, query;
+
+--
+--
+-- utility commands
+--
+SELECT pg_stat_statements_reset();
+SET pg_stat_statements.track_utility = TRUE;
+
+SELECT 1;
+CREATE INDEX test_b ON test(b);
+DROP TABLE test \;
+DROP TABLE IF EXISTS test \;
+DROP FUNCTION PLUS_ONE(INTEGER);
+DROP TABLE IF EXISTS test \;
+DROP TABLE IF EXISTS test \;
+DROP FUNCTION IF EXISTS PLUS_ONE(INTEGER);
+DROP FUNCTION PLUS_TWO(INTEGER);
 
-SELECT query, calls, rows from pg_stat_statements ORDER BY rows;
+SELECT query, calls, rows FROM pg_stat_statements ORDER BY rows, query;
 
-DROP TABLE test;
 
 DROP EXTENSION pg_stat_statements;
diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c
index 7902d43..e3f3030 100644
--- a/src/backend/commands/tablespace.c
+++ b/src/backend/commands/tablespace.c
@@ -257,7 +257,7 @@ CreateTableSpace(CreateTableSpaceStmt *stmt)
 		ownerId = GetUserId();
 
 	/* Unix-ify the offered path, and strip any trailing slashes */
-	location = pstrdup(stmt->location);
+	location = pstrdup(stmt->location_dir);
 	canonicalize_path(location);
 
 	/* disallow quotes, else CREATE DATABASE would be at risk */
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 6955298..8a6afa8 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -79,6 +79,8 @@ _copyPlannedStmt(const PlannedStmt *from)
 {
 	PlannedStmt *newnode = makeNode(PlannedStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_SCALAR_FIELD(commandType);
 	COPY_SCALAR_FIELD(queryId);
 	COPY_SCALAR_FIELD(hasReturning);
@@ -2734,6 +2736,8 @@ _copyQuery(const Query *from)
 {
 	Query	   *newnode = makeNode(Query);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_SCALAR_FIELD(commandType);
 	COPY_SCALAR_FIELD(querySource);
 	COPY_SCALAR_FIELD(queryId);
@@ -2776,6 +2780,8 @@ _copyInsertStmt(const InsertStmt *from)
 {
 	InsertStmt *newnode = makeNode(InsertStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_NODE_FIELD(relation);
 	COPY_NODE_FIELD(cols);
 	COPY_NODE_FIELD(selectStmt);
@@ -2791,6 +2797,8 @@ _copyDeleteStmt(const DeleteStmt *from)
 {
 	DeleteStmt *newnode = makeNode(DeleteStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_NODE_FIELD(relation);
 	COPY_NODE_FIELD(usingClause);
 	COPY_NODE_FIELD(whereClause);
@@ -2805,6 +2813,8 @@ _copyUpdateStmt(const UpdateStmt *from)
 {
 	UpdateStmt *newnode = makeNode(UpdateStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_NODE_FIELD(relation);
 	COPY_NODE_FIELD(targetList);
 	COPY_NODE_FIELD(whereClause);
@@ -2820,6 +2830,8 @@ _copySelectStmt(const SelectStmt *from)
 {
 	SelectStmt *newnode = makeNode(SelectStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_NODE_FIELD(distinctClause);
 	COPY_NODE_FIELD(intoClause);
 	COPY_NODE_FIELD(targetList);
@@ -2847,6 +2859,8 @@ _copySetOperationStmt(const SetOperationStmt *from)
 {
 	SetOperationStmt *newnode = makeNode(SetOperationStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_SCALAR_FIELD(op);
 	COPY_SCALAR_FIELD(all);
 	COPY_NODE_FIELD(larg);
@@ -2864,6 +2878,8 @@ _copyAlterTableStmt(const AlterTableStmt *from)
 {
 	AlterTableStmt *newnode = makeNode(AlterTableStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_NODE_FIELD(relation);
 	COPY_NODE_FIELD(cmds);
 	COPY_SCALAR_FIELD(relkind);
@@ -2892,6 +2908,8 @@ _copyAlterDomainStmt(const AlterDomainStmt *from)
 {
 	AlterDomainStmt *newnode = makeNode(AlterDomainStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_SCALAR_FIELD(subtype);
 	COPY_NODE_FIELD(typeName);
 	COPY_STRING_FIELD(name);
@@ -2907,6 +2925,8 @@ _copyGrantStmt(const GrantStmt *from)
 {
 	GrantStmt  *newnode = makeNode(GrantStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_SCALAR_FIELD(is_grant);
 	COPY_SCALAR_FIELD(targtype);
 	COPY_SCALAR_FIELD(objtype);
@@ -2946,6 +2966,8 @@ _copyGrantRoleStmt(const GrantRoleStmt *from)
 {
 	GrantRoleStmt *newnode = makeNode(GrantRoleStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_NODE_FIELD(granted_roles);
 	COPY_NODE_FIELD(grantee_roles);
 	COPY_SCALAR_FIELD(is_grant);
@@ -2961,6 +2983,8 @@ _copyAlterDefaultPrivilegesStmt(const AlterDefaultPrivilegesStmt *from)
 {
 	AlterDefaultPrivilegesStmt *newnode = makeNode(AlterDefaultPrivilegesStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_NODE_FIELD(options);
 	COPY_NODE_FIELD(action);
 
@@ -2972,6 +2996,8 @@ _copyDeclareCursorStmt(const DeclareCursorStmt *from)
 {
 	DeclareCursorStmt *newnode = makeNode(DeclareCursorStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_STRING_FIELD(portalname);
 	COPY_SCALAR_FIELD(options);
 	COPY_NODE_FIELD(query);
@@ -2984,6 +3010,8 @@ _copyClosePortalStmt(const ClosePortalStmt *from)
 {
 	ClosePortalStmt *newnode = makeNode(ClosePortalStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_STRING_FIELD(portalname);
 
 	return newnode;
@@ -2994,6 +3022,8 @@ _copyClusterStmt(const ClusterStmt *from)
 {
 	ClusterStmt *newnode = makeNode(ClusterStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_NODE_FIELD(relation);
 	COPY_STRING_FIELD(indexname);
 	COPY_SCALAR_FIELD(verbose);
@@ -3006,6 +3036,8 @@ _copyCopyStmt(const CopyStmt *from)
 {
 	CopyStmt   *newnode = makeNode(CopyStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_NODE_FIELD(relation);
 	COPY_NODE_FIELD(query);
 	COPY_NODE_FIELD(attlist);
@@ -3026,6 +3058,8 @@ _copyCopyStmt(const CopyStmt *from)
 static void
 CopyCreateStmtFields(const CreateStmt *from, CreateStmt *newnode)
 {
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_NODE_FIELD(relation);
 	COPY_NODE_FIELD(tableElts);
 	COPY_NODE_FIELD(inhRelations);
@@ -3065,6 +3099,8 @@ _copyDefineStmt(const DefineStmt *from)
 {
 	DefineStmt *newnode = makeNode(DefineStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_SCALAR_FIELD(kind);
 	COPY_SCALAR_FIELD(oldstyle);
 	COPY_NODE_FIELD(defnames);
@@ -3079,6 +3115,8 @@ _copyDropStmt(const DropStmt *from)
 {
 	DropStmt   *newnode = makeNode(DropStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_NODE_FIELD(objects);
 	COPY_NODE_FIELD(arguments);
 	COPY_SCALAR_FIELD(removeType);
@@ -3094,6 +3132,8 @@ _copyTruncateStmt(const TruncateStmt *from)
 {
 	TruncateStmt *newnode = makeNode(TruncateStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_NODE_FIELD(relations);
 	COPY_SCALAR_FIELD(restart_seqs);
 	COPY_SCALAR_FIELD(behavior);
@@ -3106,6 +3146,8 @@ _copyCommentStmt(const CommentStmt *from)
 {
 	CommentStmt *newnode = makeNode(CommentStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_SCALAR_FIELD(objtype);
 	COPY_NODE_FIELD(objname);
 	COPY_NODE_FIELD(objargs);
@@ -3119,6 +3161,8 @@ _copySecLabelStmt(const SecLabelStmt *from)
 {
 	SecLabelStmt *newnode = makeNode(SecLabelStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_SCALAR_FIELD(objtype);
 	COPY_NODE_FIELD(objname);
 	COPY_NODE_FIELD(objargs);
@@ -3133,6 +3177,8 @@ _copyFetchStmt(const FetchStmt *from)
 {
 	FetchStmt  *newnode = makeNode(FetchStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_SCALAR_FIELD(direction);
 	COPY_SCALAR_FIELD(howMany);
 	COPY_STRING_FIELD(portalname);
@@ -3146,6 +3192,8 @@ _copyIndexStmt(const IndexStmt *from)
 {
 	IndexStmt  *newnode = makeNode(IndexStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_STRING_FIELD(idxname);
 	COPY_NODE_FIELD(relation);
 	COPY_STRING_FIELD(accessMethod);
@@ -3174,6 +3222,8 @@ _copyCreateFunctionStmt(const CreateFunctionStmt *from)
 {
 	CreateFunctionStmt *newnode = makeNode(CreateFunctionStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_SCALAR_FIELD(replace);
 	COPY_NODE_FIELD(funcname);
 	COPY_NODE_FIELD(parameters);
@@ -3202,6 +3252,8 @@ _copyAlterFunctionStmt(const AlterFunctionStmt *from)
 {
 	AlterFunctionStmt *newnode = makeNode(AlterFunctionStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_NODE_FIELD(func);
 	COPY_NODE_FIELD(actions);
 
@@ -3213,6 +3265,8 @@ _copyDoStmt(const DoStmt *from)
 {
 	DoStmt	   *newnode = makeNode(DoStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_NODE_FIELD(args);
 
 	return newnode;
@@ -3223,6 +3277,8 @@ _copyRenameStmt(const RenameStmt *from)
 {
 	RenameStmt *newnode = makeNode(RenameStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_SCALAR_FIELD(renameType);
 	COPY_SCALAR_FIELD(relationType);
 	COPY_NODE_FIELD(relation);
@@ -3241,6 +3297,8 @@ _copyAlterObjectDependsStmt(const AlterObjectDependsStmt *from)
 {
 	AlterObjectDependsStmt *newnode = makeNode(AlterObjectDependsStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_SCALAR_FIELD(objectType);
 	COPY_NODE_FIELD(relation);
 	COPY_NODE_FIELD(objname);
@@ -3255,6 +3313,8 @@ _copyAlterObjectSchemaStmt(const AlterObjectSchemaStmt *from)
 {
 	AlterObjectSchemaStmt *newnode = makeNode(AlterObjectSchemaStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_SCALAR_FIELD(objectType);
 	COPY_NODE_FIELD(relation);
 	COPY_NODE_FIELD(object);
@@ -3270,6 +3330,8 @@ _copyAlterOwnerStmt(const AlterOwnerStmt *from)
 {
 	AlterOwnerStmt *newnode = makeNode(AlterOwnerStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_SCALAR_FIELD(objectType);
 	COPY_NODE_FIELD(relation);
 	COPY_NODE_FIELD(object);
@@ -3284,6 +3346,8 @@ _copyAlterOperatorStmt(const AlterOperatorStmt *from)
 {
 	AlterOperatorStmt *newnode = makeNode(AlterOperatorStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_NODE_FIELD(opername);
 	COPY_NODE_FIELD(operargs);
 	COPY_NODE_FIELD(options);
@@ -3296,6 +3360,8 @@ _copyRuleStmt(const RuleStmt *from)
 {
 	RuleStmt   *newnode = makeNode(RuleStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_NODE_FIELD(relation);
 	COPY_STRING_FIELD(rulename);
 	COPY_NODE_FIELD(whereClause);
@@ -3312,6 +3378,8 @@ _copyNotifyStmt(const NotifyStmt *from)
 {
 	NotifyStmt *newnode = makeNode(NotifyStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_STRING_FIELD(conditionname);
 	COPY_STRING_FIELD(payload);
 
@@ -3323,6 +3391,8 @@ _copyListenStmt(const ListenStmt *from)
 {
 	ListenStmt *newnode = makeNode(ListenStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_STRING_FIELD(conditionname);
 
 	return newnode;
@@ -3333,6 +3403,8 @@ _copyUnlistenStmt(const UnlistenStmt *from)
 {
 	UnlistenStmt *newnode = makeNode(UnlistenStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_STRING_FIELD(conditionname);
 
 	return newnode;
@@ -3343,6 +3415,8 @@ _copyTransactionStmt(const TransactionStmt *from)
 {
 	TransactionStmt *newnode = makeNode(TransactionStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_SCALAR_FIELD(kind);
 	COPY_NODE_FIELD(options);
 	COPY_STRING_FIELD(gid);
@@ -3355,6 +3429,8 @@ _copyCompositeTypeStmt(const CompositeTypeStmt *from)
 {
 	CompositeTypeStmt *newnode = makeNode(CompositeTypeStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_NODE_FIELD(typevar);
 	COPY_NODE_FIELD(coldeflist);
 
@@ -3366,6 +3442,8 @@ _copyCreateEnumStmt(const CreateEnumStmt *from)
 {
 	CreateEnumStmt *newnode = makeNode(CreateEnumStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_NODE_FIELD(typeName);
 	COPY_NODE_FIELD(vals);
 
@@ -3377,6 +3455,8 @@ _copyCreateRangeStmt(const CreateRangeStmt *from)
 {
 	CreateRangeStmt *newnode = makeNode(CreateRangeStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_NODE_FIELD(typeName);
 	COPY_NODE_FIELD(params);
 
@@ -3388,6 +3468,8 @@ _copyAlterEnumStmt(const AlterEnumStmt *from)
 {
 	AlterEnumStmt *newnode = makeNode(AlterEnumStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_NODE_FIELD(typeName);
 	COPY_STRING_FIELD(oldVal);
 	COPY_STRING_FIELD(newVal);
@@ -3403,6 +3485,8 @@ _copyViewStmt(const ViewStmt *from)
 {
 	ViewStmt   *newnode = makeNode(ViewStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_NODE_FIELD(view);
 	COPY_NODE_FIELD(aliases);
 	COPY_NODE_FIELD(query);
@@ -3418,6 +3502,8 @@ _copyLoadStmt(const LoadStmt *from)
 {
 	LoadStmt   *newnode = makeNode(LoadStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_STRING_FIELD(filename);
 
 	return newnode;
@@ -3428,6 +3514,8 @@ _copyCreateDomainStmt(const CreateDomainStmt *from)
 {
 	CreateDomainStmt *newnode = makeNode(CreateDomainStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_NODE_FIELD(domainname);
 	COPY_NODE_FIELD(typeName);
 	COPY_NODE_FIELD(collClause);
@@ -3441,6 +3529,8 @@ _copyCreateOpClassStmt(const CreateOpClassStmt *from)
 {
 	CreateOpClassStmt *newnode = makeNode(CreateOpClassStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_NODE_FIELD(opclassname);
 	COPY_NODE_FIELD(opfamilyname);
 	COPY_STRING_FIELD(amname);
@@ -3472,6 +3562,8 @@ _copyCreateOpFamilyStmt(const CreateOpFamilyStmt *from)
 {
 	CreateOpFamilyStmt *newnode = makeNode(CreateOpFamilyStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_NODE_FIELD(opfamilyname);
 	COPY_STRING_FIELD(amname);
 
@@ -3483,6 +3575,8 @@ _copyAlterOpFamilyStmt(const AlterOpFamilyStmt *from)
 {
 	AlterOpFamilyStmt *newnode = makeNode(AlterOpFamilyStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_NODE_FIELD(opfamilyname);
 	COPY_STRING_FIELD(amname);
 	COPY_SCALAR_FIELD(isDrop);
@@ -3496,6 +3590,8 @@ _copyCreatedbStmt(const CreatedbStmt *from)
 {
 	CreatedbStmt *newnode = makeNode(CreatedbStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_STRING_FIELD(dbname);
 	COPY_NODE_FIELD(options);
 
@@ -3507,6 +3603,8 @@ _copyAlterDatabaseStmt(const AlterDatabaseStmt *from)
 {
 	AlterDatabaseStmt *newnode = makeNode(AlterDatabaseStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_STRING_FIELD(dbname);
 	COPY_NODE_FIELD(options);
 
@@ -3518,6 +3616,8 @@ _copyAlterDatabaseSetStmt(const AlterDatabaseSetStmt *from)
 {
 	AlterDatabaseSetStmt *newnode = makeNode(AlterDatabaseSetStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_STRING_FIELD(dbname);
 	COPY_NODE_FIELD(setstmt);
 
@@ -3529,6 +3629,8 @@ _copyDropdbStmt(const DropdbStmt *from)
 {
 	DropdbStmt *newnode = makeNode(DropdbStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_STRING_FIELD(dbname);
 	COPY_SCALAR_FIELD(missing_ok);
 
@@ -3540,6 +3642,8 @@ _copyVacuumStmt(const VacuumStmt *from)
 {
 	VacuumStmt *newnode = makeNode(VacuumStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_SCALAR_FIELD(options);
 	COPY_NODE_FIELD(relation);
 	COPY_NODE_FIELD(va_cols);
@@ -3552,6 +3656,8 @@ _copyExplainStmt(const ExplainStmt *from)
 {
 	ExplainStmt *newnode = makeNode(ExplainStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_NODE_FIELD(query);
 	COPY_NODE_FIELD(options);
 
@@ -3563,6 +3669,8 @@ _copyCreateTableAsStmt(const CreateTableAsStmt *from)
 {
 	CreateTableAsStmt *newnode = makeNode(CreateTableAsStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_NODE_FIELD(query);
 	COPY_NODE_FIELD(into);
 	COPY_SCALAR_FIELD(relkind);
@@ -3577,6 +3685,8 @@ _copyRefreshMatViewStmt(const RefreshMatViewStmt *from)
 {
 	RefreshMatViewStmt *newnode = makeNode(RefreshMatViewStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_SCALAR_FIELD(concurrent);
 	COPY_SCALAR_FIELD(skipData);
 	COPY_NODE_FIELD(relation);
@@ -3589,6 +3699,8 @@ _copyReplicaIdentityStmt(const ReplicaIdentityStmt *from)
 {
 	ReplicaIdentityStmt *newnode = makeNode(ReplicaIdentityStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_SCALAR_FIELD(identity_type);
 	COPY_STRING_FIELD(name);
 
@@ -3600,6 +3712,8 @@ _copyAlterSystemStmt(const AlterSystemStmt *from)
 {
 	AlterSystemStmt *newnode = makeNode(AlterSystemStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_NODE_FIELD(setstmt);
 
 	return newnode;
@@ -3610,6 +3724,8 @@ _copyCreateSeqStmt(const CreateSeqStmt *from)
 {
 	CreateSeqStmt *newnode = makeNode(CreateSeqStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_NODE_FIELD(sequence);
 	COPY_NODE_FIELD(options);
 	COPY_SCALAR_FIELD(ownerId);
@@ -3623,6 +3739,8 @@ _copyAlterSeqStmt(const AlterSeqStmt *from)
 {
 	AlterSeqStmt *newnode = makeNode(AlterSeqStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_NODE_FIELD(sequence);
 	COPY_NODE_FIELD(options);
 	COPY_SCALAR_FIELD(missing_ok);
@@ -3635,6 +3753,8 @@ _copyVariableSetStmt(const VariableSetStmt *from)
 {
 	VariableSetStmt *newnode = makeNode(VariableSetStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_SCALAR_FIELD(kind);
 	COPY_STRING_FIELD(name);
 	COPY_NODE_FIELD(args);
@@ -3648,6 +3768,8 @@ _copyVariableShowStmt(const VariableShowStmt *from)
 {
 	VariableShowStmt *newnode = makeNode(VariableShowStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_STRING_FIELD(name);
 
 	return newnode;
@@ -3658,6 +3780,8 @@ _copyDiscardStmt(const DiscardStmt *from)
 {
 	DiscardStmt *newnode = makeNode(DiscardStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_SCALAR_FIELD(target);
 
 	return newnode;
@@ -3668,9 +3792,11 @@ _copyCreateTableSpaceStmt(const CreateTableSpaceStmt *from)
 {
 	CreateTableSpaceStmt *newnode = makeNode(CreateTableSpaceStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_STRING_FIELD(tablespacename);
 	COPY_NODE_FIELD(owner);
-	COPY_STRING_FIELD(location);
+	COPY_STRING_FIELD(location_dir);
 	COPY_NODE_FIELD(options);
 
 	return newnode;
@@ -3681,6 +3807,8 @@ _copyDropTableSpaceStmt(const DropTableSpaceStmt *from)
 {
 	DropTableSpaceStmt *newnode = makeNode(DropTableSpaceStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_STRING_FIELD(tablespacename);
 	COPY_SCALAR_FIELD(missing_ok);
 
@@ -3692,6 +3820,8 @@ _copyAlterTableSpaceOptionsStmt(const AlterTableSpaceOptionsStmt *from)
 {
 	AlterTableSpaceOptionsStmt *newnode = makeNode(AlterTableSpaceOptionsStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_STRING_FIELD(tablespacename);
 	COPY_NODE_FIELD(options);
 	COPY_SCALAR_FIELD(isReset);
@@ -3704,6 +3834,8 @@ _copyAlterTableMoveAllStmt(const AlterTableMoveAllStmt *from)
 {
 	AlterTableMoveAllStmt *newnode = makeNode(AlterTableMoveAllStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_STRING_FIELD(orig_tablespacename);
 	COPY_SCALAR_FIELD(objtype);
 	COPY_NODE_FIELD(roles);
@@ -3718,6 +3850,8 @@ _copyCreateExtensionStmt(const CreateExtensionStmt *from)
 {
 	CreateExtensionStmt *newnode = makeNode(CreateExtensionStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_STRING_FIELD(extname);
 	COPY_SCALAR_FIELD(if_not_exists);
 	COPY_NODE_FIELD(options);
@@ -3730,6 +3864,8 @@ _copyAlterExtensionStmt(const AlterExtensionStmt *from)
 {
 	AlterExtensionStmt *newnode = makeNode(AlterExtensionStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_STRING_FIELD(extname);
 	COPY_NODE_FIELD(options);
 
@@ -3741,6 +3877,8 @@ _copyAlterExtensionContentsStmt(const AlterExtensionContentsStmt *from)
 {
 	AlterExtensionContentsStmt *newnode = makeNode(AlterExtensionContentsStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_STRING_FIELD(extname);
 	COPY_SCALAR_FIELD(action);
 	COPY_SCALAR_FIELD(objtype);
@@ -3755,6 +3893,8 @@ _copyCreateFdwStmt(const CreateFdwStmt *from)
 {
 	CreateFdwStmt *newnode = makeNode(CreateFdwStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_STRING_FIELD(fdwname);
 	COPY_NODE_FIELD(func_options);
 	COPY_NODE_FIELD(options);
@@ -3767,6 +3907,8 @@ _copyAlterFdwStmt(const AlterFdwStmt *from)
 {
 	AlterFdwStmt *newnode = makeNode(AlterFdwStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_STRING_FIELD(fdwname);
 	COPY_NODE_FIELD(func_options);
 	COPY_NODE_FIELD(options);
@@ -3779,6 +3921,8 @@ _copyCreateForeignServerStmt(const CreateForeignServerStmt *from)
 {
 	CreateForeignServerStmt *newnode = makeNode(CreateForeignServerStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_STRING_FIELD(servername);
 	COPY_STRING_FIELD(servertype);
 	COPY_STRING_FIELD(version);
@@ -3793,6 +3937,8 @@ _copyAlterForeignServerStmt(const AlterForeignServerStmt *from)
 {
 	AlterForeignServerStmt *newnode = makeNode(AlterForeignServerStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_STRING_FIELD(servername);
 	COPY_STRING_FIELD(version);
 	COPY_NODE_FIELD(options);
@@ -3806,6 +3952,8 @@ _copyCreateUserMappingStmt(const CreateUserMappingStmt *from)
 {
 	CreateUserMappingStmt *newnode = makeNode(CreateUserMappingStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_NODE_FIELD(user);
 	COPY_STRING_FIELD(servername);
 	COPY_NODE_FIELD(options);
@@ -3818,6 +3966,8 @@ _copyAlterUserMappingStmt(const AlterUserMappingStmt *from)
 {
 	AlterUserMappingStmt *newnode = makeNode(AlterUserMappingStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_NODE_FIELD(user);
 	COPY_STRING_FIELD(servername);
 	COPY_NODE_FIELD(options);
@@ -3830,6 +3980,8 @@ _copyDropUserMappingStmt(const DropUserMappingStmt *from)
 {
 	DropUserMappingStmt *newnode = makeNode(DropUserMappingStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_NODE_FIELD(user);
 	COPY_STRING_FIELD(servername);
 	COPY_SCALAR_FIELD(missing_ok);
@@ -3855,6 +4007,8 @@ _copyImportForeignSchemaStmt(const ImportForeignSchemaStmt *from)
 {
 	ImportForeignSchemaStmt *newnode = makeNode(ImportForeignSchemaStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_STRING_FIELD(server_name);
 	COPY_STRING_FIELD(remote_schema);
 	COPY_STRING_FIELD(local_schema);
@@ -3870,6 +4024,8 @@ _copyCreateTransformStmt(const CreateTransformStmt *from)
 {
 	CreateTransformStmt *newnode = makeNode(CreateTransformStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_SCALAR_FIELD(replace);
 	COPY_NODE_FIELD(type_name);
 	COPY_STRING_FIELD(lang);
@@ -3884,6 +4040,8 @@ _copyCreateAmStmt(const CreateAmStmt *from)
 {
 	CreateAmStmt *newnode = makeNode(CreateAmStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_STRING_FIELD(amname);
 	COPY_NODE_FIELD(handler_name);
 	COPY_SCALAR_FIELD(amtype);
@@ -3896,6 +4054,8 @@ _copyCreateTrigStmt(const CreateTrigStmt *from)
 {
 	CreateTrigStmt *newnode = makeNode(CreateTrigStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_STRING_FIELD(trigname);
 	COPY_NODE_FIELD(relation);
 	COPY_NODE_FIELD(funcname);
@@ -3919,6 +4079,8 @@ _copyCreateEventTrigStmt(const CreateEventTrigStmt *from)
 {
 	CreateEventTrigStmt *newnode = makeNode(CreateEventTrigStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_STRING_FIELD(trigname);
 	COPY_STRING_FIELD(eventname);
 	COPY_NODE_FIELD(whenclause);
@@ -3932,6 +4094,8 @@ _copyAlterEventTrigStmt(const AlterEventTrigStmt *from)
 {
 	AlterEventTrigStmt *newnode = makeNode(AlterEventTrigStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_STRING_FIELD(trigname);
 	COPY_SCALAR_FIELD(tgenabled);
 
@@ -3943,6 +4107,8 @@ _copyCreatePLangStmt(const CreatePLangStmt *from)
 {
 	CreatePLangStmt *newnode = makeNode(CreatePLangStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_SCALAR_FIELD(replace);
 	COPY_STRING_FIELD(plname);
 	COPY_NODE_FIELD(plhandler);
@@ -3958,6 +4124,8 @@ _copyCreateRoleStmt(const CreateRoleStmt *from)
 {
 	CreateRoleStmt *newnode = makeNode(CreateRoleStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_SCALAR_FIELD(stmt_type);
 	COPY_STRING_FIELD(role);
 	COPY_NODE_FIELD(options);
@@ -3970,6 +4138,8 @@ _copyAlterRoleStmt(const AlterRoleStmt *from)
 {
 	AlterRoleStmt *newnode = makeNode(AlterRoleStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_NODE_FIELD(role);
 	COPY_NODE_FIELD(options);
 	COPY_SCALAR_FIELD(action);
@@ -3982,6 +4152,8 @@ _copyAlterRoleSetStmt(const AlterRoleSetStmt *from)
 {
 	AlterRoleSetStmt *newnode = makeNode(AlterRoleSetStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_NODE_FIELD(role);
 	COPY_STRING_FIELD(database);
 	COPY_NODE_FIELD(setstmt);
@@ -3994,6 +4166,8 @@ _copyDropRoleStmt(const DropRoleStmt *from)
 {
 	DropRoleStmt *newnode = makeNode(DropRoleStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_NODE_FIELD(roles);
 	COPY_SCALAR_FIELD(missing_ok);
 
@@ -4005,6 +4179,8 @@ _copyLockStmt(const LockStmt *from)
 {
 	LockStmt   *newnode = makeNode(LockStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_NODE_FIELD(relations);
 	COPY_SCALAR_FIELD(mode);
 	COPY_SCALAR_FIELD(nowait);
@@ -4017,6 +4193,8 @@ _copyConstraintsSetStmt(const ConstraintsSetStmt *from)
 {
 	ConstraintsSetStmt *newnode = makeNode(ConstraintsSetStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_NODE_FIELD(constraints);
 	COPY_SCALAR_FIELD(deferred);
 
@@ -4028,6 +4206,8 @@ _copyReindexStmt(const ReindexStmt *from)
 {
 	ReindexStmt *newnode = makeNode(ReindexStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_SCALAR_FIELD(kind);
 	COPY_NODE_FIELD(relation);
 	COPY_STRING_FIELD(name);
@@ -4041,6 +4221,8 @@ _copyCreateSchemaStmt(const CreateSchemaStmt *from)
 {
 	CreateSchemaStmt *newnode = makeNode(CreateSchemaStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_STRING_FIELD(schemaname);
 	COPY_NODE_FIELD(authrole);
 	COPY_NODE_FIELD(schemaElts);
@@ -4054,6 +4236,8 @@ _copyCreateConversionStmt(const CreateConversionStmt *from)
 {
 	CreateConversionStmt *newnode = makeNode(CreateConversionStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_NODE_FIELD(conversion_name);
 	COPY_STRING_FIELD(for_encoding_name);
 	COPY_STRING_FIELD(to_encoding_name);
@@ -4068,6 +4252,8 @@ _copyCreateCastStmt(const CreateCastStmt *from)
 {
 	CreateCastStmt *newnode = makeNode(CreateCastStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_NODE_FIELD(sourcetype);
 	COPY_NODE_FIELD(targettype);
 	COPY_NODE_FIELD(func);
@@ -4082,6 +4268,8 @@ _copyPrepareStmt(const PrepareStmt *from)
 {
 	PrepareStmt *newnode = makeNode(PrepareStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_STRING_FIELD(name);
 	COPY_NODE_FIELD(argtypes);
 	COPY_NODE_FIELD(query);
@@ -4094,6 +4282,8 @@ _copyExecuteStmt(const ExecuteStmt *from)
 {
 	ExecuteStmt *newnode = makeNode(ExecuteStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_STRING_FIELD(name);
 	COPY_NODE_FIELD(params);
 
@@ -4105,6 +4295,8 @@ _copyDeallocateStmt(const DeallocateStmt *from)
 {
 	DeallocateStmt *newnode = makeNode(DeallocateStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_STRING_FIELD(name);
 
 	return newnode;
@@ -4115,6 +4307,8 @@ _copyDropOwnedStmt(const DropOwnedStmt *from)
 {
 	DropOwnedStmt *newnode = makeNode(DropOwnedStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_NODE_FIELD(roles);
 	COPY_SCALAR_FIELD(behavior);
 
@@ -4126,6 +4320,8 @@ _copyReassignOwnedStmt(const ReassignOwnedStmt *from)
 {
 	ReassignOwnedStmt *newnode = makeNode(ReassignOwnedStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_NODE_FIELD(roles);
 	COPY_NODE_FIELD(newrole);
 
@@ -4137,6 +4333,8 @@ _copyAlterTSDictionaryStmt(const AlterTSDictionaryStmt *from)
 {
 	AlterTSDictionaryStmt *newnode = makeNode(AlterTSDictionaryStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_NODE_FIELD(dictname);
 	COPY_NODE_FIELD(options);
 
@@ -4148,6 +4346,8 @@ _copyAlterTSConfigurationStmt(const AlterTSConfigurationStmt *from)
 {
 	AlterTSConfigurationStmt *newnode = makeNode(AlterTSConfigurationStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_SCALAR_FIELD(kind);
 	COPY_NODE_FIELD(cfgname);
 	COPY_NODE_FIELD(tokentype);
@@ -4164,6 +4364,8 @@ _copyCreatePolicyStmt(const CreatePolicyStmt *from)
 {
 	CreatePolicyStmt *newnode = makeNode(CreatePolicyStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_STRING_FIELD(policy_name);
 	COPY_NODE_FIELD(table);
 	COPY_STRING_FIELD(cmd_name);
@@ -4180,6 +4382,8 @@ _copyAlterPolicyStmt(const AlterPolicyStmt *from)
 {
 	AlterPolicyStmt *newnode = makeNode(AlterPolicyStmt);
 
+	COPY_SCALAR_FIELD(location);
+	COPY_SCALAR_FIELD(length);
 	COPY_STRING_FIELD(policy_name);
 	COPY_NODE_FIELD(table);
 	COPY_NODE_FIELD(roles);
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 548a2aa..8916028 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -913,6 +913,8 @@ _equalExtensibleNode(const ExtensibleNode *a, const ExtensibleNode *b)
 static bool
 _equalQuery(const Query *a, const Query *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_SCALAR_FIELD(commandType);
 	COMPARE_SCALAR_FIELD(querySource);
 	/* we intentionally ignore queryId, since it might not be set */
@@ -953,6 +955,8 @@ _equalQuery(const Query *a, const Query *b)
 static bool
 _equalInsertStmt(const InsertStmt *a, const InsertStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_NODE_FIELD(relation);
 	COMPARE_NODE_FIELD(cols);
 	COMPARE_NODE_FIELD(selectStmt);
@@ -966,6 +970,8 @@ _equalInsertStmt(const InsertStmt *a, const InsertStmt *b)
 static bool
 _equalDeleteStmt(const DeleteStmt *a, const DeleteStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_NODE_FIELD(relation);
 	COMPARE_NODE_FIELD(usingClause);
 	COMPARE_NODE_FIELD(whereClause);
@@ -978,6 +984,8 @@ _equalDeleteStmt(const DeleteStmt *a, const DeleteStmt *b)
 static bool
 _equalUpdateStmt(const UpdateStmt *a, const UpdateStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_NODE_FIELD(relation);
 	COMPARE_NODE_FIELD(targetList);
 	COMPARE_NODE_FIELD(whereClause);
@@ -991,6 +999,8 @@ _equalUpdateStmt(const UpdateStmt *a, const UpdateStmt *b)
 static bool
 _equalSelectStmt(const SelectStmt *a, const SelectStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_NODE_FIELD(distinctClause);
 	COMPARE_NODE_FIELD(intoClause);
 	COMPARE_NODE_FIELD(targetList);
@@ -1016,6 +1026,8 @@ _equalSelectStmt(const SelectStmt *a, const SelectStmt *b)
 static bool
 _equalSetOperationStmt(const SetOperationStmt *a, const SetOperationStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_SCALAR_FIELD(op);
 	COMPARE_SCALAR_FIELD(all);
 	COMPARE_NODE_FIELD(larg);
@@ -1031,6 +1043,8 @@ _equalSetOperationStmt(const SetOperationStmt *a, const SetOperationStmt *b)
 static bool
 _equalAlterTableStmt(const AlterTableStmt *a, const AlterTableStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_NODE_FIELD(relation);
 	COMPARE_NODE_FIELD(cmds);
 	COMPARE_SCALAR_FIELD(relkind);
@@ -1055,6 +1069,8 @@ _equalAlterTableCmd(const AlterTableCmd *a, const AlterTableCmd *b)
 static bool
 _equalAlterDomainStmt(const AlterDomainStmt *a, const AlterDomainStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_SCALAR_FIELD(subtype);
 	COMPARE_NODE_FIELD(typeName);
 	COMPARE_STRING_FIELD(name);
@@ -1068,6 +1084,8 @@ _equalAlterDomainStmt(const AlterDomainStmt *a, const AlterDomainStmt *b)
 static bool
 _equalGrantStmt(const GrantStmt *a, const GrantStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_SCALAR_FIELD(is_grant);
 	COMPARE_SCALAR_FIELD(targtype);
 	COMPARE_SCALAR_FIELD(objtype);
@@ -1101,6 +1119,8 @@ _equalAccessPriv(const AccessPriv *a, const AccessPriv *b)
 static bool
 _equalGrantRoleStmt(const GrantRoleStmt *a, const GrantRoleStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_NODE_FIELD(granted_roles);
 	COMPARE_NODE_FIELD(grantee_roles);
 	COMPARE_SCALAR_FIELD(is_grant);
@@ -1114,6 +1134,8 @@ _equalGrantRoleStmt(const GrantRoleStmt *a, const GrantRoleStmt *b)
 static bool
 _equalAlterDefaultPrivilegesStmt(const AlterDefaultPrivilegesStmt *a, const AlterDefaultPrivilegesStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_NODE_FIELD(options);
 	COMPARE_NODE_FIELD(action);
 
@@ -1123,6 +1145,8 @@ _equalAlterDefaultPrivilegesStmt(const AlterDefaultPrivilegesStmt *a, const Alte
 static bool
 _equalDeclareCursorStmt(const DeclareCursorStmt *a, const DeclareCursorStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_STRING_FIELD(portalname);
 	COMPARE_SCALAR_FIELD(options);
 	COMPARE_NODE_FIELD(query);
@@ -1133,6 +1157,8 @@ _equalDeclareCursorStmt(const DeclareCursorStmt *a, const DeclareCursorStmt *b)
 static bool
 _equalClosePortalStmt(const ClosePortalStmt *a, const ClosePortalStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_STRING_FIELD(portalname);
 
 	return true;
@@ -1141,6 +1167,8 @@ _equalClosePortalStmt(const ClosePortalStmt *a, const ClosePortalStmt *b)
 static bool
 _equalClusterStmt(const ClusterStmt *a, const ClusterStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_NODE_FIELD(relation);
 	COMPARE_STRING_FIELD(indexname);
 	COMPARE_SCALAR_FIELD(verbose);
@@ -1151,6 +1179,8 @@ _equalClusterStmt(const ClusterStmt *a, const ClusterStmt *b)
 static bool
 _equalCopyStmt(const CopyStmt *a, const CopyStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_NODE_FIELD(relation);
 	COMPARE_NODE_FIELD(query);
 	COMPARE_NODE_FIELD(attlist);
@@ -1165,6 +1195,8 @@ _equalCopyStmt(const CopyStmt *a, const CopyStmt *b)
 static bool
 _equalCreateStmt(const CreateStmt *a, const CreateStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_NODE_FIELD(relation);
 	COMPARE_NODE_FIELD(tableElts);
 	COMPARE_NODE_FIELD(inhRelations);
@@ -1192,6 +1224,8 @@ _equalTableLikeClause(const TableLikeClause *a, const TableLikeClause *b)
 static bool
 _equalDefineStmt(const DefineStmt *a, const DefineStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_SCALAR_FIELD(kind);
 	COMPARE_SCALAR_FIELD(oldstyle);
 	COMPARE_NODE_FIELD(defnames);
@@ -1204,6 +1238,8 @@ _equalDefineStmt(const DefineStmt *a, const DefineStmt *b)
 static bool
 _equalDropStmt(const DropStmt *a, const DropStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_NODE_FIELD(objects);
 	COMPARE_NODE_FIELD(arguments);
 	COMPARE_SCALAR_FIELD(removeType);
@@ -1217,6 +1253,8 @@ _equalDropStmt(const DropStmt *a, const DropStmt *b)
 static bool
 _equalTruncateStmt(const TruncateStmt *a, const TruncateStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_NODE_FIELD(relations);
 	COMPARE_SCALAR_FIELD(restart_seqs);
 	COMPARE_SCALAR_FIELD(behavior);
@@ -1227,6 +1265,8 @@ _equalTruncateStmt(const TruncateStmt *a, const TruncateStmt *b)
 static bool
 _equalCommentStmt(const CommentStmt *a, const CommentStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_SCALAR_FIELD(objtype);
 	COMPARE_NODE_FIELD(objname);
 	COMPARE_NODE_FIELD(objargs);
@@ -1238,6 +1278,8 @@ _equalCommentStmt(const CommentStmt *a, const CommentStmt *b)
 static bool
 _equalSecLabelStmt(const SecLabelStmt *a, const SecLabelStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_SCALAR_FIELD(objtype);
 	COMPARE_NODE_FIELD(objname);
 	COMPARE_NODE_FIELD(objargs);
@@ -1250,6 +1292,8 @@ _equalSecLabelStmt(const SecLabelStmt *a, const SecLabelStmt *b)
 static bool
 _equalFetchStmt(const FetchStmt *a, const FetchStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_SCALAR_FIELD(direction);
 	COMPARE_SCALAR_FIELD(howMany);
 	COMPARE_STRING_FIELD(portalname);
@@ -1261,6 +1305,8 @@ _equalFetchStmt(const FetchStmt *a, const FetchStmt *b)
 static bool
 _equalIndexStmt(const IndexStmt *a, const IndexStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_STRING_FIELD(idxname);
 	COMPARE_NODE_FIELD(relation);
 	COMPARE_STRING_FIELD(accessMethod);
@@ -1287,6 +1333,8 @@ _equalIndexStmt(const IndexStmt *a, const IndexStmt *b)
 static bool
 _equalCreateFunctionStmt(const CreateFunctionStmt *a, const CreateFunctionStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_SCALAR_FIELD(replace);
 	COMPARE_NODE_FIELD(funcname);
 	COMPARE_NODE_FIELD(parameters);
@@ -1311,6 +1359,8 @@ _equalFunctionParameter(const FunctionParameter *a, const FunctionParameter *b)
 static bool
 _equalAlterFunctionStmt(const AlterFunctionStmt *a, const AlterFunctionStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_NODE_FIELD(func);
 	COMPARE_NODE_FIELD(actions);
 
@@ -1320,6 +1370,8 @@ _equalAlterFunctionStmt(const AlterFunctionStmt *a, const AlterFunctionStmt *b)
 static bool
 _equalDoStmt(const DoStmt *a, const DoStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_NODE_FIELD(args);
 
 	return true;
@@ -1328,6 +1380,8 @@ _equalDoStmt(const DoStmt *a, const DoStmt *b)
 static bool
 _equalRenameStmt(const RenameStmt *a, const RenameStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_SCALAR_FIELD(renameType);
 	COMPARE_SCALAR_FIELD(relationType);
 	COMPARE_NODE_FIELD(relation);
@@ -1344,6 +1398,8 @@ _equalRenameStmt(const RenameStmt *a, const RenameStmt *b)
 static bool
 _equalAlterObjectDependsStmt(const AlterObjectDependsStmt *a, const AlterObjectDependsStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_SCALAR_FIELD(objectType);
 	COMPARE_NODE_FIELD(relation);
 	COMPARE_NODE_FIELD(objname);
@@ -1356,6 +1412,8 @@ _equalAlterObjectDependsStmt(const AlterObjectDependsStmt *a, const AlterObjectD
 static bool
 _equalAlterObjectSchemaStmt(const AlterObjectSchemaStmt *a, const AlterObjectSchemaStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_SCALAR_FIELD(objectType);
 	COMPARE_NODE_FIELD(relation);
 	COMPARE_NODE_FIELD(object);
@@ -1369,6 +1427,8 @@ _equalAlterObjectSchemaStmt(const AlterObjectSchemaStmt *a, const AlterObjectSch
 static bool
 _equalAlterOwnerStmt(const AlterOwnerStmt *a, const AlterOwnerStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_SCALAR_FIELD(objectType);
 	COMPARE_NODE_FIELD(relation);
 	COMPARE_NODE_FIELD(object);
@@ -1381,6 +1441,8 @@ _equalAlterOwnerStmt(const AlterOwnerStmt *a, const AlterOwnerStmt *b)
 static bool
 _equalAlterOperatorStmt(const AlterOperatorStmt *a, const AlterOperatorStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_NODE_FIELD(opername);
 	COMPARE_NODE_FIELD(operargs);
 	COMPARE_NODE_FIELD(options);
@@ -1391,6 +1453,8 @@ _equalAlterOperatorStmt(const AlterOperatorStmt *a, const AlterOperatorStmt *b)
 static bool
 _equalRuleStmt(const RuleStmt *a, const RuleStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_NODE_FIELD(relation);
 	COMPARE_STRING_FIELD(rulename);
 	COMPARE_NODE_FIELD(whereClause);
@@ -1405,6 +1469,8 @@ _equalRuleStmt(const RuleStmt *a, const RuleStmt *b)
 static bool
 _equalNotifyStmt(const NotifyStmt *a, const NotifyStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_STRING_FIELD(conditionname);
 	COMPARE_STRING_FIELD(payload);
 
@@ -1414,6 +1480,8 @@ _equalNotifyStmt(const NotifyStmt *a, const NotifyStmt *b)
 static bool
 _equalListenStmt(const ListenStmt *a, const ListenStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_STRING_FIELD(conditionname);
 
 	return true;
@@ -1422,6 +1490,8 @@ _equalListenStmt(const ListenStmt *a, const ListenStmt *b)
 static bool
 _equalUnlistenStmt(const UnlistenStmt *a, const UnlistenStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_STRING_FIELD(conditionname);
 
 	return true;
@@ -1430,6 +1500,8 @@ _equalUnlistenStmt(const UnlistenStmt *a, const UnlistenStmt *b)
 static bool
 _equalTransactionStmt(const TransactionStmt *a, const TransactionStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_SCALAR_FIELD(kind);
 	COMPARE_NODE_FIELD(options);
 	COMPARE_STRING_FIELD(gid);
@@ -1440,6 +1512,8 @@ _equalTransactionStmt(const TransactionStmt *a, const TransactionStmt *b)
 static bool
 _equalCompositeTypeStmt(const CompositeTypeStmt *a, const CompositeTypeStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_NODE_FIELD(typevar);
 	COMPARE_NODE_FIELD(coldeflist);
 
@@ -1449,6 +1523,8 @@ _equalCompositeTypeStmt(const CompositeTypeStmt *a, const CompositeTypeStmt *b)
 static bool
 _equalCreateEnumStmt(const CreateEnumStmt *a, const CreateEnumStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_NODE_FIELD(typeName);
 	COMPARE_NODE_FIELD(vals);
 
@@ -1458,6 +1534,8 @@ _equalCreateEnumStmt(const CreateEnumStmt *a, const CreateEnumStmt *b)
 static bool
 _equalCreateRangeStmt(const CreateRangeStmt *a, const CreateRangeStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_NODE_FIELD(typeName);
 	COMPARE_NODE_FIELD(params);
 
@@ -1467,6 +1545,8 @@ _equalCreateRangeStmt(const CreateRangeStmt *a, const CreateRangeStmt *b)
 static bool
 _equalAlterEnumStmt(const AlterEnumStmt *a, const AlterEnumStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_NODE_FIELD(typeName);
 	COMPARE_STRING_FIELD(oldVal);
 	COMPARE_STRING_FIELD(newVal);
@@ -1480,6 +1560,8 @@ _equalAlterEnumStmt(const AlterEnumStmt *a, const AlterEnumStmt *b)
 static bool
 _equalViewStmt(const ViewStmt *a, const ViewStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_NODE_FIELD(view);
 	COMPARE_NODE_FIELD(aliases);
 	COMPARE_NODE_FIELD(query);
@@ -1493,6 +1575,8 @@ _equalViewStmt(const ViewStmt *a, const ViewStmt *b)
 static bool
 _equalLoadStmt(const LoadStmt *a, const LoadStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_STRING_FIELD(filename);
 
 	return true;
@@ -1501,6 +1585,8 @@ _equalLoadStmt(const LoadStmt *a, const LoadStmt *b)
 static bool
 _equalCreateDomainStmt(const CreateDomainStmt *a, const CreateDomainStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_NODE_FIELD(domainname);
 	COMPARE_NODE_FIELD(typeName);
 	COMPARE_NODE_FIELD(collClause);
@@ -1512,6 +1598,8 @@ _equalCreateDomainStmt(const CreateDomainStmt *a, const CreateDomainStmt *b)
 static bool
 _equalCreateOpClassStmt(const CreateOpClassStmt *a, const CreateOpClassStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_NODE_FIELD(opclassname);
 	COMPARE_NODE_FIELD(opfamilyname);
 	COMPARE_STRING_FIELD(amname);
@@ -1539,6 +1627,8 @@ _equalCreateOpClassItem(const CreateOpClassItem *a, const CreateOpClassItem *b)
 static bool
 _equalCreateOpFamilyStmt(const CreateOpFamilyStmt *a, const CreateOpFamilyStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_NODE_FIELD(opfamilyname);
 	COMPARE_STRING_FIELD(amname);
 
@@ -1548,6 +1638,8 @@ _equalCreateOpFamilyStmt(const CreateOpFamilyStmt *a, const CreateOpFamilyStmt *
 static bool
 _equalAlterOpFamilyStmt(const AlterOpFamilyStmt *a, const AlterOpFamilyStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_NODE_FIELD(opfamilyname);
 	COMPARE_STRING_FIELD(amname);
 	COMPARE_SCALAR_FIELD(isDrop);
@@ -1559,6 +1651,8 @@ _equalAlterOpFamilyStmt(const AlterOpFamilyStmt *a, const AlterOpFamilyStmt *b)
 static bool
 _equalCreatedbStmt(const CreatedbStmt *a, const CreatedbStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_STRING_FIELD(dbname);
 	COMPARE_NODE_FIELD(options);
 
@@ -1568,6 +1662,8 @@ _equalCreatedbStmt(const CreatedbStmt *a, const CreatedbStmt *b)
 static bool
 _equalAlterDatabaseStmt(const AlterDatabaseStmt *a, const AlterDatabaseStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_STRING_FIELD(dbname);
 	COMPARE_NODE_FIELD(options);
 
@@ -1577,6 +1673,8 @@ _equalAlterDatabaseStmt(const AlterDatabaseStmt *a, const AlterDatabaseStmt *b)
 static bool
 _equalAlterDatabaseSetStmt(const AlterDatabaseSetStmt *a, const AlterDatabaseSetStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_STRING_FIELD(dbname);
 	COMPARE_NODE_FIELD(setstmt);
 
@@ -1586,6 +1684,8 @@ _equalAlterDatabaseSetStmt(const AlterDatabaseSetStmt *a, const AlterDatabaseSet
 static bool
 _equalDropdbStmt(const DropdbStmt *a, const DropdbStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_STRING_FIELD(dbname);
 	COMPARE_SCALAR_FIELD(missing_ok);
 
@@ -1595,6 +1695,8 @@ _equalDropdbStmt(const DropdbStmt *a, const DropdbStmt *b)
 static bool
 _equalVacuumStmt(const VacuumStmt *a, const VacuumStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_SCALAR_FIELD(options);
 	COMPARE_NODE_FIELD(relation);
 	COMPARE_NODE_FIELD(va_cols);
@@ -1605,6 +1707,8 @@ _equalVacuumStmt(const VacuumStmt *a, const VacuumStmt *b)
 static bool
 _equalExplainStmt(const ExplainStmt *a, const ExplainStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_NODE_FIELD(query);
 	COMPARE_NODE_FIELD(options);
 
@@ -1614,6 +1718,8 @@ _equalExplainStmt(const ExplainStmt *a, const ExplainStmt *b)
 static bool
 _equalCreateTableAsStmt(const CreateTableAsStmt *a, const CreateTableAsStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_NODE_FIELD(query);
 	COMPARE_NODE_FIELD(into);
 	COMPARE_SCALAR_FIELD(relkind);
@@ -1626,6 +1732,8 @@ _equalCreateTableAsStmt(const CreateTableAsStmt *a, const CreateTableAsStmt *b)
 static bool
 _equalRefreshMatViewStmt(const RefreshMatViewStmt *a, const RefreshMatViewStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_SCALAR_FIELD(concurrent);
 	COMPARE_SCALAR_FIELD(skipData);
 	COMPARE_NODE_FIELD(relation);
@@ -1636,6 +1744,8 @@ _equalRefreshMatViewStmt(const RefreshMatViewStmt *a, const RefreshMatViewStmt *
 static bool
 _equalReplicaIdentityStmt(const ReplicaIdentityStmt *a, const ReplicaIdentityStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_SCALAR_FIELD(identity_type);
 	COMPARE_STRING_FIELD(name);
 
@@ -1645,6 +1755,8 @@ _equalReplicaIdentityStmt(const ReplicaIdentityStmt *a, const ReplicaIdentityStm
 static bool
 _equalAlterSystemStmt(const AlterSystemStmt *a, const AlterSystemStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_NODE_FIELD(setstmt);
 
 	return true;
@@ -1654,6 +1766,8 @@ _equalAlterSystemStmt(const AlterSystemStmt *a, const AlterSystemStmt *b)
 static bool
 _equalCreateSeqStmt(const CreateSeqStmt *a, const CreateSeqStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_NODE_FIELD(sequence);
 	COMPARE_NODE_FIELD(options);
 	COMPARE_SCALAR_FIELD(ownerId);
@@ -1665,6 +1779,8 @@ _equalCreateSeqStmt(const CreateSeqStmt *a, const CreateSeqStmt *b)
 static bool
 _equalAlterSeqStmt(const AlterSeqStmt *a, const AlterSeqStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_NODE_FIELD(sequence);
 	COMPARE_NODE_FIELD(options);
 	COMPARE_SCALAR_FIELD(missing_ok);
@@ -1675,6 +1791,8 @@ _equalAlterSeqStmt(const AlterSeqStmt *a, const AlterSeqStmt *b)
 static bool
 _equalVariableSetStmt(const VariableSetStmt *a, const VariableSetStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_SCALAR_FIELD(kind);
 	COMPARE_STRING_FIELD(name);
 	COMPARE_NODE_FIELD(args);
@@ -1686,6 +1804,8 @@ _equalVariableSetStmt(const VariableSetStmt *a, const VariableSetStmt *b)
 static bool
 _equalVariableShowStmt(const VariableShowStmt *a, const VariableShowStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_STRING_FIELD(name);
 
 	return true;
@@ -1694,6 +1814,8 @@ _equalVariableShowStmt(const VariableShowStmt *a, const VariableShowStmt *b)
 static bool
 _equalDiscardStmt(const DiscardStmt *a, const DiscardStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_SCALAR_FIELD(target);
 
 	return true;
@@ -1702,9 +1824,11 @@ _equalDiscardStmt(const DiscardStmt *a, const DiscardStmt *b)
 static bool
 _equalCreateTableSpaceStmt(const CreateTableSpaceStmt *a, const CreateTableSpaceStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_STRING_FIELD(tablespacename);
 	COMPARE_NODE_FIELD(owner);
-	COMPARE_STRING_FIELD(location);
+	COMPARE_STRING_FIELD(location_dir);
 	COMPARE_NODE_FIELD(options);
 
 	return true;
@@ -1713,6 +1837,8 @@ _equalCreateTableSpaceStmt(const CreateTableSpaceStmt *a, const CreateTableSpace
 static bool
 _equalDropTableSpaceStmt(const DropTableSpaceStmt *a, const DropTableSpaceStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_STRING_FIELD(tablespacename);
 	COMPARE_SCALAR_FIELD(missing_ok);
 
@@ -1723,6 +1849,8 @@ static bool
 _equalAlterTableSpaceOptionsStmt(const AlterTableSpaceOptionsStmt *a,
 								 const AlterTableSpaceOptionsStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_STRING_FIELD(tablespacename);
 	COMPARE_NODE_FIELD(options);
 	COMPARE_SCALAR_FIELD(isReset);
@@ -1734,6 +1862,8 @@ static bool
 _equalAlterTableMoveAllStmt(const AlterTableMoveAllStmt *a,
 							const AlterTableMoveAllStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_STRING_FIELD(orig_tablespacename);
 	COMPARE_SCALAR_FIELD(objtype);
 	COMPARE_NODE_FIELD(roles);
@@ -1746,6 +1876,8 @@ _equalAlterTableMoveAllStmt(const AlterTableMoveAllStmt *a,
 static bool
 _equalCreateExtensionStmt(const CreateExtensionStmt *a, const CreateExtensionStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_STRING_FIELD(extname);
 	COMPARE_SCALAR_FIELD(if_not_exists);
 	COMPARE_NODE_FIELD(options);
@@ -1756,6 +1888,8 @@ _equalCreateExtensionStmt(const CreateExtensionStmt *a, const CreateExtensionStm
 static bool
 _equalAlterExtensionStmt(const AlterExtensionStmt *a, const AlterExtensionStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_STRING_FIELD(extname);
 	COMPARE_NODE_FIELD(options);
 
@@ -1765,6 +1899,8 @@ _equalAlterExtensionStmt(const AlterExtensionStmt *a, const AlterExtensionStmt *
 static bool
 _equalAlterExtensionContentsStmt(const AlterExtensionContentsStmt *a, const AlterExtensionContentsStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_STRING_FIELD(extname);
 	COMPARE_SCALAR_FIELD(action);
 	COMPARE_SCALAR_FIELD(objtype);
@@ -1777,6 +1913,8 @@ _equalAlterExtensionContentsStmt(const AlterExtensionContentsStmt *a, const Alte
 static bool
 _equalCreateFdwStmt(const CreateFdwStmt *a, const CreateFdwStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_STRING_FIELD(fdwname);
 	COMPARE_NODE_FIELD(func_options);
 	COMPARE_NODE_FIELD(options);
@@ -1787,6 +1925,8 @@ _equalCreateFdwStmt(const CreateFdwStmt *a, const CreateFdwStmt *b)
 static bool
 _equalAlterFdwStmt(const AlterFdwStmt *a, const AlterFdwStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_STRING_FIELD(fdwname);
 	COMPARE_NODE_FIELD(func_options);
 	COMPARE_NODE_FIELD(options);
@@ -1797,6 +1937,8 @@ _equalAlterFdwStmt(const AlterFdwStmt *a, const AlterFdwStmt *b)
 static bool
 _equalCreateForeignServerStmt(const CreateForeignServerStmt *a, const CreateForeignServerStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_STRING_FIELD(servername);
 	COMPARE_STRING_FIELD(servertype);
 	COMPARE_STRING_FIELD(version);
@@ -1809,6 +1951,8 @@ _equalCreateForeignServerStmt(const CreateForeignServerStmt *a, const CreateFore
 static bool
 _equalAlterForeignServerStmt(const AlterForeignServerStmt *a, const AlterForeignServerStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_STRING_FIELD(servername);
 	COMPARE_STRING_FIELD(version);
 	COMPARE_NODE_FIELD(options);
@@ -1820,6 +1964,8 @@ _equalAlterForeignServerStmt(const AlterForeignServerStmt *a, const AlterForeign
 static bool
 _equalCreateUserMappingStmt(const CreateUserMappingStmt *a, const CreateUserMappingStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_NODE_FIELD(user);
 	COMPARE_STRING_FIELD(servername);
 	COMPARE_NODE_FIELD(options);
@@ -1830,6 +1976,8 @@ _equalCreateUserMappingStmt(const CreateUserMappingStmt *a, const CreateUserMapp
 static bool
 _equalAlterUserMappingStmt(const AlterUserMappingStmt *a, const AlterUserMappingStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_NODE_FIELD(user);
 	COMPARE_STRING_FIELD(servername);
 	COMPARE_NODE_FIELD(options);
@@ -1840,6 +1988,8 @@ _equalAlterUserMappingStmt(const AlterUserMappingStmt *a, const AlterUserMapping
 static bool
 _equalDropUserMappingStmt(const DropUserMappingStmt *a, const DropUserMappingStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_NODE_FIELD(user);
 	COMPARE_STRING_FIELD(servername);
 	COMPARE_SCALAR_FIELD(missing_ok);
@@ -1862,6 +2012,8 @@ _equalCreateForeignTableStmt(const CreateForeignTableStmt *a, const CreateForeig
 static bool
 _equalImportForeignSchemaStmt(const ImportForeignSchemaStmt *a, const ImportForeignSchemaStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_STRING_FIELD(server_name);
 	COMPARE_STRING_FIELD(remote_schema);
 	COMPARE_STRING_FIELD(local_schema);
@@ -1875,6 +2027,8 @@ _equalImportForeignSchemaStmt(const ImportForeignSchemaStmt *a, const ImportFore
 static bool
 _equalCreateTransformStmt(const CreateTransformStmt *a, const CreateTransformStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_SCALAR_FIELD(replace);
 	COMPARE_NODE_FIELD(type_name);
 	COMPARE_STRING_FIELD(lang);
@@ -1887,6 +2041,8 @@ _equalCreateTransformStmt(const CreateTransformStmt *a, const CreateTransformStm
 static bool
 _equalCreateAmStmt(const CreateAmStmt *a, const CreateAmStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_STRING_FIELD(amname);
 	COMPARE_NODE_FIELD(handler_name);
 	COMPARE_SCALAR_FIELD(amtype);
@@ -1897,6 +2053,8 @@ _equalCreateAmStmt(const CreateAmStmt *a, const CreateAmStmt *b)
 static bool
 _equalCreateTrigStmt(const CreateTrigStmt *a, const CreateTrigStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_STRING_FIELD(trigname);
 	COMPARE_NODE_FIELD(relation);
 	COMPARE_NODE_FIELD(funcname);
@@ -1918,6 +2076,8 @@ _equalCreateTrigStmt(const CreateTrigStmt *a, const CreateTrigStmt *b)
 static bool
 _equalCreateEventTrigStmt(const CreateEventTrigStmt *a, const CreateEventTrigStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_STRING_FIELD(trigname);
 	COMPARE_STRING_FIELD(eventname);
 	COMPARE_NODE_FIELD(whenclause);
@@ -1929,6 +2089,8 @@ _equalCreateEventTrigStmt(const CreateEventTrigStmt *a, const CreateEventTrigStm
 static bool
 _equalAlterEventTrigStmt(const AlterEventTrigStmt *a, const AlterEventTrigStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_STRING_FIELD(trigname);
 	COMPARE_SCALAR_FIELD(tgenabled);
 
@@ -1938,6 +2100,8 @@ _equalAlterEventTrigStmt(const AlterEventTrigStmt *a, const AlterEventTrigStmt *
 static bool
 _equalCreatePLangStmt(const CreatePLangStmt *a, const CreatePLangStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_SCALAR_FIELD(replace);
 	COMPARE_STRING_FIELD(plname);
 	COMPARE_NODE_FIELD(plhandler);
@@ -1951,6 +2115,8 @@ _equalCreatePLangStmt(const CreatePLangStmt *a, const CreatePLangStmt *b)
 static bool
 _equalCreateRoleStmt(const CreateRoleStmt *a, const CreateRoleStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_SCALAR_FIELD(stmt_type);
 	COMPARE_STRING_FIELD(role);
 	COMPARE_NODE_FIELD(options);
@@ -1961,6 +2127,8 @@ _equalCreateRoleStmt(const CreateRoleStmt *a, const CreateRoleStmt *b)
 static bool
 _equalAlterRoleStmt(const AlterRoleStmt *a, const AlterRoleStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_NODE_FIELD(role);
 	COMPARE_NODE_FIELD(options);
 	COMPARE_SCALAR_FIELD(action);
@@ -1971,6 +2139,8 @@ _equalAlterRoleStmt(const AlterRoleStmt *a, const AlterRoleStmt *b)
 static bool
 _equalAlterRoleSetStmt(const AlterRoleSetStmt *a, const AlterRoleSetStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_NODE_FIELD(role);
 	COMPARE_STRING_FIELD(database);
 	COMPARE_NODE_FIELD(setstmt);
@@ -1981,6 +2151,8 @@ _equalAlterRoleSetStmt(const AlterRoleSetStmt *a, const AlterRoleSetStmt *b)
 static bool
 _equalDropRoleStmt(const DropRoleStmt *a, const DropRoleStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_NODE_FIELD(roles);
 	COMPARE_SCALAR_FIELD(missing_ok);
 
@@ -1990,6 +2162,8 @@ _equalDropRoleStmt(const DropRoleStmt *a, const DropRoleStmt *b)
 static bool
 _equalLockStmt(const LockStmt *a, const LockStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_NODE_FIELD(relations);
 	COMPARE_SCALAR_FIELD(mode);
 	COMPARE_SCALAR_FIELD(nowait);
@@ -2000,6 +2174,8 @@ _equalLockStmt(const LockStmt *a, const LockStmt *b)
 static bool
 _equalConstraintsSetStmt(const ConstraintsSetStmt *a, const ConstraintsSetStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_NODE_FIELD(constraints);
 	COMPARE_SCALAR_FIELD(deferred);
 
@@ -2009,6 +2185,8 @@ _equalConstraintsSetStmt(const ConstraintsSetStmt *a, const ConstraintsSetStmt *
 static bool
 _equalReindexStmt(const ReindexStmt *a, const ReindexStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_SCALAR_FIELD(kind);
 	COMPARE_NODE_FIELD(relation);
 	COMPARE_STRING_FIELD(name);
@@ -2020,6 +2198,8 @@ _equalReindexStmt(const ReindexStmt *a, const ReindexStmt *b)
 static bool
 _equalCreateSchemaStmt(const CreateSchemaStmt *a, const CreateSchemaStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_STRING_FIELD(schemaname);
 	COMPARE_NODE_FIELD(authrole);
 	COMPARE_NODE_FIELD(schemaElts);
@@ -2031,6 +2211,8 @@ _equalCreateSchemaStmt(const CreateSchemaStmt *a, const CreateSchemaStmt *b)
 static bool
 _equalCreateConversionStmt(const CreateConversionStmt *a, const CreateConversionStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_NODE_FIELD(conversion_name);
 	COMPARE_STRING_FIELD(for_encoding_name);
 	COMPARE_STRING_FIELD(to_encoding_name);
@@ -2043,6 +2225,8 @@ _equalCreateConversionStmt(const CreateConversionStmt *a, const CreateConversion
 static bool
 _equalCreateCastStmt(const CreateCastStmt *a, const CreateCastStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_NODE_FIELD(sourcetype);
 	COMPARE_NODE_FIELD(targettype);
 	COMPARE_NODE_FIELD(func);
@@ -2055,6 +2239,8 @@ _equalCreateCastStmt(const CreateCastStmt *a, const CreateCastStmt *b)
 static bool
 _equalPrepareStmt(const PrepareStmt *a, const PrepareStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_STRING_FIELD(name);
 	COMPARE_NODE_FIELD(argtypes);
 	COMPARE_NODE_FIELD(query);
@@ -2065,6 +2251,8 @@ _equalPrepareStmt(const PrepareStmt *a, const PrepareStmt *b)
 static bool
 _equalExecuteStmt(const ExecuteStmt *a, const ExecuteStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_STRING_FIELD(name);
 	COMPARE_NODE_FIELD(params);
 
@@ -2074,6 +2262,8 @@ _equalExecuteStmt(const ExecuteStmt *a, const ExecuteStmt *b)
 static bool
 _equalDeallocateStmt(const DeallocateStmt *a, const DeallocateStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_STRING_FIELD(name);
 
 	return true;
@@ -2082,6 +2272,8 @@ _equalDeallocateStmt(const DeallocateStmt *a, const DeallocateStmt *b)
 static bool
 _equalDropOwnedStmt(const DropOwnedStmt *a, const DropOwnedStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_NODE_FIELD(roles);
 	COMPARE_SCALAR_FIELD(behavior);
 
@@ -2091,6 +2283,8 @@ _equalDropOwnedStmt(const DropOwnedStmt *a, const DropOwnedStmt *b)
 static bool
 _equalReassignOwnedStmt(const ReassignOwnedStmt *a, const ReassignOwnedStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_NODE_FIELD(roles);
 	COMPARE_NODE_FIELD(newrole);
 
@@ -2100,6 +2294,8 @@ _equalReassignOwnedStmt(const ReassignOwnedStmt *a, const ReassignOwnedStmt *b)
 static bool
 _equalAlterTSDictionaryStmt(const AlterTSDictionaryStmt *a, const AlterTSDictionaryStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_NODE_FIELD(dictname);
 	COMPARE_NODE_FIELD(options);
 
@@ -2110,6 +2306,8 @@ static bool
 _equalAlterTSConfigurationStmt(const AlterTSConfigurationStmt *a,
 							   const AlterTSConfigurationStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_SCALAR_FIELD(kind);
 	COMPARE_NODE_FIELD(cfgname);
 	COMPARE_NODE_FIELD(tokentype);
@@ -2124,6 +2322,8 @@ _equalAlterTSConfigurationStmt(const AlterTSConfigurationStmt *a,
 static bool
 _equalCreatePolicyStmt(const CreatePolicyStmt *a, const CreatePolicyStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_STRING_FIELD(policy_name);
 	COMPARE_NODE_FIELD(table);
 	COMPARE_STRING_FIELD(cmd_name);
@@ -2138,6 +2338,8 @@ _equalCreatePolicyStmt(const CreatePolicyStmt *a, const CreatePolicyStmt *b)
 static bool
 _equalAlterPolicyStmt(const AlterPolicyStmt *a, const AlterPolicyStmt *b)
 {
+	COMPARE_SCALAR_FIELD(location);
+	COMPARE_SCALAR_FIELD(length);
 	COMPARE_STRING_FIELD(policy_name);
 	COMPARE_NODE_FIELD(table);
 	COMPARE_NODE_FIELD(roles);
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 41dde50..475efcf 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -177,6 +177,7 @@ planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
 		result = (*planner_hook) (parse, cursorOptions, boundParams);
 	else
 		result = standard_planner(parse, cursorOptions, boundParams);
+
 	return result;
 }
 
@@ -410,6 +411,8 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
 	/* build the PlannedStmt result */
 	result = makeNode(PlannedStmt);
 
+	result->location = parse->location;
+	result->length = parse->length;
 	result->commandType = parse->commandType;
 	result->queryId = parse->queryId;
 	result->hasReturning = (parse->returningList != NIL);
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index a558083..018cc75 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -307,6 +307,11 @@ transformStmt(ParseState *pstate, Node *parseTree)
 	result->querySource = QSRC_ORIGINAL;
 	result->canSetTag = true;
 
+	/* keep track of location & length */
+	Assert(isParseNode(parseTree));
+	result->location = ((ParseNode*) parseTree)->location;
+	result->length = ((ParseNode*) parseTree)->length;
+
 	return result;
 }
 
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 08cf5b7..c65f3b5 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -178,6 +178,7 @@ static void processCASbits(int cas_bits, int location, const char *constrType,
 			   bool *deferrable, bool *initdeferred, bool *not_valid,
 			   bool *no_inherit, core_yyscan_t yyscanner);
 static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
+static Node *stmtWithLocation(Node *node, core_yyscan_t yyscanner, int start);
 
 %}
 
@@ -762,14 +763,14 @@ stmtblock:	stmtmulti
 stmtmulti:	stmtmulti ';' stmt
 				{
 					if ($3 != NULL)
-						$$ = lappend($1, $3);
+						$$ = lappend($1, stmtWithLocation($3, yyscanner, @2+1));
 					else
 						$$ = $1;
 				}
 			| stmt
 				{
 					if ($1 != NULL)
-						$$ = list_make1($1);
+						$$ = list_make1(stmtWithLocation($1, yyscanner, 0));
 					else
 						$$ = NIL;
 				}
@@ -4080,7 +4081,7 @@ CreateTableSpaceStmt: CREATE TABLESPACE name OptTableSpaceOwner LOCATION Sconst
 					CreateTableSpaceStmt *n = makeNode(CreateTableSpaceStmt);
 					n->tablespacename = $3;
 					n->owner = $4;
-					n->location = $6;
+					n->location_dir = $6;
 					n->options = $7;
 					$$ = (Node *) n;
 				}
@@ -15284,6 +15285,31 @@ makeRecursiveViewSelect(char *relname, List *aliases, Node *query)
 	return (Node *) s;
 }
 
+/*
+ * Set query location & length for statement "node" starting at "start"
+ *
+ *  Computing the length depends on what triggered the stmtmulti reduction, which may be:
+ * - a ';', in which case statement ends at this last semicolon
+ * - the end of input, in which case statement ends at end of string
+ */
+static Node *
+stmtWithLocation(Node *node, core_yyscan_t yyscanner, int start)
+{
+	base_yy_extra_type *extra = pg_yyget_extra(yyscanner);
+	ParseNode *pn = (ParseNode *) node;
+	Assert(isParseNode(node));
+
+	pn->location = start;
+	if (extra->last_semicolon == -1 || start == (extra->last_semicolon + 1))
+		/* reduction triggered by end of input */
+		pn->length = strlen(extra->core_yy_extra.scanbuf) - start;
+	else
+		/* reduction triggered by ';' */
+		pn->length = extra->last_semicolon - start;
+
+	return node;
+}
+
 /* parser_init()
  * Initialize to parse one query string
  */
@@ -15291,4 +15317,5 @@ void
 parser_init(base_yy_extra_type *yyext)
 {
 	yyext->parsetree = NIL;		/* in case grammar forgets to set it */
+	yyext->last_semicolon = -1;
 }
diff --git a/src/backend/parser/scan.l b/src/backend/parser/scan.l
index acd9269..470a697 100644
--- a/src/backend/parser/scan.l
+++ b/src/backend/parser/scan.l
@@ -351,7 +351,8 @@ not_equals		"!="
  * If you change either set, adjust the character lists appearing in the
  * rule for "operator"!
  */
-self			[,()\[\].;\:\+\-\*\/\%\^\<\>\=]
+semicolon		;
+self			[,()\[\].\:\+\-\*\/\%\^\<\>\=]
 op_chars		[\~\!\@\#\^\&\|\`\?\+\-\*\/\%\<\>\=]
 operator		{op_chars}+
 
@@ -845,7 +846,11 @@ other			.
 					SET_YYLLOC();
 					return NOT_EQUALS;
 				}
-
+{semicolon}		{
+					SET_YYLLOC();
+					pg_yyget_extra(yyscanner)->last_semicolon = *yylloc;
+					return yytext[0];
+				}
 {self}			{
 					SET_YYLLOC();
 					return yytext[0];
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 201f248..66e049e 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -308,7 +308,6 @@ typedef enum NodeTag
 	T_UpdateStmt,
 	T_SelectStmt,
 	T_AlterTableStmt,
-	T_AlterTableCmd,
 	T_AlterDomainStmt,
 	T_SetOperationStmt,
 	T_GrantStmt,
@@ -406,7 +405,6 @@ typedef enum NodeTag
 	T_AlterPolicyStmt,
 	T_CreateTransformStmt,
 	T_CreateAmStmt,
-	T_PartitionCmd,
 
 	/*
 	 * TAGS FOR PARSE TREE NODES (parsenodes.h)
@@ -459,6 +457,8 @@ typedef enum NodeTag
 	T_PartitionSpec,
 	T_PartitionBoundSpec,
 	T_PartitionRangeDatum,
+	T_AlterTableCmd,
+	T_PartitionCmd,
 
 	/*
 	 * TAGS FOR REPLICATION GRAMMAR PARSE NODES (replnodes.h)
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 9d8ef77..561ed01 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -78,6 +78,24 @@ typedef uint32 AclMode;			/* a bitmask of privilege bits */
 /* Currently, SELECT ... FOR [KEY] UPDATE/SHARE requires UPDATE privileges */
 #define ACL_SELECT_FOR_UPDATE	ACL_UPDATE
 
+/*
+ * A ParseNode is a Node with additional location information.
+ * Zero qlengh means not set.
+ * If non-zero, then location is within to the initial query string.
+ */
+typedef struct ParseNode
+{
+	NodeTag		type;
+	int			location;
+	int			length;
+} ParseNode;
+
+/*
+ * All high-level statements coming out of the parser are ParseNode,
+ * plus Query & PlannedStmt.
+ */
+#define isParseNodeTag(tag)	((T_Query <= (tag)) && ((tag) < T_A_Expr))
+#define isParseNode(nodeptr) isParseNodeTag(nodeTag(nodeptr))
 
 /*****************************************************************************
  *	Query Tree
@@ -99,6 +117,8 @@ typedef uint32 AclMode;			/* a bitmask of privilege bits */
 typedef struct Query
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 
 	CmdType		commandType;	/* select|insert|update|delete|utility */
 
@@ -1322,6 +1342,8 @@ typedef struct TriggerTransition
 typedef struct InsertStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	RangeVar   *relation;		/* relation to insert into */
 	List	   *cols;			/* optional: names of the target columns */
 	Node	   *selectStmt;		/* the source SELECT/VALUES, or NULL */
@@ -1337,6 +1359,8 @@ typedef struct InsertStmt
 typedef struct DeleteStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	RangeVar   *relation;		/* relation to delete from */
 	List	   *usingClause;	/* optional using clause for more tables */
 	Node	   *whereClause;	/* qualifications */
@@ -1351,6 +1375,8 @@ typedef struct DeleteStmt
 typedef struct UpdateStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	RangeVar   *relation;		/* relation to update */
 	List	   *targetList;		/* the target list (of ResTarget) */
 	Node	   *whereClause;	/* qualifications */
@@ -1383,6 +1409,8 @@ typedef enum SetOperation
 typedef struct SelectStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 
 	/*
 	 * These fields are used only in "leaf" SelectStmts.
@@ -1450,6 +1478,8 @@ typedef struct SelectStmt
 typedef struct SetOperationStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	SetOperation op;			/* type of set op */
 	bool		all;			/* ALL specified? */
 	Node	   *larg;			/* left child */
@@ -1541,6 +1571,8 @@ typedef enum ObjectType
 typedef struct CreateSchemaStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	char	   *schemaname;		/* the name of the schema to create */
 	RoleSpec   *authrole;		/* the owner of the created schema */
 	List	   *schemaElts;		/* schema components (list of parsenodes) */
@@ -1560,6 +1592,8 @@ typedef enum DropBehavior
 typedef struct AlterTableStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	RangeVar   *relation;		/* table to work on */
 	List	   *cmds;			/* list of subcommands */
 	ObjectType	relkind;		/* type of object */
@@ -1637,6 +1671,8 @@ typedef enum AlterTableType
 typedef struct ReplicaIdentityStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	char		identity_type;
 	char	   *name;
 } ReplicaIdentityStmt;
@@ -1665,6 +1701,8 @@ typedef struct AlterTableCmd	/* one subcommand of an ALTER TABLE */
 typedef struct AlterDomainStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	char		subtype;		/*------------
 								 *	T = alter column default
 								 *	N = alter column drop not null
@@ -1712,6 +1750,8 @@ typedef enum GrantObjectType
 typedef struct GrantStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	bool		is_grant;		/* true = GRANT, false = REVOKE */
 	GrantTargetType targtype;	/* type of the grant target */
 	GrantObjectType objtype;	/* kind of object being operated on */
@@ -1762,6 +1802,8 @@ typedef struct AccessPriv
 typedef struct GrantRoleStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	List	   *granted_roles;	/* list of roles to be granted/revoked */
 	List	   *grantee_roles;	/* list of member roles to add/delete */
 	bool		is_grant;		/* true = GRANT, false = REVOKE */
@@ -1777,6 +1819,8 @@ typedef struct GrantRoleStmt
 typedef struct AlterDefaultPrivilegesStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	List	   *options;		/* list of DefElem */
 	GrantStmt  *action;			/* GRANT/REVOKE action (with objects=NIL) */
 } AlterDefaultPrivilegesStmt;
@@ -1792,6 +1836,8 @@ typedef struct AlterDefaultPrivilegesStmt
 typedef struct CopyStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	RangeVar   *relation;		/* the relation to copy */
 	Node	   *query;			/* the query (SELECT or DML statement with
 								 * RETURNING) to copy */
@@ -1823,6 +1869,8 @@ typedef enum
 typedef struct VariableSetStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	VariableSetKind kind;
 	char	   *name;			/* variable to be set */
 	List	   *args;			/* List of A_Const nodes */
@@ -1836,6 +1884,8 @@ typedef struct VariableSetStmt
 typedef struct VariableShowStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	char	   *name;
 } VariableShowStmt;
 
@@ -1853,6 +1903,8 @@ typedef struct VariableShowStmt
 typedef struct CreateStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	RangeVar   *relation;		/* relation to create */
 	List	   *tableElts;		/* column definitions (list of ColumnDef) */
 	List	   *inhRelations;	/* relations to inherit from (list of
@@ -1980,15 +2032,19 @@ typedef struct Constraint
 typedef struct CreateTableSpaceStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	char	   *tablespacename;
 	RoleSpec   *owner;
-	char	   *location;
+	char	   *location_dir;
 	List	   *options;
 } CreateTableSpaceStmt;
 
 typedef struct DropTableSpaceStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	char	   *tablespacename;
 	bool		missing_ok;		/* skip error if missing? */
 } DropTableSpaceStmt;
@@ -1996,6 +2052,8 @@ typedef struct DropTableSpaceStmt
 typedef struct AlterTableSpaceOptionsStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	char	   *tablespacename;
 	List	   *options;
 	bool		isReset;
@@ -2004,6 +2062,8 @@ typedef struct AlterTableSpaceOptionsStmt
 typedef struct AlterTableMoveAllStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	char	   *orig_tablespacename;
 	ObjectType	objtype;		/* Object type to move */
 	List	   *roles;			/* List of roles to move objects of */
@@ -2019,6 +2079,8 @@ typedef struct AlterTableMoveAllStmt
 typedef struct CreateExtensionStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	char	   *extname;
 	bool		if_not_exists;	/* just do nothing if it already exists? */
 	List	   *options;		/* List of DefElem nodes */
@@ -2028,6 +2090,8 @@ typedef struct CreateExtensionStmt
 typedef struct AlterExtensionStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	char	   *extname;
 	List	   *options;		/* List of DefElem nodes */
 } AlterExtensionStmt;
@@ -2035,6 +2099,8 @@ typedef struct AlterExtensionStmt
 typedef struct AlterExtensionContentsStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	char	   *extname;		/* Extension's name */
 	int			action;			/* +1 = add object, -1 = drop object */
 	ObjectType	objtype;		/* Object's type */
@@ -2050,6 +2116,8 @@ typedef struct AlterExtensionContentsStmt
 typedef struct CreateFdwStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	char	   *fdwname;		/* foreign-data wrapper name */
 	List	   *func_options;	/* HANDLER/VALIDATOR options */
 	List	   *options;		/* generic options to FDW */
@@ -2058,6 +2126,8 @@ typedef struct CreateFdwStmt
 typedef struct AlterFdwStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	char	   *fdwname;		/* foreign-data wrapper name */
 	List	   *func_options;	/* HANDLER/VALIDATOR options */
 	List	   *options;		/* generic options to FDW */
@@ -2071,6 +2141,8 @@ typedef struct AlterFdwStmt
 typedef struct CreateForeignServerStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	char	   *servername;		/* server name */
 	char	   *servertype;		/* optional server type */
 	char	   *version;		/* optional server version */
@@ -2081,6 +2153,8 @@ typedef struct CreateForeignServerStmt
 typedef struct AlterForeignServerStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	char	   *servername;		/* server name */
 	char	   *version;		/* optional server version */
 	List	   *options;		/* generic options to server */
@@ -2094,7 +2168,7 @@ typedef struct AlterForeignServerStmt
 
 typedef struct CreateForeignTableStmt
 {
-	CreateStmt	base;
+	CreateStmt	base;			/* is a ParseNode */
 	char	   *servername;
 	List	   *options;
 } CreateForeignTableStmt;
@@ -2107,6 +2181,8 @@ typedef struct CreateForeignTableStmt
 typedef struct CreateUserMappingStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	RoleSpec   *user;			/* user role */
 	char	   *servername;		/* server name */
 	List	   *options;		/* generic options to server */
@@ -2115,6 +2191,8 @@ typedef struct CreateUserMappingStmt
 typedef struct AlterUserMappingStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	RoleSpec   *user;			/* user role */
 	char	   *servername;		/* server name */
 	List	   *options;		/* generic options to server */
@@ -2123,6 +2201,8 @@ typedef struct AlterUserMappingStmt
 typedef struct DropUserMappingStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	RoleSpec   *user;			/* user role */
 	char	   *servername;		/* server name */
 	bool		missing_ok;		/* ignore missing mappings */
@@ -2143,6 +2223,8 @@ typedef enum ImportForeignSchemaType
 typedef struct ImportForeignSchemaStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	char	   *server_name;	/* FDW server name */
 	char	   *remote_schema;	/* remote schema name to query */
 	char	   *local_schema;	/* local schema to create objects in */
@@ -2158,6 +2240,8 @@ typedef struct ImportForeignSchemaStmt
 typedef struct CreatePolicyStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	char	   *policy_name;	/* Policy's name */
 	RangeVar   *table;			/* the table name the policy applies to */
 	char	   *cmd_name;		/* the command name the policy applies to */
@@ -2174,6 +2258,8 @@ typedef struct CreatePolicyStmt
 typedef struct AlterPolicyStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	char	   *policy_name;	/* Policy's name */
 	RangeVar   *table;			/* the table name the policy applies to */
 	List	   *roles;			/* the roles associated with the policy */
@@ -2188,6 +2274,8 @@ typedef struct AlterPolicyStmt
 typedef struct CreateAmStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	char	   *amname;			/* access method name */
 	List	   *handler_name;	/* handler function name */
 	char		amtype;			/* type of access method */
@@ -2200,6 +2288,8 @@ typedef struct CreateAmStmt
 typedef struct CreateTrigStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	char	   *trigname;		/* TRIGGER's name */
 	RangeVar   *relation;		/* relation trigger is on */
 	List	   *funcname;		/* qual. name of function to call */
@@ -2227,6 +2317,8 @@ typedef struct CreateTrigStmt
 typedef struct CreateEventTrigStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	char	   *trigname;		/* TRIGGER's name */
 	char	   *eventname;		/* event's identifier */
 	List	   *whenclause;		/* list of DefElems indicating filtering */
@@ -2240,6 +2332,8 @@ typedef struct CreateEventTrigStmt
 typedef struct AlterEventTrigStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	char	   *trigname;		/* TRIGGER's name */
 	char		tgenabled;		/* trigger's firing configuration WRT
 								 * session_replication_role */
@@ -2253,6 +2347,8 @@ typedef struct AlterEventTrigStmt
 typedef struct CreatePLangStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	bool		replace;		/* T => replace if already exists */
 	char	   *plname;			/* PL name */
 	List	   *plhandler;		/* PL call handler function (qual. name) */
@@ -2280,6 +2376,8 @@ typedef enum RoleStmtType
 typedef struct CreateRoleStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	RoleStmtType stmt_type;		/* ROLE/USER/GROUP */
 	char	   *role;			/* role name */
 	List	   *options;		/* List of DefElem nodes */
@@ -2288,6 +2386,8 @@ typedef struct CreateRoleStmt
 typedef struct AlterRoleStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	RoleSpec   *role;			/* role */
 	List	   *options;		/* List of DefElem nodes */
 	int			action;			/* +1 = add members, -1 = drop members */
@@ -2296,6 +2396,8 @@ typedef struct AlterRoleStmt
 typedef struct AlterRoleSetStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	RoleSpec   *role;			/* role */
 	char	   *database;		/* database name, or NULL */
 	VariableSetStmt *setstmt;	/* SET or RESET subcommand */
@@ -2304,6 +2406,8 @@ typedef struct AlterRoleSetStmt
 typedef struct DropRoleStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	List	   *roles;			/* List of roles to remove */
 	bool		missing_ok;		/* skip error if a role is missing? */
 } DropRoleStmt;
@@ -2316,6 +2420,8 @@ typedef struct DropRoleStmt
 typedef struct CreateSeqStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	RangeVar   *sequence;		/* the sequence to create */
 	List	   *options;
 	Oid			ownerId;		/* ID of owner, or InvalidOid for default */
@@ -2325,6 +2431,8 @@ typedef struct CreateSeqStmt
 typedef struct AlterSeqStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	RangeVar   *sequence;		/* the sequence to alter */
 	List	   *options;
 	bool		missing_ok;		/* skip error if a role is missing? */
@@ -2337,6 +2445,8 @@ typedef struct AlterSeqStmt
 typedef struct DefineStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	ObjectType	kind;			/* aggregate, operator, type */
 	bool		oldstyle;		/* hack to signal old CREATE AGG syntax */
 	List	   *defnames;		/* qualified name (list of Value strings) */
@@ -2351,6 +2461,8 @@ typedef struct DefineStmt
 typedef struct CreateDomainStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	List	   *domainname;		/* qualified name (list of Value strings) */
 	TypeName   *typeName;		/* the base type */
 	CollateClause *collClause;	/* untransformed COLLATE spec, if any */
@@ -2364,6 +2476,8 @@ typedef struct CreateDomainStmt
 typedef struct CreateOpClassStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	List	   *opclassname;	/* qualified name (list of Value strings) */
 	List	   *opfamilyname;	/* qualified name (ditto); NIL if omitted */
 	char	   *amname;			/* name of index AM opclass is for */
@@ -2397,6 +2511,8 @@ typedef struct CreateOpClassItem
 typedef struct CreateOpFamilyStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	List	   *opfamilyname;	/* qualified name (list of Value strings) */
 	char	   *amname;			/* name of index AM opfamily is for */
 } CreateOpFamilyStmt;
@@ -2408,6 +2524,8 @@ typedef struct CreateOpFamilyStmt
 typedef struct AlterOpFamilyStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	List	   *opfamilyname;	/* qualified name (list of Value strings) */
 	char	   *amname;			/* name of index AM opfamily is for */
 	bool		isDrop;			/* ADD or DROP the items? */
@@ -2422,6 +2540,8 @@ typedef struct AlterOpFamilyStmt
 typedef struct DropStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	List	   *objects;		/* list of sublists of names (as Values) */
 	List	   *arguments;		/* list of sublists of arguments (as Values) */
 	ObjectType	removeType;		/* object type */
@@ -2437,6 +2557,8 @@ typedef struct DropStmt
 typedef struct TruncateStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	List	   *relations;		/* relations (RangeVars) to be truncated */
 	bool		restart_seqs;	/* restart owned sequences? */
 	DropBehavior behavior;		/* RESTRICT or CASCADE behavior */
@@ -2449,6 +2571,8 @@ typedef struct TruncateStmt
 typedef struct CommentStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	ObjectType	objtype;		/* Object's type */
 	List	   *objname;		/* Qualified name of the object */
 	List	   *objargs;		/* Arguments if needed (eg, for functions) */
@@ -2462,6 +2586,8 @@ typedef struct CommentStmt
 typedef struct SecLabelStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	ObjectType	objtype;		/* Object's type */
 	List	   *objname;		/* Qualified name of the object */
 	List	   *objargs;		/* Arguments if needed (eg, for functions) */
@@ -2491,6 +2617,8 @@ typedef struct SecLabelStmt
 typedef struct DeclareCursorStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	char	   *portalname;		/* name of the portal (cursor) */
 	int			options;		/* bitmask of options (see above) */
 	Node	   *query;			/* the raw SELECT query */
@@ -2503,6 +2631,8 @@ typedef struct DeclareCursorStmt
 typedef struct ClosePortalStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	char	   *portalname;		/* name of the portal (cursor) */
 	/* NULL means CLOSE ALL */
 } ClosePortalStmt;
@@ -2526,6 +2656,8 @@ typedef enum FetchDirection
 typedef struct FetchStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	FetchDirection direction;	/* see above */
 	long		howMany;		/* number of rows, or position argument */
 	char	   *portalname;		/* name of portal (cursor) */
@@ -2546,6 +2678,8 @@ typedef struct FetchStmt
 typedef struct IndexStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	char	   *idxname;		/* name of new index, or NULL for default */
 	RangeVar   *relation;		/* relation to build index on */
 	char	   *accessMethod;	/* name of access method (eg. btree) */
@@ -2574,6 +2708,8 @@ typedef struct IndexStmt
 typedef struct CreateFunctionStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	bool		replace;		/* T => replace if already exists */
 	List	   *funcname;		/* qualified name of function to create */
 	List	   *parameters;		/* a list of FunctionParameter */
@@ -2604,6 +2740,8 @@ typedef struct FunctionParameter
 typedef struct AlterFunctionStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	FuncWithArgs *func;			/* name and args of function */
 	List	   *actions;		/* list of DefElem */
 } AlterFunctionStmt;
@@ -2617,6 +2755,8 @@ typedef struct AlterFunctionStmt
 typedef struct DoStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	List	   *args;			/* List of DefElem nodes */
 } DoStmt;
 
@@ -2635,6 +2775,8 @@ typedef struct InlineCodeBlock
 typedef struct RenameStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	ObjectType	renameType;		/* OBJECT_TABLE, OBJECT_COLUMN, etc */
 	ObjectType	relationType;	/* if column name, associated relation type */
 	RangeVar   *relation;		/* in case it's a table */
@@ -2654,6 +2796,8 @@ typedef struct RenameStmt
 typedef struct AlterObjectDependsStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	ObjectType	objectType;		/* OBJECT_FUNCTION, OBJECT_TRIGGER, etc */
 	RangeVar   *relation;		/* in case a table is involved */
 	List	   *objname;		/* name of the object */
@@ -2668,6 +2812,8 @@ typedef struct AlterObjectDependsStmt
 typedef struct AlterObjectSchemaStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	ObjectType	objectType;		/* OBJECT_TABLE, OBJECT_TYPE, etc */
 	RangeVar   *relation;		/* in case it's a table */
 	List	   *object;			/* in case it's some other object */
@@ -2683,6 +2829,8 @@ typedef struct AlterObjectSchemaStmt
 typedef struct AlterOwnerStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	ObjectType	objectType;		/* OBJECT_TABLE, OBJECT_TYPE, etc */
 	RangeVar   *relation;		/* in case it's a table */
 	List	   *object;			/* in case it's some other object */
@@ -2698,6 +2846,8 @@ typedef struct AlterOwnerStmt
 typedef struct AlterOperatorStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	List	   *opername;		/* operator name */
 	List	   *operargs;		/* operator's argument TypeNames */
 	List	   *options;		/* List of DefElem nodes */
@@ -2711,6 +2861,8 @@ typedef struct AlterOperatorStmt
 typedef struct RuleStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	RangeVar   *relation;		/* relation the rule is for */
 	char	   *rulename;		/* name of the rule */
 	Node	   *whereClause;	/* qualifications */
@@ -2727,6 +2879,8 @@ typedef struct RuleStmt
 typedef struct NotifyStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	char	   *conditionname;	/* condition name to notify */
 	char	   *payload;		/* the payload string, or NULL if none */
 } NotifyStmt;
@@ -2738,6 +2892,8 @@ typedef struct NotifyStmt
 typedef struct ListenStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	char	   *conditionname;	/* condition name to listen on */
 } ListenStmt;
 
@@ -2748,6 +2904,8 @@ typedef struct ListenStmt
 typedef struct UnlistenStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	char	   *conditionname;	/* name to unlisten on, or NULL for all */
 } UnlistenStmt;
 
@@ -2772,6 +2930,8 @@ typedef enum TransactionStmtKind
 typedef struct TransactionStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	TransactionStmtKind kind;	/* see above */
 	List	   *options;		/* for BEGIN/START and savepoint commands */
 	char	   *gid;			/* for two-phase-commit related commands */
@@ -2784,6 +2944,8 @@ typedef struct TransactionStmt
 typedef struct CompositeTypeStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	RangeVar   *typevar;		/* the composite type to be created */
 	List	   *coldeflist;		/* list of ColumnDef nodes */
 } CompositeTypeStmt;
@@ -2795,6 +2957,8 @@ typedef struct CompositeTypeStmt
 typedef struct CreateEnumStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	List	   *typeName;		/* qualified name (list of Value strings) */
 	List	   *vals;			/* enum values (list of Value strings) */
 } CreateEnumStmt;
@@ -2806,6 +2970,8 @@ typedef struct CreateEnumStmt
 typedef struct CreateRangeStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	List	   *typeName;		/* qualified name (list of Value strings) */
 	List	   *params;			/* range parameters (list of DefElem) */
 } CreateRangeStmt;
@@ -2817,6 +2983,8 @@ typedef struct CreateRangeStmt
 typedef struct AlterEnumStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	List	   *typeName;		/* qualified name (list of Value strings) */
 	char	   *oldVal;			/* old enum value's name, if renaming */
 	char	   *newVal;			/* new enum value's name */
@@ -2839,6 +3007,8 @@ typedef enum ViewCheckOption
 typedef struct ViewStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	RangeVar   *view;			/* the view to be created */
 	List	   *aliases;		/* target column names */
 	Node	   *query;			/* the SELECT query */
@@ -2854,6 +3024,8 @@ typedef struct ViewStmt
 typedef struct LoadStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	char	   *filename;		/* file to load */
 } LoadStmt;
 
@@ -2864,6 +3036,8 @@ typedef struct LoadStmt
 typedef struct CreatedbStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	char	   *dbname;			/* name of database to create */
 	List	   *options;		/* List of DefElem nodes */
 } CreatedbStmt;
@@ -2875,6 +3049,8 @@ typedef struct CreatedbStmt
 typedef struct AlterDatabaseStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	char	   *dbname;			/* name of database to alter */
 	List	   *options;		/* List of DefElem nodes */
 } AlterDatabaseStmt;
@@ -2882,6 +3058,8 @@ typedef struct AlterDatabaseStmt
 typedef struct AlterDatabaseSetStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	char	   *dbname;			/* database name */
 	VariableSetStmt *setstmt;	/* SET or RESET subcommand */
 } AlterDatabaseSetStmt;
@@ -2893,6 +3071,8 @@ typedef struct AlterDatabaseSetStmt
 typedef struct DropdbStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	char	   *dbname;			/* database to drop */
 	bool		missing_ok;		/* skip error if db is missing? */
 } DropdbStmt;
@@ -2904,6 +3084,8 @@ typedef struct DropdbStmt
 typedef struct AlterSystemStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	VariableSetStmt *setstmt;	/* SET subcommand */
 } AlterSystemStmt;
 
@@ -2914,6 +3096,8 @@ typedef struct AlterSystemStmt
 typedef struct ClusterStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	RangeVar   *relation;		/* relation being indexed, or NULL if all */
 	char	   *indexname;		/* original index defined */
 	bool		verbose;		/* print progress info */
@@ -2942,6 +3126,8 @@ typedef enum VacuumOption
 typedef struct VacuumStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	int			options;		/* OR of VacuumOption flags */
 	RangeVar   *relation;		/* single table to process, or NULL */
 	List	   *va_cols;		/* list of column names, or NIL for all */
@@ -2958,6 +3144,8 @@ typedef struct VacuumStmt
 typedef struct ExplainStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	Node	   *query;			/* the query (see comments above) */
 	List	   *options;		/* list of DefElem nodes */
 } ExplainStmt;
@@ -2978,6 +3166,8 @@ typedef struct ExplainStmt
 typedef struct CreateTableAsStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	Node	   *query;			/* the query (see comments above) */
 	IntoClause *into;			/* destination table */
 	ObjectType	relkind;		/* OBJECT_TABLE or OBJECT_MATVIEW */
@@ -2992,6 +3182,8 @@ typedef struct CreateTableAsStmt
 typedef struct RefreshMatViewStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	bool		concurrent;		/* allow concurrent access? */
 	bool		skipData;		/* true for WITH NO DATA */
 	RangeVar   *relation;		/* relation to insert into */
@@ -3004,6 +3196,8 @@ typedef struct RefreshMatViewStmt
 typedef struct CheckPointStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 } CheckPointStmt;
 
 /* ----------------------
@@ -3022,6 +3216,8 @@ typedef enum DiscardMode
 typedef struct DiscardStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	DiscardMode target;
 } DiscardStmt;
 
@@ -3032,6 +3228,8 @@ typedef struct DiscardStmt
 typedef struct LockStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	List	   *relations;		/* relations to lock */
 	int			mode;			/* lock mode */
 	bool		nowait;			/* no wait mode */
@@ -3044,6 +3242,8 @@ typedef struct LockStmt
 typedef struct ConstraintsSetStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	List	   *constraints;	/* List of names as RangeVars */
 	bool		deferred;
 } ConstraintsSetStmt;
@@ -3068,6 +3268,8 @@ typedef enum ReindexObjectType
 typedef struct ReindexStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	ReindexObjectType kind;		/* REINDEX_OBJECT_INDEX, REINDEX_OBJECT_TABLE,
 								 * etc. */
 	RangeVar   *relation;		/* Table or index to reindex */
@@ -3082,6 +3284,8 @@ typedef struct ReindexStmt
 typedef struct CreateConversionStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	List	   *conversion_name;	/* Name of the conversion */
 	char	   *for_encoding_name;		/* source encoding name */
 	char	   *to_encoding_name;		/* destination encoding name */
@@ -3096,6 +3300,8 @@ typedef struct CreateConversionStmt
 typedef struct CreateCastStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	TypeName   *sourcetype;
 	TypeName   *targettype;
 	FuncWithArgs *func;
@@ -3110,6 +3316,8 @@ typedef struct CreateCastStmt
 typedef struct CreateTransformStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	bool		replace;
 	TypeName   *type_name;
 	char	   *lang;
@@ -3124,6 +3332,8 @@ typedef struct CreateTransformStmt
 typedef struct PrepareStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	char	   *name;			/* Name of plan, arbitrary */
 	List	   *argtypes;		/* Types of parameters (List of TypeName) */
 	Node	   *query;			/* The query itself (as a raw parsetree) */
@@ -3138,6 +3348,8 @@ typedef struct PrepareStmt
 typedef struct ExecuteStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	char	   *name;			/* The name of the plan to execute */
 	List	   *params;			/* Values to assign to parameters */
 } ExecuteStmt;
@@ -3150,6 +3362,8 @@ typedef struct ExecuteStmt
 typedef struct DeallocateStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	char	   *name;			/* The name of the plan to remove */
 	/* NULL means DEALLOCATE ALL */
 } DeallocateStmt;
@@ -3160,6 +3374,8 @@ typedef struct DeallocateStmt
 typedef struct DropOwnedStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	List	   *roles;
 	DropBehavior behavior;
 } DropOwnedStmt;
@@ -3170,6 +3386,8 @@ typedef struct DropOwnedStmt
 typedef struct ReassignOwnedStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	List	   *roles;
 	RoleSpec   *newrole;
 } ReassignOwnedStmt;
@@ -3180,6 +3398,8 @@ typedef struct ReassignOwnedStmt
 typedef struct AlterTSDictionaryStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	List	   *dictname;		/* qualified name (list of Value strings) */
 	List	   *options;		/* List of DefElem nodes */
 } AlterTSDictionaryStmt;
@@ -3199,6 +3419,8 @@ typedef enum AlterTSConfigType
 typedef struct AlterTSConfigurationStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;		/* query length, 0 if unset */
 	AlterTSConfigType kind;		/* ALTER_TSCONFIG_ADD_MAPPING, etc */
 	List	   *cfgname;		/* qualified name (list of Value strings) */
 
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index e2fbc7d..7d139a3 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -36,6 +36,8 @@
 typedef struct PlannedStmt
 {
 	NodeTag		type;
+	int			location;		/* query location */
+	int			length;			/* query length, 0 if unset */
 
 	CmdType		commandType;	/* select|insert|update|delete */
 
diff --git a/src/include/parser/gramparse.h b/src/include/parser/gramparse.h
index 6d8e493..e373ab2 100644
--- a/src/include/parser/gramparse.h
+++ b/src/include/parser/gramparse.h
@@ -49,6 +49,8 @@ typedef struct base_yy_extra_type
 	char	   *lookahead_end;	/* end of current token */
 	char		lookahead_hold_char;	/* to be put back at *lookahead_end */
 
+	int			last_semicolon;	/* for query length computation */
+
 	/*
 	 * State variables that belong to the grammar.
 	 */
