diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c index 137b242ea97cf2cfa08021eac45236533a14fcce..58c85ded58717117bd835f69a4abedc5d93d2be1 100644 --- a/contrib/pg_stat_statements/pg_stat_statements.c +++ b/contrib/pg_stat_statements/pg_stat_statements.c @@ -602,9 +602,19 @@ pgss_post_parse_analyze(ParseState *pstate, Query *query) if (!pgss || !pgss_hash) return; - /* We do nothing with utility statements at this stage */ + /* + * 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. + */ if (query->utilityStmt) + { + query->queryId = 0; return; + } /* Set up workspace for query jumbling */ jstate.jumble = (unsigned char *) palloc(JUMBLE_SIZE); @@ -618,6 +628,13 @@ pgss_post_parse_analyze(ParseState *pstate, Query *query) JumbleQuery(&jstate, query); query->queryId = hash_any(jstate.jumble, jstate.jumble_len); + /* + * If we are unlucky enough to get a hash of zero, use 1 instead, to + * prevent confusion with the utility-statement case. + */ + if (query->queryId == 0) + query->queryId = 1; + /* * If we were able to identify any ignorable constants, we immediately * create a hash table entry for the query, so that we can record the @@ -649,7 +666,12 @@ pgss_ExecutorStart(QueryDesc *queryDesc, int eflags) else standard_ExecutorStart(queryDesc, eflags); - if (pgss_enabled()) + /* + * If query has queryId zero, don't track it. This prevents double + * counting of optimizable statements that are directly contained in + * utility statements. + */ + if (pgss_enabled() && queryDesc->plannedstmt->queryId != 0) { /* * Set up to track total elapsed time in ExecutorRun. Make sure the @@ -719,13 +741,10 @@ pgss_ExecutorFinish(QueryDesc *queryDesc) static void pgss_ExecutorEnd(QueryDesc *queryDesc) { - if (queryDesc->totaltime && pgss_enabled()) - { - uint32 queryId; - - /* Query's ID should have been filled in by post-analyze hook */ - queryId = queryDesc->plannedstmt->queryId; + uint32 queryId = queryDesc->plannedstmt->queryId; + if (queryId != 0 && queryDesc->totaltime && pgss_enabled()) + { /* * Make sure stats accumulation is done. (Note: it's okay if several * levels of hook all do this.) @@ -1794,6 +1813,8 @@ JumbleExpr(pgssJumbleState * jstate, Node *node) { CommonTableExpr *cte = (CommonTableExpr *) node; + /* we store the string name because RTE_CTE RTEs need it */ + APP_JUMB_STRING(cte->ctename); JumbleQuery(jstate, (Query *) cte->ctequery); } break;