*** a/contrib/pg_stat_statements/Makefile
--- b/contrib/pg_stat_statements/Makefile
***************
*** 5,10 **** OBJS = pg_stat_statements.o
--- 5,11 ----
  
  EXTENSION = pg_stat_statements
  DATA = pg_stat_statements--1.1.sql pg_stat_statements--1.0--1.1.sql \
+ 	pg_stat_statements--1.2.sql pg_stat_statements--1.1--1.2.sql \
  	pg_stat_statements--unpackaged--1.0.sql
  
  ifdef USE_PGXS
*** /dev/null
--- b/contrib/pg_stat_statements/pg_stat_statements--1.1--1.2.sql
***************
*** 0 ****
--- 1,44 ----
+ /* contrib/pg_stat_statements/pg_stat_statements--1.1--1.2.sql */
+ 
+ -- complain if script is sourced in psql, rather than via ALTER EXTENSION
+ \echo Use "ALTER EXTENSION pg_stat_statements UPDATE" to load this file. \quit
+ 
+ /* First we have to remove them from the extension */
+ ALTER EXTENSION pg_stat_statements DROP VIEW pg_stat_statements;
+ ALTER EXTENSION pg_stat_statements DROP FUNCTION pg_stat_statements();
+ 
+ /* Then we can drop them */
+ DROP VIEW pg_stat_statements;
+ DROP FUNCTION pg_stat_statements();
+ 
+ /* Now redefine */
+ CREATE FUNCTION pg_stat_statements(
+     OUT userid oid,
+     OUT dbid oid,
+     OUT stat_session_id int8,
+     OUT query text,
+     OUT query_id int4,
+     OUT calls int8,
+     OUT total_time float8,
+     OUT rows int8,
+     OUT shared_blks_hit int8,
+     OUT shared_blks_read int8,
+     OUT shared_blks_dirtied int8,
+     OUT shared_blks_written int8,
+     OUT local_blks_hit int8,
+     OUT local_blks_read int8,
+     OUT local_blks_dirtied int8,
+     OUT local_blks_written int8,
+     OUT temp_blks_read int8,
+     OUT temp_blks_written int8,
+     OUT blk_read_time float8,
+     OUT blk_write_time float8
+ )
+ RETURNS SETOF record
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C;
+ 
+ CREATE VIEW pg_stat_statements AS
+   SELECT * FROM pg_stat_statements();
+ 
+ GRANT SELECT ON pg_stat_statements TO PUBLIC;
*** /dev/null
--- b/contrib/pg_stat_statements/pg_stat_statements--1.2.sql
***************
*** 0 ****
--- 1,45 ----
+ /* contrib/pg_stat_statements/pg_stat_statements--1.2.sql */
+ 
+ -- complain if script is sourced in psql, rather than via CREATE EXTENSION
+ \echo Use "CREATE EXTENSION pg_stat_statements" to load this file. \quit
+ 
+ -- Register functions.
+ CREATE FUNCTION pg_stat_statements_reset()
+ RETURNS void
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C;
+ 
+ CREATE FUNCTION pg_stat_statements(
+     OUT userid oid,
+     OUT dbid oid,
+     OUT stat_session_id int4,
+     OUT query text,
+     OUT query_id int8,
+     OUT calls int8,
+     OUT total_time float8,
+     OUT rows int8,
+     OUT shared_blks_hit int8,
+     OUT shared_blks_read int8,
+     OUT shared_blks_dirtied int8,
+     OUT shared_blks_written int8,
+     OUT local_blks_hit int8,
+     OUT local_blks_read int8,
+     OUT local_blks_dirtied int8,
+     OUT local_blks_written int8,
+     OUT temp_blks_read int8,
+     OUT temp_blks_written int8,
+     OUT blk_read_time float8,
+     OUT blk_write_time float8
+ )
+ RETURNS SETOF record
+ AS 'MODULE_PATHNAME'
+ LANGUAGE C;
+ 
+ -- Register a view on the function for ease of use.
+ CREATE VIEW pg_stat_statements AS
+   SELECT * FROM pg_stat_statements();
+ 
+ GRANT SELECT ON pg_stat_statements TO PUBLIC;
+ 
+ -- Don't want this to be available to non-superusers.
+ REVOKE ALL ON FUNCTION pg_stat_statements_reset() FROM PUBLIC;
*** a/contrib/pg_stat_statements/pg_stat_statements.c
--- b/contrib/pg_stat_statements/pg_stat_statements.c
***************
*** 43,48 ****
--- 43,49 ----
   */
  #include "postgres.h"
  
