67
67
#include "tcop/utility.h"
68
68
#include "utils/acl.h"
69
69
#include "utils/builtins.h"
70
+ #include "utils/queryjumble.h"
70
71
#include "utils/memutils.h"
71
72
#include "utils/timestamp.h"
72
73
@@ -101,6 +102,14 @@ static const uint32 PGSS_PG_MAJOR_VERSION = PG_VERSION_NUM / 100;
101
102
#define USAGE_DEALLOC_PERCENT 5 /* free this % of entries at once */
102
103
#define IS_STICKY (c ) ((c.calls[PGSS_PLAN] + c.calls[PGSS_EXEC]) == 0)
103
104
105
+ /*
106
+ * Utility statements that pgss_ProcessUtility and pgss_post_parse_analyze
107
+ * ignores.
108
+ */
109
+ #define PGSS_HANDLED_UTILITY (n ) (!IsA(n, ExecuteStmt) && \
110
+ !IsA(n, PrepareStmt) && \
111
+ !IsA(n, DeallocateStmt))
112
+
104
113
/*
105
114
* Extension version number, for supporting older extension versions' objects
106
115
*/
@@ -309,7 +318,6 @@ static void pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
309
318
ProcessUtilityContext context , ParamListInfo params ,
310
319
QueryEnvironment * queryEnv ,
311
320
DestReceiver * dest , QueryCompletion * qc );
312
- static uint64 pgss_hash_string (const char * str , int len );
313
321
static void pgss_store (const char * query , uint64 queryId ,
314
322
int query_location , int query_len ,
315
323
pgssStoreKind kind ,
@@ -806,16 +814,14 @@ pgss_post_parse_analyze(ParseState *pstate, Query *query, JumbleState *jstate)
806
814
return ;
807
815
808
816
/*
809
- * Utility statements get queryId zero. We do this even in cases where
810
- * the statement contains an optimizable statement for which a queryId
811
- * could be derived (such as EXPLAIN or DECLARE CURSOR). For such cases,
812
- * runtime control will first go through ProcessUtility and then the
813
- * executor, and we don't want the executor hooks to do anything, since we
814
- * are already measuring the statement's costs at the utility level.
817
+ * Clear queryId for prepared statements related utility, as those will
818
+ * inherit from the underlying statement's one (except DEALLOCATE which is
819
+ * entirely untracked).
815
820
*/
816
821
if (query -> utilityStmt )
817
822
{
818
- query -> queryId = UINT64CONST (0 );
823
+ if (pgss_track_utility && !PGSS_HANDLED_UTILITY (query -> utilityStmt ))
824
+ query -> queryId = UINT64CONST (0 );
819
825
return ;
820
826
}
821
827
@@ -1057,6 +1063,23 @@ pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
1057
1063
DestReceiver * dest , QueryCompletion * qc )
1058
1064
{
1059
1065
Node * parsetree = pstmt -> utilityStmt ;
1066
+ uint64 saved_queryId = pstmt -> queryId ;
1067
+
1068
+ /*
1069
+ * Force utility statements to get queryId zero. We do this even in cases
1070
+ * where the statement contains an optimizable statement for which a
1071
+ * queryId could be derived (such as EXPLAIN or DECLARE CURSOR). For such
1072
+ * cases, runtime control will first go through ProcessUtility and then the
1073
+ * executor, and we don't want the executor hooks to do anything, since we
1074
+ * are already measuring the statement's costs at the utility level.
1075
+ *
1076
+ * Note that this is only done if pg_stat_statements is enabled and
1077
+ * configured to track utility statements, in the unlikely possibility
1078
+ * that user configured another extension to handle utility statements
1079
+ * only.
1080
+ */
1081
+ if (pgss_enabled (exec_nested_level ) && pgss_track_utility )
1082
+ pstmt -> queryId = UINT64CONST (0 );
1060
1083
1061
1084
/*
1062
1085
* If it's an EXECUTE statement, we don't track it and don't increment the
@@ -1073,9 +1096,7 @@ pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
1073
1096
* Likewise, we don't track execution of DEALLOCATE.
1074
1097
*/
1075
1098
if (pgss_track_utility && pgss_enabled (exec_nested_level ) &&
1076
- !IsA (parsetree , ExecuteStmt ) &&
1077
- !IsA (parsetree , PrepareStmt ) &&
1078
- !IsA (parsetree , DeallocateStmt ))
1099
+ PGSS_HANDLED_UTILITY (parsetree ))
1079
1100
{
1080
1101
instr_time start ;
1081
1102
instr_time duration ;
@@ -1130,7 +1151,7 @@ pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
1130
1151
WalUsageAccumDiff (& walusage , & pgWalUsage , & walusage_start );
1131
1152
1132
1153
pgss_store (queryString ,
1133
- 0 , /* signal that it's a utility stmt */
1154
+ saved_queryId ,
1134
1155
pstmt -> stmt_location ,
1135
1156
pstmt -> stmt_len ,
1136
1157
PGSS_EXEC ,
@@ -1153,23 +1174,12 @@ pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
1153
1174
}
1154
1175
}
1155
1176
1156
- /*
1157
- * Given an arbitrarily long query string, produce a hash for the purposes of
1158
- * identifying the query, without normalizing constants. Used when hashing
1159
- * utility statements.
1160
- */
1161
- static uint64
1162
- pgss_hash_string (const char * str , int len )
1163
- {
1164
- return DatumGetUInt64 (hash_any_extended ((const unsigned char * ) str ,
1165
- len , 0 ));
1166
- }
1167
-
1168
1177
/*
1169
1178
* Store some statistics for a statement.
1170
1179
*
1171
- * If queryId is 0 then this is a utility statement and we should compute
1172
- * a suitable queryId internally.
1180
+ * If queryId is 0 then this is a utility statement for which we couldn't
1181
+ * compute a queryId during parse analysis, and we should compute a suitable
1182
+ * queryId internally.
1173
1183
*
1174
1184
* If jstate is not NULL then we're trying to create an entry for which
1175
1185
* we have no statistics as yet; we just want to record the normalized
@@ -1200,52 +1210,18 @@ pgss_store(const char *query, uint64 queryId,
1200
1210
return ;
1201
1211
1202
1212
/*
1203
- * Confine our attention to the relevant part of the string, if the query
1204
- * is a portion of a multi-statement source string.
1205
- *
1206
- * First apply starting offset, unless it's -1 (unknown).
1207
- */
1208
- if (query_location >= 0 )
1209
- {
1210
- Assert (query_location <= strlen (query ));
1211
- query += query_location ;
1212
- /* Length of 0 (or -1) means "rest of string" */
1213
- if (query_len <= 0 )
1214
- query_len = strlen (query );
1215
- else
1216
- Assert (query_len <= strlen (query ));
1217
- }
1218
- else
1219
- {
1220
- /* If query location is unknown, distrust query_len as well */
1221
- query_location = 0 ;
1222
- query_len = strlen (query );
1223
- }
1224
-
1225
- /*
1226
- * Discard leading and trailing whitespace, too. Use scanner_isspace()
1227
- * not libc's isspace(), because we want to match the lexer's behavior.
1213
+ * Nothing to do if compute_query_id isn't enabled and no other module
1214
+ * computed a query identifier.
1228
1215
*/
1229
- while (query_len > 0 && scanner_isspace (query [0 ]))
1230
- query ++ , query_location ++ , query_len -- ;
1231
- while (query_len > 0 && scanner_isspace (query [query_len - 1 ]))
1232
- query_len -- ;
1216
+ if (queryId == UINT64CONST (0 ))
1217
+ return ;
1233
1218
1234
1219
/*
1235
- * For utility statements, we just hash the query string to get an ID.
1220
+ * Confine our attention to the relevant part of the string, if the query
1221
+ * is a portion of a multi-statement source string, and update query
1222
+ * location and length if needed.
1236
1223
*/
1237
- if (queryId == UINT64CONST (0 ))
1238
- {
1239
- queryId = pgss_hash_string (query , query_len );
1240
-
1241
- /*
1242
- * If we are unlucky enough to get a hash of zero(invalid), use
1243
- * queryID as 2 instead, queryID 1 is already in use for normal
1244
- * statements.
1245
- */
1246
- if (queryId == UINT64CONST (0 ))
1247
- queryId = UINT64CONST (2 );
1248
- }
1224
+ query = CleanQuerytext (query , & query_location , & query_len );
1249
1225
1250
1226
/* Set up key for hashtable search */
1251
1227
key .userid = GetUserId ();
0 commit comments