6767#include "tcop/utility.h"
6868#include "utils/acl.h"
6969#include "utils/builtins.h"
70+ #include "utils/queryjumble.h"
7071#include "utils/memutils.h"
7172#include "utils/timestamp.h"
7273
@@ -101,6 +102,14 @@ static const uint32 PGSS_PG_MAJOR_VERSION = PG_VERSION_NUM / 100;
101102#define USAGE_DEALLOC_PERCENT 5 /* free this % of entries at once */
102103#define IS_STICKY (c ) ((c.calls[PGSS_PLAN] + c.calls[PGSS_EXEC]) == 0)
103104
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+
104113/*
105114 * Extension version number, for supporting older extension versions' objects
106115 */
@@ -309,7 +318,6 @@ static void pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
309318 ProcessUtilityContext context , ParamListInfo params ,
310319 QueryEnvironment * queryEnv ,
311320 DestReceiver * dest , QueryCompletion * qc );
312- static uint64 pgss_hash_string (const char * str , int len );
313321static void pgss_store (const char * query , uint64 queryId ,
314322 int query_location , int query_len ,
315323 pgssStoreKind kind ,
@@ -806,16 +814,14 @@ pgss_post_parse_analyze(ParseState *pstate, Query *query, JumbleState *jstate)
806814 return ;
807815
808816 /*
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).
815820 */
816821 if (query -> utilityStmt )
817822 {
818- query -> queryId = UINT64CONST (0 );
823+ if (pgss_track_utility && !PGSS_HANDLED_UTILITY (query -> utilityStmt ))
824+ query -> queryId = UINT64CONST (0 );
819825 return ;
820826 }
821827
@@ -1057,6 +1063,23 @@ pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
10571063 DestReceiver * dest , QueryCompletion * qc )
10581064{
10591065 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 );
10601083
10611084 /*
10621085 * 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,
10731096 * Likewise, we don't track execution of DEALLOCATE.
10741097 */
10751098 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 ))
10791100 {
10801101 instr_time start ;
10811102 instr_time duration ;
@@ -1130,7 +1151,7 @@ pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
11301151 WalUsageAccumDiff (& walusage , & pgWalUsage , & walusage_start );
11311152
11321153 pgss_store (queryString ,
1133- 0 , /* signal that it's a utility stmt */
1154+ saved_queryId ,
11341155 pstmt -> stmt_location ,
11351156 pstmt -> stmt_len ,
11361157 PGSS_EXEC ,
@@ -1153,23 +1174,12 @@ pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
11531174 }
11541175}
11551176
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-
11681177/*
11691178 * Store some statistics for a statement.
11701179 *
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.
11731183 *
11741184 * If jstate is not NULL then we're trying to create an entry for which
11751185 * we have no statistics as yet; we just want to record the normalized
@@ -1200,52 +1210,18 @@ pgss_store(const char *query, uint64 queryId,
12001210 return ;
12011211
12021212 /*
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.
12281215 */
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 ;
12331218
12341219 /*
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.
12361223 */
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 );
12491225
12501226 /* Set up key for hashtable search */
12511227 key .userid = GetUserId ();
0 commit comments