+ #include <time.h>
  #include <unistd.h>
  
  #include "access/hash.h"
***************
*** 67,73 **** PG_MODULE_MAGIC;
  #define PGSS_DUMP_FILE	"global/pg_stat_statements.stat"
  
  /* This constant defines the magic number in the stats file header */
! static const uint32 PGSS_FILE_HEADER = 0x20120328;
  
  /* XXX: Should USAGE_EXEC reflect execution time and/or buffer usage? */
  #define USAGE_EXEC(duration)	(1.0)
--- 68,74 ----
  #define PGSS_DUMP_FILE	"global/pg_stat_statements.stat"
  
  /* This constant defines the magic number in the stats file header */
! static const uint32 PGSS_FILE_HEADER = 0x20130820;
  
  /* XXX: Should USAGE_EXEC reflect execution time and/or buffer usage? */
  #define USAGE_EXEC(duration)	(1.0)
***************
*** 96,101 **** typedef struct pgssHashKey
--- 97,116 ----
  } pgssHashKey;
  
  /*
+  * Identifies the tuple format detected by pg_stat_statements.
+  *
+  * Used to identify features of newer formats and enable smooth
+  * upgrades: one can install a new pg_stat_statements binary while
+  * running with the old SQL function definitions.
+  */
+ typedef enum pgssTupVersion
+ {
+ 	PGSS_TUP_V1_0 = 1,
+ 	PGSS_TUP_V1_1,
+ 	PGSS_TUP_LATEST
+ } pgssTupVersion;
+ 
+ /*
   * The actual stats counters kept within pgssEntry.
   */
  typedef struct Counters
***************
*** 128,133 **** typedef struct pgssEntry
--- 143,149 ----
  	pgssHashKey key;			/* hash key of entry - MUST BE FIRST */
  	Counters	counters;		/* the statistics for this query */
  	int			query_len;		/* # of valid bytes in query string */
+ 	uint32		query_id;		/* jumble value for this entry */
  	slock_t		mutex;			/* protects the counters only */
  	char		query[1];		/* VARIABLE LENGTH ARRAY - MUST BE LAST */
  	/* Note: the allocated length of query[] is actually pgss->query_size */
***************
*** 141,146 **** typedef struct pgssSharedState
--- 157,171 ----
  	LWLockId	lock;			/* protects hashtable search/modification */
  	int			query_size;		/* max query length in bytes */
  	double		cur_median_usage;		/* current median usage in hashtable */
+ 
+ 	/*
+ 	 * Is set to a new random value when the server restarts or stats
+ 	 * are reset, to de-confuse cases of non-monotonic counters (as
+ 	 * they had reasons to decrease) for tools that aggregate
+ 	 * snapshots of pg_stat_statements.
+ 	 */
+ 	int32		stat_session_key;
+ 	uint64		private_stat_session_key;
  } pgssSharedState;
  
  /*
***************
*** 192,197 **** static ProcessUtility_hook_type prev_ProcessUtility = NULL;
--- 217,226 ----
  static pgssSharedState *pgss = NULL;
  static HTAB *pgss_hash = NULL;
  
+ /* Random number seeding */
+ static unsigned int random_seed = 0;
+ static struct timeval random_start_time;
+ 
  /*---- GUC variables ----*/
  
  typedef enum
***************
*** 230,235 **** Datum		pg_stat_statements(PG_FUNCTION_ARGS);
--- 259,266 ----
  PG_FUNCTION_INFO_V1(pg_stat_statements_reset);
  PG_FUNCTION_INFO_V1(pg_stat_statements);
  
+ static long pgssRandom(void);
+ static void pgss_new_stat_session(pgssSharedState *state);
  static void pgss_shmem_startup(void);
  static void pgss_shmem_shutdown(int code, Datum arg);
  static void pgss_post_parse_analyze(ParseState *pstate, Query *query);
