mirror of
https://github.com/postgres/postgres.git
synced 2025-06-11 20:28:21 +03:00
Make use of in-core query id added by commit 5fd9dfa5f5
Use the in-core query id computation for pg_stat_activity, log_line_prefix, and EXPLAIN VERBOSE. Similar to other fields in pg_stat_activity, only the queryid from the top level statements are exposed, and if the backends status isn't active then the queryid from the last executed statements is displayed. Add a %Q placeholder to include the queryid in log_line_prefix, which will also only expose top level statements. For EXPLAIN VERBOSE, if a query identifier has been computed, either by enabling compute_query_id or using a third-party module, display it. Bump catalog version. Discussion: https://postgr.es/m/20210407125726.tkvjdbw76hxnpwfi@nol Author: Julien Rouhaud Reviewed-by: Alvaro Herrera, Nitin Jadhav, Zhihong Yu
This commit is contained in:
@ -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"
|
||||
|
||||
@ -101,6 +102,14 @@ static const uint32 PGSS_PG_MAJOR_VERSION = PG_VERSION_NUM / 100;
|
||||
#define USAGE_DEALLOC_PERCENT 5 /* free this % of entries at once */
|
||||
#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
|
||||
*/
|
||||
@ -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,
|
||||
@ -1153,23 +1174,12 @@ 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.
|
||||
*/
|
||||
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--;
|
||||
|
||||
/*
|
||||
* For utility statements, we just hash the query string to get an ID.
|
||||
* Nothing to do if compute_query_id isn't enabled and no other module
|
||||
* computed a query identifier.
|
||||
*/
|
||||
if (queryId == UINT64CONST(0))
|
||||
{
|
||||
queryId = pgss_hash_string(query, query_len);
|
||||
return;
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
query = CleanQuerytext(query, &query_location, &query_len);
|
||||
|
||||
/* Set up key for hashtable search */
|
||||
key.userid = GetUserId();
|
||||
|
Reference in New Issue
Block a user