@@ -67,7 +67,9 @@ PG_MODULE_MAGIC;
6767#define PGSS_DUMP_FILE "global/pg_stat_statements.stat"
6868
6969/* This constant defines the magic number in the stats file header */
70- static const uint32 PGSS_FILE_HEADER = 0x20120328 ;
70+ static const uint32 PGSS_FILE_HEADER = 0x20131115 ;
71+ /* PostgreSQL major version number, changes in which invalidate all entries */
72+ static const uint32 PGSS_PG_MAJOR_VERSION = PG_VERSION_NUM / 100 ;
7173
7274/* XXX: Should USAGE_EXEC reflect execution time and/or buffer usage? */
7375#define USAGE_EXEC (duration ) (1.0)
@@ -79,6 +81,16 @@ static const uint32 PGSS_FILE_HEADER = 0x20120328;
7981
8082#define JUMBLE_SIZE 1024 /* query serialization buffer size */
8183
84+ /*
85+ * Extension version number, for supporting older extension versions' objects
86+ */
87+ typedef enum pgssVersion
88+ {
89+ PGSS_V1_0 = 0 ,
90+ PGSS_V1_1 ,
91+ PGSS_V1_2
92+ } pgssVersion ;
93+
8294/*
8395 * Hashtable key that defines the identity of a hashtable entry. We separate
8496 * queries by user and by database even if they are otherwise identical.
@@ -390,6 +402,7 @@ pgss_shmem_startup(void)
390402 FILE * file ;
391403 uint32 header ;
392404 int32 num ;
405+ int32 pgver ;
393406 int32 i ;
394407 int query_size ;
395408 int buffer_size ;
@@ -465,6 +478,8 @@ pgss_shmem_startup(void)
465478
466479 if (fread (& header , sizeof (uint32 ), 1 , file ) != 1 ||
467480 header != PGSS_FILE_HEADER ||
481+ fread (& pgver , sizeof (uint32 ), 1 , file ) != 1 ||
482+ pgver != PGSS_PG_MAJOR_VERSION ||
468483 fread (& num , sizeof (int32 ), 1 , file ) != 1 )
469484 goto error ;
470485
@@ -565,6 +580,8 @@ pgss_shmem_shutdown(int code, Datum arg)
565580
566581 if (fwrite (& PGSS_FILE_HEADER , sizeof (uint32 ), 1 , file ) != 1 )
567582 goto error ;
583+ if (fwrite (& PGSS_PG_MAJOR_VERSION , sizeof (uint32 ), 1 , file ) != 1 )
584+ goto error ;
568585 num_entries = hash_get_num_entries (pgss_hash );
569586 if (fwrite (& num_entries , sizeof (int32 ), 1 , file ) != 1 )
570587 goto error ;
@@ -1069,7 +1086,8 @@ pg_stat_statements_reset(PG_FUNCTION_ARGS)
10691086}
10701087
10711088#define PG_STAT_STATEMENTS_COLS_V1_0 14
1072- #define PG_STAT_STATEMENTS_COLS 18
1089+ #define PG_STAT_STATEMENTS_COLS_V1_1 18
1090+ #define PG_STAT_STATEMENTS_COLS 19
10731091
10741092/*
10751093 * Retrieve statement statistics.
@@ -1086,7 +1104,7 @@ pg_stat_statements(PG_FUNCTION_ARGS)
10861104 bool is_superuser = superuser ();
10871105 HASH_SEQ_STATUS hash_seq ;
10881106 pgssEntry * entry ;
1089- bool sql_supports_v1_1_counters = true ;
1107+ pgssVersion detected_version ;
10901108
10911109 if (!pgss || !pgss_hash )
10921110 ereport (ERROR ,
@@ -1107,8 +1125,21 @@ pg_stat_statements(PG_FUNCTION_ARGS)
11071125 /* Build a tuple descriptor for our result type */
11081126 if (get_call_result_type (fcinfo , NULL , & tupdesc ) != TYPEFUNC_COMPOSITE )
11091127 elog (ERROR , "return type must be a row type" );
1110- if (tupdesc -> natts == PG_STAT_STATEMENTS_COLS_V1_0 )
1111- sql_supports_v1_1_counters = false;
1128+
1129+ switch (tupdesc -> natts )
1130+ {
1131+ case PG_STAT_STATEMENTS_COLS_V1_0 :
1132+ detected_version = PGSS_V1_0 ;
1133+ break ;
1134+ case PG_STAT_STATEMENTS_COLS_V1_1 :
1135+ detected_version = PGSS_V1_1 ;
1136+ break ;
1137+ case PG_STAT_STATEMENTS_COLS :
1138+ detected_version = PGSS_V1_2 ;
1139+ break ;
1140+ default :
1141+ elog (ERROR , "pgss version unrecognized from tuple descriptor" );
1142+ }
11121143
11131144 per_query_ctx = rsinfo -> econtext -> ecxt_per_query_memory ;
11141145 oldcontext = MemoryContextSwitchTo (per_query_ctx );
@@ -1140,6 +1171,9 @@ pg_stat_statements(PG_FUNCTION_ARGS)
11401171 {
11411172 char * qstr ;
11421173
1174+ if (detected_version >= PGSS_V1_2 )
1175+ values [i ++ ] = Int64GetDatumFast ((int64 ) entry -> key .queryid );
1176+
11431177 qstr = (char * )
11441178 pg_do_encoding_conversion ((unsigned char * ) entry -> query ,
11451179 entry -> query_len ,
@@ -1150,7 +1184,12 @@ pg_stat_statements(PG_FUNCTION_ARGS)
11501184 pfree (qstr );
11511185 }
11521186 else
1187+ {
1188+ if (detected_version >= PGSS_V1_2 )
1189+ nulls [i ++ ] = true;
1190+
11531191 values [i ++ ] = CStringGetTextDatum ("<insufficient privilege>" );
1192+ }
11541193
11551194 /* copy counters to a local variable to keep locking time short */
11561195 {
@@ -1170,24 +1209,27 @@ pg_stat_statements(PG_FUNCTION_ARGS)
11701209 values [i ++ ] = Int64GetDatumFast (tmp .rows );
11711210 values [i ++ ] = Int64GetDatumFast (tmp .shared_blks_hit );
11721211 values [i ++ ] = Int64GetDatumFast (tmp .shared_blks_read );
1173- if (sql_supports_v1_1_counters )
1212+ if (detected_version >= PGSS_V1_1 )
11741213 values [i ++ ] = Int64GetDatumFast (tmp .shared_blks_dirtied );
11751214 values [i ++ ] = Int64GetDatumFast (tmp .shared_blks_written );
11761215 values [i ++ ] = Int64GetDatumFast (tmp .local_blks_hit );
11771216 values [i ++ ] = Int64GetDatumFast (tmp .local_blks_read );
1178- if (sql_supports_v1_1_counters )
1217+ if (detected_version >= PGSS_V1_1 )
11791218 values [i ++ ] = Int64GetDatumFast (tmp .local_blks_dirtied );
11801219 values [i ++ ] = Int64GetDatumFast (tmp .local_blks_written );
11811220 values [i ++ ] = Int64GetDatumFast (tmp .temp_blks_read );
11821221 values [i ++ ] = Int64GetDatumFast (tmp .temp_blks_written );
1183- if (sql_supports_v1_1_counters )
1222+ if (detected_version >= PGSS_V1_1 )
11841223 {
11851224 values [i ++ ] = Float8GetDatumFast (tmp .blk_read_time );
11861225 values [i ++ ] = Float8GetDatumFast (tmp .blk_write_time );
11871226 }
11881227
1189- Assert (i == (sql_supports_v1_1_counters ?
1190- PG_STAT_STATEMENTS_COLS : PG_STAT_STATEMENTS_COLS_V1_0 ));
1228+ Assert (i == (detected_version == PGSS_V1_0 ?
1229+ PG_STAT_STATEMENTS_COLS_V1_0 :
1230+ detected_version == PGSS_V1_1 ?
1231+ PG_STAT_STATEMENTS_COLS_V1_1 :
1232+ PG_STAT_STATEMENTS_COLS ));
11911233
11921234 tuplestore_putvalues (tupstore , tupdesc , values , nulls );
11931235 }
0 commit comments