***************
*** 251,257 **** static void pgss_store(const char *query, uint32 queryId,
  		   pgssJumbleState *jstate);
  static Size pgss_memsize(void);
  static pgssEntry *entry_alloc(pgssHashKey *key, const char *query,
! 			int query_len, bool sticky);
  static void entry_dealloc(void);
  static void entry_reset(void);
  static void AppendJumble(pgssJumbleState *jstate,
--- 282,288 ----
  		   pgssJumbleState *jstate);
  static Size pgss_memsize(void);
  static pgssEntry *entry_alloc(pgssHashKey *key, const char *query,
! 							  int query_len, uint32 query_id, bool sticky);
  static void entry_dealloc(void);
  static void entry_reset(void);
  static void AppendJumble(pgssJumbleState *jstate,
***************
*** 291,297 **** _PG_init(void)
  							NULL,
  							&pgss_max,
  							1000,
! 							100,
  							INT_MAX,
  							PGC_POSTMASTER,
  							0,
--- 322,328 ----
  							NULL,
  							&pgss_max,
  							1000,
! 							1,
  							INT_MAX,
  							PGC_POSTMASTER,
  							0,
***************
*** 379,384 **** _PG_fini(void)
--- 410,463 ----
  }
  
  /*
+  * Random numbers -- ported from PostmasterRandom.
+  */
+ static long
+ pgssRandom(void)
+ {
+ 	/*
+ 	 * Select a random seed if one hasn't been selected before.
+ 	 */
+ 	if (random_seed == 0)
+ 	{
+ 		do
+ 		{
+ 			struct timeval random_stop_time;
+ 
+ 			gettimeofday(&random_stop_time, NULL);
+ 
+ 			/*
+ 			 * We are not sure how much precision is in tv_usec, so we swap
+ 			 * the high and low 16 bits of 'random_stop_time' and XOR them
+ 			 * with 'random_start_time'. On the off chance that the result is
+ 			 * 0, we loop until it isn't.
+ 			 */
+ 			random_seed = random_start_time.tv_usec ^
+ 				((random_stop_time.tv_usec << 16) |
+ 				 ((random_stop_time.tv_usec >> 16) & 0xffff));
+ 		}
+ 		while (random_seed == 0);
+ 
+ 		srandom(random_seed);
+ 	}
+ 
+ 	return random();
+ }
+ 
+ /*
+  * Create a new, random stat session key.
+  */
+ static void
+ pgss_new_stat_session(pgssSharedState *state)
+ {
+ 	state->stat_session_key = (int32) pgssRandom();
+ 
+ 	/* Generate 64-bit private session */
+ 	state->private_stat_session_key	 = (uint64) pgssRandom();
+ 	state->private_stat_session_key |= ((uint64) pgssRandom()) << 32;
+ }
+ 
+ /*
   * shmem_startup hook: allocate or attach to shared memory,
   * then load any pre-existing statistics from file.
   */
***************
*** 394,399 **** pgss_shmem_startup(void)
--- 473,479 ----
  	int			query_size;
  	int			buffer_size;
  	char	   *buffer = NULL;
+ 	bool 		log_cannot_read = true;
  
  	if (prev_shmem_startup_hook)
  		prev_shmem_startup_hook();
***************
*** 456,471 **** pgss_shmem_startup(void)
  	if (file == NULL)
  	{
  		if (errno == ENOENT)
! 			return;				/* ignore not-found error */
  		goto error;
  	}
  
  	buffer_size = query_size;
  	buffer = (char *) palloc(buffer_size);
  
  	if (fread(&header, sizeof(uint32), 1, file) != 1 ||
! 		header != PGSS_FILE_HEADER ||
! 		fread(&num, sizeof(int32), 1, file) != 1)
  		goto error;
  
  	for (i = 0; i < num; i++)
--- 536,566 ----
  	if (file == NULL)
  	{
  		if (errno == ENOENT)
! 			log_cannot_read = false;
! 
  		goto error;
  	}
  
  	buffer_size = query_size;
  	buffer = (char *) palloc(buffer_size);
  
+ 	/* Check header existence and magic number match. */
  	if (fread(&header, sizeof(uint32), 1, file) != 1 ||
! 		header != PGSS_FILE_HEADER)
! 		goto error;
! 
! 	/* Restore saved session key, if possible. */
! 	if (fread(&pgss->stat_session_key,
! 			  sizeof pgss->stat_session_key, 1, file) != 1)
! 		goto error;
! 
! 	/* Restore private session key */
! 	if (fread(&pgss->private_stat_session_key,
! 			  sizeof pgss->private_stat_session_key, 1, file) != 1)
! 		goto error;
! 
! 	/* Read how many table entries there are. */
! 	if (fread(&num, sizeof(int32), 1, file) != 1)
  		goto error;
  
  	for (i = 0; i < num; i++)
