aboutsummaryrefslogtreecommitdiff
path: root/contrib/pg_stat_statements/pg_stat_statements.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/pg_stat_statements/pg_stat_statements.c')
-rw-r--r--contrib/pg_stat_statements/pg_stat_statements.c112
1 files changed, 44 insertions, 68 deletions
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 0f8bac0ccae..52cba861969 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -67,6 +67,7 @@
#include "tcop/utility.h"
#include "utils/acl.h"
#include "utils/builtins.h"
+#include "utils/queryjumble.h"
#include "utils/memutils.h"
#include "utils/timestamp.h"
@@ -102,6 +103,14 @@ static const uint32 PGSS_PG_MAJOR_VERSION = PG_VERSION_NUM / 100;
#define IS_STICKY(c) ((c.calls[PGSS_PLAN] + c.calls[PGSS_EXEC]) == 0)
/*
+ * Utility statements that pgss_ProcessUtility and pgss_post_parse_analyze
+ * ignores.
+ */
+#define PGSS_HANDLED_UTILITY(n) (!IsA(n, ExecuteStmt) && \
+ !IsA(n, PrepareStmt) && \
+ !IsA(n, DeallocateStmt))
+
+/*
* Extension version number, for supporting older extension versions' objects
*/
typedef enum pgssVersion
@@ -309,7 +318,6 @@ static void pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
ProcessUtilityContext context, ParamListInfo params,
QueryEnvironment *queryEnv,
DestReceiver *dest, QueryCompletion *qc);
-static uint64 pgss_hash_string(const char *str, int len);
static void pgss_store(const char *query, uint64 queryId,
int query_location, int query_len,
pgssStoreKind kind,
@@ -806,16 +814,14 @@ pgss_post_parse_analyze(ParseState *pstate, Query *query, JumbleState *jstate)
return;
/*
- * Utility statements get queryId zero. We do this even in cases where
- * the statement contains an optimizable statement for which a queryId
- * could be derived (such as EXPLAIN or DECLARE CURSOR). For such cases,
- * runtime control will first go through ProcessUtility and then the
- * executor, and we don't want the executor hooks to do anything, since we
- * are already measuring the statement's costs at the utility level.
+ * Clear queryId for prepared statements related utility, as those will
+ * inherit from the underlying statement's one (except DEALLOCATE which is
+ * entirely untracked).
*/
if (query->utilityStmt)
{
- query->queryId = UINT64CONST(0);
+ if (pgss_track_utility && !PGSS_HANDLED_UTILITY(query->utilityStmt))
+ query->queryId = UINT64CONST(0);
return;
}
@@ -1057,6 +1063,23 @@ pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
DestReceiver *dest, QueryCompletion *qc)
{
Node *parsetree = pstmt->utilityStmt;
+ uint64 saved_queryId = pstmt->queryId;
+
+ /*
+ * Force utility statements to get queryId zero. We do this even in cases
+ * where the statement contains an optimizable statement for which a
+ * queryId could be derived (such as EXPLAIN or DECLARE CURSOR). For such
+ * cases, runtime control will first go through ProcessUtility and then the
+ * executor, and we don't want the executor hooks to do anything, since we
+ * are already measuring the statement's costs at the utility level.
+ *
+ * Note that this is only done if pg_stat_statements is enabled and
+ * configured to track utility statements, in the unlikely possibility
+ * that user configured another extension to handle utility statements
+ * only.
+ */
+ if (pgss_enabled(exec_nested_level) && pgss_track_utility)
+ pstmt->queryId = UINT64CONST(0);
/*
* 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,
* Likewise, we don't track execution of DEALLOCATE.
*/
if (pgss_track_utility && pgss_enabled(exec_nested_level) &&
- !IsA(parsetree, ExecuteStmt) &&
- !IsA(parsetree, PrepareStmt) &&
- !IsA(parsetree, DeallocateStmt))
+ PGSS_HANDLED_UTILITY(parsetree))
{
instr_time start;
instr_time duration;
@@ -1130,7 +1151,7 @@ pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
WalUsageAccumDiff(&walusage, &pgWalUsage, &walusage_start);
pgss_store(queryString,
- 0, /* signal that it's a utility stmt */
+ saved_queryId,
pstmt->stmt_location,
pstmt->stmt_len,
PGSS_EXEC,
@@ -1154,22 +1175,11 @@ pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
}
/*
- * Given an arbitrarily long query string, produce a hash for the purposes of
- * identifying the query, without normalizing constants. Used when hashing
- * utility statements.
- */
-static uint64
-pgss_hash_string(const char *str, int len)
-{
- return DatumGetUInt64(hash_any_extended((const unsigned char *) str,
- len, 0));
-}
-
-/*
* Store some statistics for a statement.
*
- * If queryId is 0 then this is a utility statement and we should compute
- * a suitable queryId internally.
+ * If queryId is 0 then this is a utility statement for which we couldn't
+ * compute a queryId during parse analysis, and we should compute a suitable
+ * queryId internally.
*
* If jstate is not NULL then we're trying to create an entry for which
* we have no statistics as yet; we just want to record the normalized
@@ -1200,52 +1210,18 @@ pgss_store(const char *query, uint64 queryId,
return;
/*
- * Confine our attention to the relevant part of the string, if the query
- * is a portion of a multi-statement source string.
- *
- * First apply starting offset, unless it's -1 (unknown).
- */
- if (query_location >= 0)
- {
- Assert(query_location <= strlen(query));
- query += query_location;
- /* Length of 0 (or -1) means "rest of string" */
- if (query_len <= 0)
- query_len = strlen(query);
- else
- Assert(query_len <= strlen(query));
- }
- else
- {
- /* If query location is unknown, distrust query_len as well */
- query_location = 0;
- query_len = strlen(query);
- }
-
- /*
- * Discard leading and trailing whitespace, too. Use scanner_isspace()
- * not libc's isspace(), because we want to match the lexer's behavior.
+ * Nothing to do if compute_query_id isn't enabled and no other module
+ * computed a query identifier.
*/
- while (query_len > 0 && scanner_isspace(query[0]))
- query++, query_location++, query_len--;
- while (query_len > 0 && scanner_isspace(query[query_len - 1]))
- query_len--;
+ if (queryId == UINT64CONST(0))
+ return;
/*
- * For utility statements, we just hash the query string to get an ID.
+ * Confine our attention to the relevant part of the string, if the query
+ * is a portion of a multi-statement source string, and update query
+ * location and length if needed.
*/
- if (queryId == UINT64CONST(0))
- {
- queryId = pgss_hash_string(query, query_len);
-
- /*
- * If we are unlucky enough to get a hash of zero(invalid), use
- * queryID as 2 instead, queryID 1 is already in use for normal
- * statements.
- */
- if (queryId == UINT64CONST(0))
- queryId = UINT64CONST(2);
- }
+ query = CleanQuerytext(query, &query_location, &query_len);
/* Set up key for hashtable search */
key.userid = GetUserId();