@@ -87,7 +87,7 @@ PG_MODULE_MAGIC;
87
87
#define PGSS_TEXT_FILE PG_STAT_TMP_DIR "/pgss_query_texts.stat"
88
88
89
89
/* Magic number identifying the stats file format */
90
- static const uint32 PGSS_FILE_HEADER = 0x20201218 ;
90
+ static const uint32 PGSS_FILE_HEADER = 0x20201227 ;
91
91
92
92
/* PostgreSQL major version number, changes in which invalidate all entries */
93
93
static const uint32 PGSS_PG_MAJOR_VERSION = PG_VERSION_NUM / 100 ;
@@ -119,7 +119,8 @@ typedef enum pgssVersion
119
119
PGSS_V1_1 ,
120
120
PGSS_V1_2 ,
121
121
PGSS_V1_3 ,
122
- PGSS_V1_8
122
+ PGSS_V1_8 ,
123
+ PGSS_V1_10
123
124
} pgssVersion ;
124
125
125
126
typedef enum pgssStoreKind
@@ -141,16 +142,17 @@ typedef enum pgssStoreKind
141
142
* Hashtable key that defines the identity of a hashtable entry. We separate
142
143
* queries by user and by database even if they are otherwise identical.
143
144
*
144
- * Right now, this structure contains no padding. If you add any , make sure
145
- * to teach pgss_store() to zero the padding bytes. Otherwise, things will
146
- * break, because pgss_hash is created using HASH_BLOBS, and thus tag_hash
147
- * is used to hash this.
145
+ * If you add a new key to this struct , make sure to teach pgss_store() to
146
+ * zero the padding bytes. Otherwise, things will break, because pgss_hash is
147
+ * created using HASH_BLOBS, and thus tag_hash is used to hash this.
148
+
148
149
*/
149
150
typedef struct pgssHashKey
150
151
{
151
152
Oid userid ; /* user OID */
152
153
Oid dbid ; /* database OID */
153
154
uint64 queryid ; /* query identifier */
155
+ bool toplevel ; /* query executed at top level */
154
156
} pgssHashKey ;
155
157
156
158
/*
@@ -297,6 +299,7 @@ PG_FUNCTION_INFO_V1(pg_stat_statements_reset_1_7);
297
299
PG_FUNCTION_INFO_V1 (pg_stat_statements_1_2 );
298
300
PG_FUNCTION_INFO_V1 (pg_stat_statements_1_3 );
299
301
PG_FUNCTION_INFO_V1 (pg_stat_statements_1_8 );
302
+ PG_FUNCTION_INFO_V1 (pg_stat_statements_1_10 );
300
303
PG_FUNCTION_INFO_V1 (pg_stat_statements );
301
304
PG_FUNCTION_INFO_V1 (pg_stat_statements_info );
302
305
@@ -1224,9 +1227,14 @@ pgss_store(const char *query, uint64 queryId,
1224
1227
query = CleanQuerytext (query , & query_location , & query_len );
1225
1228
1226
1229
/* Set up key for hashtable search */
1230
+
1231
+ /* memset() is required when pgssHashKey is without padding only */
1232
+ memset (& key , 0 , sizeof (pgssHashKey ));
1233
+
1227
1234
key .userid = GetUserId ();
1228
1235
key .dbid = MyDatabaseId ;
1229
1236
key .queryid = queryId ;
1237
+ key .toplevel = (exec_nested_level == 0 );
1230
1238
1231
1239
/* Lookup the hash table entry with shared lock. */
1232
1240
LWLockAcquire (pgss -> lock , LW_SHARED );
@@ -1406,7 +1414,8 @@ pg_stat_statements_reset(PG_FUNCTION_ARGS)
1406
1414
#define PG_STAT_STATEMENTS_COLS_V1_2 19
1407
1415
#define PG_STAT_STATEMENTS_COLS_V1_3 23
1408
1416
#define PG_STAT_STATEMENTS_COLS_V1_8 32
1409
- #define PG_STAT_STATEMENTS_COLS 32 /* maximum of above */
1417
+ #define PG_STAT_STATEMENTS_COLS_V1_10 33
1418
+ #define PG_STAT_STATEMENTS_COLS 33 /* maximum of above */
1410
1419
1411
1420
/*
1412
1421
* Retrieve statement statistics.
@@ -1418,6 +1427,16 @@ pg_stat_statements_reset(PG_FUNCTION_ARGS)
1418
1427
* expected API version is identified by embedding it in the C name of the
1419
1428
* function. Unfortunately we weren't bright enough to do that for 1.1.
1420
1429
*/
1430
+ Datum
1431
+ pg_stat_statements_1_10 (PG_FUNCTION_ARGS )
1432
+ {
1433
+ bool showtext = PG_GETARG_BOOL (0 );
1434
+
1435
+ pg_stat_statements_internal (fcinfo , PGSS_V1_10 , showtext );
1436
+
1437
+ return (Datum ) 0 ;
1438
+ }
1439
+
1421
1440
Datum
1422
1441
pg_stat_statements_1_8 (PG_FUNCTION_ARGS )
1423
1442
{
@@ -1537,6 +1556,10 @@ pg_stat_statements_internal(FunctionCallInfo fcinfo,
1537
1556
if (api_version != PGSS_V1_8 )
1538
1557
elog (ERROR , "incorrect number of output arguments" );
1539
1558
break ;
1559
+ case PG_STAT_STATEMENTS_COLS_V1_10 :
1560
+ if (api_version != PGSS_V1_10 )
1561
+ elog (ERROR , "incorrect number of output arguments" );
1562
+ break ;
1540
1563
default :
1541
1564
elog (ERROR , "incorrect number of output arguments" );
1542
1565
}
@@ -1628,6 +1651,8 @@ pg_stat_statements_internal(FunctionCallInfo fcinfo,
1628
1651
1629
1652
values [i ++ ] = ObjectIdGetDatum (entry -> key .userid );
1630
1653
values [i ++ ] = ObjectIdGetDatum (entry -> key .dbid );
1654
+ if (api_version >= PGSS_V1_10 )
1655
+ values [i ++ ] = BoolGetDatum (entry -> key .toplevel );
1631
1656
1632
1657
if (is_allowed_role || entry -> key .userid == userid )
1633
1658
{
@@ -1765,6 +1790,7 @@ pg_stat_statements_internal(FunctionCallInfo fcinfo,
1765
1790
api_version == PGSS_V1_2 ? PG_STAT_STATEMENTS_COLS_V1_2 :
1766
1791
api_version == PGSS_V1_3 ? PG_STAT_STATEMENTS_COLS_V1_3 :
1767
1792
api_version == PGSS_V1_8 ? PG_STAT_STATEMENTS_COLS_V1_8 :
1793
+ api_version == PGSS_V1_10 ? PG_STAT_STATEMENTS_COLS_V1_10 :
1768
1794
-1 /* fail if you forget to update this assert */ ));
1769
1795
1770
1796
tuplestore_putvalues (tupstore , tupdesc , values , nulls );
@@ -2437,10 +2463,20 @@ entry_reset(Oid userid, Oid dbid, uint64 queryid)
2437
2463
if (userid != 0 && dbid != 0 && queryid != UINT64CONST (0 ))
2438
2464
{
2439
2465
/* If all the parameters are available, use the fast path. */
2466
+ memset (& key , 0 , sizeof (pgssHashKey ));
2440
2467
key .userid = userid ;
2441
2468
key .dbid = dbid ;
2442
2469
key .queryid = queryid ;
2443
2470
2471
+ /* Remove the key if it exists, starting with the top-level entry */
2472
+ key .toplevel = false;
2473
+ entry = (pgssEntry * ) hash_search (pgss_hash , & key , HASH_REMOVE , NULL );
2474
+ if (entry ) /* found */
2475
+ num_remove ++ ;
2476
+
2477
+ /* Also remove entries for top level statements */
2478
+ key .toplevel = true;
2479
+
2444
2480
/* Remove the key if exists */
2445
2481
entry = (pgssEntry * ) hash_search (pgss_hash , & key , HASH_REMOVE , NULL );
2446
2482
if (entry ) /* found */
0 commit comments