***************
*** 503,509 **** pgss_shmem_startup(void)
  												   query_size - 1);
  
  		/* make the hashtable entry (discards old entries if too many) */
! 		entry = entry_alloc(&temp.key, buffer, temp.query_len, false);
  
  		/* copy in the actual stats */
  		entry->counters = temp.counters;
--- 598,605 ----
  												   query_size - 1);
  
  		/* make the hashtable entry (discards old entries if too many) */
! 		entry = entry_alloc(&temp.key, buffer, temp.query_len, temp.query_id,
! 							false);
  
  		/* copy in the actual stats */
  		entry->counters = temp.counters;
***************
*** 521,530 **** pgss_shmem_startup(void)
  	return;
  
  error:
! 	ereport(LOG,
! 			(errcode_for_file_access(),
! 			 errmsg("could not read pg_stat_statement file \"%s\": %m",
! 					PGSS_DUMP_FILE)));
  	if (buffer)
  		pfree(buffer);
  	if (file)
--- 617,632 ----
  	return;
  
  error:
! 	/* Ignore not-found error. */
! 	if (log_cannot_read)
! 		ereport(LOG,
! 				(errcode_for_file_access(),
! 				 errmsg("could not read pg_stat_statement file \"%s\": %m",
! 						PGSS_DUMP_FILE)));
! 
! 	/* Need a new session if none could be read from the file */
! 	pgss_new_stat_session(pgss);
! 
  	if (buffer)
  		pfree(buffer);
  	if (file)
***************
*** 563,570 **** pgss_shmem_shutdown(int code, Datum arg)
--- 665,685 ----
  	if (file == NULL)
  		goto error;
  
+ 	/* Save header/magic number.  */
  	if (fwrite(&PGSS_FILE_HEADER, sizeof(uint32), 1, file) != 1)
  		goto error;
+ 
+ 	/* Save stat session key. */
+ 	if (fwrite(&pgss->stat_session_key,
+ 			   sizeof pgss->stat_session_key, 1, file) != 1)
+ 			goto error;
+ 
+ 	/* Save private session key */
+ 	if (fwrite(&pgss->private_stat_session_key,
+ 			   sizeof pgss->private_stat_session_key, 1, file) != 1)
+ 			goto error;
+ 
+ 	/* Write how many table entries there are. */
  	num_entries = hash_get_num_entries(pgss_hash);
  	if (fwrite(&num_entries, sizeof(int32), 1, file) != 1)
  		goto error;
***************
*** 991,997 **** pgss_store(const char *query, uint32 queryId,
  			/* Acquire exclusive lock as required by entry_alloc() */
  			LWLockAcquire(pgss->lock, LW_EXCLUSIVE);
  
! 			entry = entry_alloc(&key, norm_query, query_len, true);
  		}
  		else
  		{
--- 1106,1112 ----
  			/* Acquire exclusive lock as required by entry_alloc() */
  			LWLockAcquire(pgss->lock, LW_EXCLUSIVE);
  
! 			entry = entry_alloc(&key, norm_query, query_len, queryId, true);
  		}
  		else
  		{
***************
*** 1008,1014 **** pgss_store(const char *query, uint32 queryId,
  			/* Acquire exclusive lock as required by entry_alloc() */
  			LWLockAcquire(pgss->lock, LW_EXCLUSIVE);
  
! 			entry = entry_alloc(&key, query, query_len, false);
  		}
  	}
  
--- 1123,1129 ----
  			/* Acquire exclusive lock as required by entry_alloc() */
  			LWLockAcquire(pgss->lock, LW_EXCLUSIVE);
  
! 			entry = entry_alloc(&key, query, query_len, queryId, false);
  		}
  	}
  
***************
*** 1069,1075 **** pg_stat_statements_reset(PG_FUNCTION_ARGS)
  }
  
  #define PG_STAT_STATEMENTS_COLS_V1_0	14
! #define PG_STAT_STATEMENTS_COLS			18
  
  /*
   * Retrieve statement statistics.
--- 1184,1191 ----
  }
  
  #define PG_STAT_STATEMENTS_COLS_V1_0	14
! #define PG_STAT_STATEMENTS_COLS_V1_1	18
! #define PG_STAT_STATEMENTS_COLS			20
  
  /*
   * Retrieve statement statistics.
***************
*** 1086,1092 **** pg_stat_statements(PG_FUNCTION_ARGS)
  	bool		is_superuser = superuser();
  	HASH_SEQ_STATUS hash_seq;
  	pgssEntry  *entry;
! 	bool		sql_supports_v1_1_counters = true;
  
  	if (!pgss || !pgss_hash)
  		ereport(ERROR,
--- 1202,1208 ----
  	bool		is_superuser = superuser();
  	HASH_SEQ_STATUS hash_seq;
  	pgssEntry  *entry;
! 	pgssTupVersion detected_version;
  
  	if (!pgss || !pgss_hash)
  		ereport(ERROR,
***************
*** 1107,1114 **** pg_stat_statements(PG_FUNCTION_ARGS)
  	/* Build a tuple descriptor for our result type */
  	if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
  		elog(ERROR, "return type must be a row type");
  	if (tupdesc->natts == PG_STAT_STATEMENTS_COLS_V1_0)
! 		sql_supports_v1_1_counters = false;
  
  	per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
  	oldcontext = MemoryContextSwitchTo(per_query_ctx);
--- 1223,1250 ----
  	/* Build a tuple descriptor for our result type */
  	if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
  		elog(ERROR, "return type must be a row type");
+ 
+ 	/* Perform version detection */
  	if (tupdesc->natts == PG_STAT_STATEMENTS_COLS_V1_0)
! 		detected_version = PGSS_TUP_V1_0;
! 	else if (tupdesc->natts == PG_STAT_STATEMENTS_COLS_V1_1)
! 		detected_version = PGSS_TUP_V1_1;
! 	else if (tupdesc->natts == PG_STAT_STATEMENTS_COLS)
! 		detected_version = PGSS_TUP_LATEST;
! 	else
! 	{
! 		/*
! 		 * Couldn't identify the tuple format.  Raise error.
! 		 *
! 		 * This is an exceptional case that may only happen in bizarre
! 		 * situations, since it is thought that every released version
! 		 * of pg_stat_statements has a matching schema.
! 		 */
! 		ereport(ERROR,
! 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
! 				 errmsg("pg_stat_statements schema is not supported "
! 						"by its installed binary")));
! 	}
  
  	per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
  	oldcontext = MemoryContextSwitchTo(per_query_ctx);
***************
*** 1135,1140 **** pg_stat_statements(PG_FUNCTION_ARGS)
--- 1271,1277 ----
  
  		values[i++] = ObjectIdGetDatum(entry->key.userid);
  		values[i++] = ObjectIdGetDatum(entry->key.dbid);
+ 		values[i++] = DatumGetInt32(pgss->stat_session_key);
  
  		if (is_superuser || entry->key.userid == userid)
  		{
***************
*** 1150,1156 **** pg_stat_statements(PG_FUNCTION_ARGS)
  				pfree(qstr);
  		}
  		else
! 			values[i++] = CStringGetTextDatum("<insufficient privilege>");
  
  		/* copy counters to a local variable to keep locking time short */
  		{
--- 1287,1307 ----
  				pfree(qstr);
  		}
  		else
! 		{
! 			/*
! 			 * The role calling this function is unable to see
! 			 * sensitive aspects of this tuple.
! 			 *
! 			 * Nullify everything except the "insufficient privilege"
! 			 * message for this entry
! 			 */
! 			memset(nulls, 1, sizeof nulls);
! 
! 			nulls[i]  = 0;
! 			values[i] = CStringGetTextDatum("<insufficient privilege>");
! 
! 			i += 1;
! 		}
  
  		/* copy counters to a local variable to keep locking time short */
  		{
***************
*** 1165,1193 **** pg_stat_statements(PG_FUNCTION_ARGS)
  		if (tmp.calls == 0)
  			continue;
  
  		values[i++] = Int64GetDatumFast(tmp.calls);
  		values[i++] = Float8GetDatumFast(tmp.total_time);
  		values[i++] = Int64GetDatumFast(tmp.rows);
  		values[i++] = Int64GetDatumFast(tmp.shared_blks_hit);
  		values[i++] = Int64GetDatumFast(tmp.shared_blks_read);
! 		if (sql_supports_v1_1_counters)
  			values[i++] = Int64GetDatumFast(tmp.shared_blks_dirtied);
  		values[i++] = Int64GetDatumFast(tmp.shared_blks_written);
  		values[i++] = Int64GetDatumFast(tmp.local_blks_hit);
  		values[i++] = Int64GetDatumFast(tmp.local_blks_read);
! 		if (sql_supports_v1_1_counters)
  			values[i++] = Int64GetDatumFast(tmp.local_blks_dirtied);
  		values[i++] = Int64GetDatumFast(tmp.local_blks_written);
  		values[i++] = Int64GetDatumFast(tmp.temp_blks_read);
  		values[i++] = Int64GetDatumFast(tmp.temp_blks_written);
! 		if (sql_supports_v1_1_counters)
  		{
  			values[i++] = Float8GetDatumFast(tmp.blk_read_time);
  			values[i++] = Float8GetDatumFast(tmp.blk_write_time);
  		}
  
! 		Assert(i == (sql_supports_v1_1_counters ?
! 					 PG_STAT_STATEMENTS_COLS : PG_STAT_STATEMENTS_COLS_V1_0));
  
  		tuplestore_putvalues(tupstore, tupdesc, values, nulls);
  	}
--- 1316,1369 ----
  		if (tmp.calls == 0)
  			continue;
  
+ 		if (detected_version >= PGSS_TUP_LATEST)
+ 		{
+ 			uint64 qid = pgss->private_stat_session_key;
+ 
+ 			qid ^= (uint64) entry->query_id;
+ 			qid ^= ((uint64) entry->query_id) << 32;
+ 
+ 			values[i++] = Int64GetDatumFast(qid);
+ 		}
+ 
  		values[i++] = Int64GetDatumFast(tmp.calls);
  		values[i++] = Float8GetDatumFast(tmp.total_time);
  		values[i++] = Int64GetDatumFast(tmp.rows);
  		values[i++] = Int64GetDatumFast(tmp.shared_blks_hit);
  		values[i++] = Int64GetDatumFast(tmp.shared_blks_read);
! 		if (detected_version >= PGSS_TUP_V1_1)
  			values[i++] = Int64GetDatumFast(tmp.shared_blks_dirtied);
  		values[i++] = Int64GetDatumFast(tmp.shared_blks_written);
  		values[i++] = Int64GetDatumFast(tmp.local_blks_hit);
  		values[i++] = Int64GetDatumFast(tmp.local_blks_read);
! 		if (detected_version >= PGSS_TUP_V1_1)
  			values[i++] = Int64GetDatumFast(tmp.local_blks_dirtied);
  		values[i++] = Int64GetDatumFast(tmp.local_blks_written);
  		values[i++] = Int64GetDatumFast(tmp.temp_blks_read);
  		values[i++] = Int64GetDatumFast(tmp.temp_blks_written);
! 		if (detected_version >= PGSS_TUP_V1_1)
  		{
  			values[i++] = Float8GetDatumFast(tmp.blk_read_time);
  			values[i++] = Float8GetDatumFast(tmp.blk_write_time);
  		}
  
! #ifdef USE_ASSERT_CHECKING
! 		/* Check that every column appears to be filled */
! 		switch (detected_version)
! 		{
! 				case PGSS_TUP_V1_0:
! 						Assert(i == PG_STAT_STATEMENTS_COLS_V1_0);
! 						break;
! 				case PGSS_TUP_V1_1:
! 						Assert(i == PG_STAT_STATEMENTS_COLS_V1_1);
! 						break;
! 				case PGSS_TUP_LATEST:
! 						Assert(i == PG_STAT_STATEMENTS_COLS);
! 						break;
! 				default:
! 						Assert(false);
! 		}
! #endif
  
  		tuplestore_putvalues(tupstore, tupdesc, values, nulls);
  	}
***************
*** 1234,1240 **** pgss_memsize(void)
   * have made the entry while we waited to get exclusive lock.
   */
  static pgssEntry *
! entry_alloc(pgssHashKey *key, const char *query, int query_len, bool sticky)
  {
  	pgssEntry  *entry;
  	bool		found;
--- 1410,1417 ----
   * have made the entry while we waited to get exclusive lock.
   */
  static pgssEntry *
! entry_alloc(pgssHashKey *key, const char *query, int query_len,
! 			uint32 query_id, bool sticky)
  {
  	pgssEntry  *entry;
  	bool		found;
***************
*** 1254,1259 **** entry_alloc(pgssHashKey *key, const char *query, int query_len, bool sticky)
--- 1431,1437 ----
  		memset(&entry->counters, 0, sizeof(Counters));
  		/* set the appropriate initial usage count */
  		entry->counters.usage = sticky ? pgss->cur_median_usage : USAGE_INIT;
+ 
  		/* re-initialize the mutex each time ... we assume no one using it */
  		SpinLockInit(&entry->mutex);
  		/* ... and don't forget the query text */
***************
*** 1261,1266 **** entry_alloc(pgssHashKey *key, const char *query, int query_len, bool sticky)
--- 1439,1447 ----
  		entry->query_len = query_len;
  		memcpy(entry->query, query, query_len);
  		entry->query[query_len] = '\0';
+ 
+ 		/* Copy in the query id for reporting */
+ 		entry->query_id = query_id;
  	}
  
  	return entry;
***************
*** 1309,1314 **** entry_dealloc(void)
--- 1490,1496 ----
  	while ((entry = hash_seq_search(&hash_seq)) != NULL)
  	{
  		entries[i++] = entry;
+ 
  		/* "Sticky" entries get a different usage decay rate. */
  		if (entry->counters.calls == 0)
  			entry->counters.usage *= STICKY_DECREASE_FACTOR;
***************
*** 1350,1355 **** entry_reset(void)
--- 1532,1543 ----
  		hash_search(pgss_hash, &entry->key, HASH_REMOVE, NULL);
  	}
  
+ 	/*
+ 	 * Counters all reset, so need to generate a new identity for the
+ 	 * session.
+ 	 */
+ 	pgss_new_stat_session(pgss);
+ 
  	LWLockRelease(pgss->lock);
  }
  
*** a/contrib/pg_stat_statements/pg_stat_statements.control
--- b/contrib/pg_stat_statements/pg_stat_statements.control
***************
*** 1,5 ****
  # pg_stat_statements extension
  comment = 'track execution statistics of all SQL statements executed'
! default_version = '1.1'
  module_pathname = '$libdir/pg_stat_statements'
  relocatable = true
--- 1,5 ----
  # pg_stat_statements extension
  comment = 'track execution statistics of all SQL statements executed'
! default_version = '1.2'
  module_pathname = '$libdir/pg_stat_statements'
  relocatable = true
*** a/doc/src/sgml/pgstatstatements.sgml
--- b/doc/src/sgml/pgstatstatements.sgml
***************
*** 57,76 ****
        <entry>OID of database in which the statement was executed</entry>
       </row>
  
!     <row>
        <entry><structfield>query</structfield></entry>
        <entry><type>text</type></entry>
        <entry></entry>
        <entry>Text of a representative statement (up to <xref linkend="guc-track-activity-query-size"> bytes)</entry>
       </row>
! 
       <row>
        <entry><structfield>calls</structfield></entry>
        <entry><type>bigint</type></entry>
        <entry></entry>
        <entry>Number of times executed</entry>
       </row>
- 
       <row>
        <entry><structfield>total_time</structfield></entry>
        <entry><type>double precision</type></entry>
--- 57,81 ----
        <entry>OID of database in which the statement was executed</entry>
       </row>
  
!      <row>
        <entry><structfield>query</structfield></entry>
        <entry><type>text</type></entry>
        <entry></entry>
        <entry>Text of a representative statement (up to <xref linkend="guc-track-activity-query-size"> bytes)</entry>
       </row>
!      <row>
!       <entry><structfield>queryid</structfield></entry>
!       <entry><type>bigint</type></entry>
!       <entry></entry>
!       <entry>Unique value of each representative statement for the current statistics session.
!        This value will change for each new statistics session.</entry>
!      </row>
       <row>
        <entry><structfield>calls</structfield></entry>
        <entry><type>bigint</type></entry>
        <entry></entry>
        <entry>Number of times executed</entry>
       </row>
       <row>
        <entry><structfield>total_time</structfield></entry>
        <entry><type>double precision</type></entry>
