Commit a40fa613 authored by Tom Lane's avatar Tom Lane

Add some infrastructure for contrib/pg_stat_statements.

Add a queryId field to Query and PlannedStmt.  This is not used by the
core backend, except for being copied around at appropriate times.
It's meant to allow plug-ins to track a particular query forward from
parse analysis to execution.

The queryId is intentionally not dumped into stored rules (and hence this
commit doesn't bump catversion).  You could argue that choice either way,
but it seems better that stored rule strings not have any dependency
on plug-ins that might or might not be present.

Also, add a post_parse_analyze_hook that gets invoked at the end of
parse analysis (but only for top-level analysis of complete queries,
not cases such as analyzing a domain's default-value expression).
This is mainly meant to be used to compute and assign a queryId,
but it could have other applications.

Peter Geoghegan
parent 40b9b957
...@@ -78,6 +78,7 @@ _copyPlannedStmt(const PlannedStmt *from) ...@@ -78,6 +78,7 @@ _copyPlannedStmt(const PlannedStmt *from)
PlannedStmt *newnode = makeNode(PlannedStmt); PlannedStmt *newnode = makeNode(PlannedStmt);
COPY_SCALAR_FIELD(commandType); COPY_SCALAR_FIELD(commandType);
COPY_SCALAR_FIELD(queryId);
COPY_SCALAR_FIELD(hasReturning); COPY_SCALAR_FIELD(hasReturning);
COPY_SCALAR_FIELD(hasModifyingCTE); COPY_SCALAR_FIELD(hasModifyingCTE);
COPY_SCALAR_FIELD(canSetTag); COPY_SCALAR_FIELD(canSetTag);
...@@ -2402,6 +2403,7 @@ _copyQuery(const Query *from) ...@@ -2402,6 +2403,7 @@ _copyQuery(const Query *from)
COPY_SCALAR_FIELD(commandType); COPY_SCALAR_FIELD(commandType);
COPY_SCALAR_FIELD(querySource); COPY_SCALAR_FIELD(querySource);
COPY_SCALAR_FIELD(queryId);
COPY_SCALAR_FIELD(canSetTag); COPY_SCALAR_FIELD(canSetTag);
COPY_NODE_FIELD(utilityStmt); COPY_NODE_FIELD(utilityStmt);
COPY_SCALAR_FIELD(resultRelation); COPY_SCALAR_FIELD(resultRelation);
......
...@@ -897,6 +897,7 @@ _equalQuery(const Query *a, const Query *b) ...@@ -897,6 +897,7 @@ _equalQuery(const Query *a, const Query *b)
{ {
COMPARE_SCALAR_FIELD(commandType); COMPARE_SCALAR_FIELD(commandType);
COMPARE_SCALAR_FIELD(querySource); COMPARE_SCALAR_FIELD(querySource);
/* we intentionally ignore queryId, since it might not be set */
COMPARE_SCALAR_FIELD(canSetTag); COMPARE_SCALAR_FIELD(canSetTag);
COMPARE_NODE_FIELD(utilityStmt); COMPARE_NODE_FIELD(utilityStmt);
COMPARE_SCALAR_FIELD(resultRelation); COMPARE_SCALAR_FIELD(resultRelation);
......
...@@ -242,6 +242,7 @@ _outPlannedStmt(StringInfo str, const PlannedStmt *node) ...@@ -242,6 +242,7 @@ _outPlannedStmt(StringInfo str, const PlannedStmt *node)
WRITE_NODE_TYPE("PLANNEDSTMT"); WRITE_NODE_TYPE("PLANNEDSTMT");
WRITE_ENUM_FIELD(commandType, CmdType); WRITE_ENUM_FIELD(commandType, CmdType);
WRITE_UINT_FIELD(queryId);
WRITE_BOOL_FIELD(hasReturning); WRITE_BOOL_FIELD(hasReturning);
WRITE_BOOL_FIELD(hasModifyingCTE); WRITE_BOOL_FIELD(hasModifyingCTE);
WRITE_BOOL_FIELD(canSetTag); WRITE_BOOL_FIELD(canSetTag);
...@@ -2152,6 +2153,7 @@ _outQuery(StringInfo str, const Query *node) ...@@ -2152,6 +2153,7 @@ _outQuery(StringInfo str, const Query *node)
WRITE_ENUM_FIELD(commandType, CmdType); WRITE_ENUM_FIELD(commandType, CmdType);
WRITE_ENUM_FIELD(querySource, QuerySource); WRITE_ENUM_FIELD(querySource, QuerySource);
/* we intentionally do not print the queryId field */
WRITE_BOOL_FIELD(canSetTag); WRITE_BOOL_FIELD(canSetTag);
/* /*
......
...@@ -195,6 +195,7 @@ _readQuery(void) ...@@ -195,6 +195,7 @@ _readQuery(void)
READ_ENUM_FIELD(commandType, CmdType); READ_ENUM_FIELD(commandType, CmdType);
READ_ENUM_FIELD(querySource, QuerySource); READ_ENUM_FIELD(querySource, QuerySource);
local_node->queryId = 0; /* not saved in output format */
READ_BOOL_FIELD(canSetTag); READ_BOOL_FIELD(canSetTag);
READ_NODE_FIELD(utilityStmt); READ_NODE_FIELD(utilityStmt);
READ_INT_FIELD(resultRelation); READ_INT_FIELD(resultRelation);
......
...@@ -225,6 +225,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) ...@@ -225,6 +225,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
result = makeNode(PlannedStmt); result = makeNode(PlannedStmt);
result->commandType = parse->commandType; result->commandType = parse->commandType;
result->queryId = parse->queryId;
result->hasReturning = (parse->returningList != NIL); result->hasReturning = (parse->returningList != NIL);
result->hasModifyingCTE = parse->hasModifyingCTE; result->hasModifyingCTE = parse->hasModifyingCTE;
result->canSetTag = parse->canSetTag; result->canSetTag = parse->canSetTag;
......
...@@ -44,6 +44,9 @@ ...@@ -44,6 +44,9 @@
#include "utils/rel.h" #include "utils/rel.h"
/* Hook for plugins to get control at end of parse analysis */
post_parse_analyze_hook_type post_parse_analyze_hook = NULL;
static Query *transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt); static Query *transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt);
static Query *transformInsertStmt(ParseState *pstate, InsertStmt *stmt); static Query *transformInsertStmt(ParseState *pstate, InsertStmt *stmt);
static List *transformInsertRow(ParseState *pstate, List *exprlist, static List *transformInsertRow(ParseState *pstate, List *exprlist,
...@@ -95,6 +98,9 @@ parse_analyze(Node *parseTree, const char *sourceText, ...@@ -95,6 +98,9 @@ parse_analyze(Node *parseTree, const char *sourceText,
query = transformTopLevelStmt(pstate, parseTree); query = transformTopLevelStmt(pstate, parseTree);
if (post_parse_analyze_hook)
(*post_parse_analyze_hook) (pstate, query);
free_parsestate(pstate); free_parsestate(pstate);
return query; return query;
...@@ -125,6 +131,9 @@ parse_analyze_varparams(Node *parseTree, const char *sourceText, ...@@ -125,6 +131,9 @@ parse_analyze_varparams(Node *parseTree, const char *sourceText,
/* make sure all is well with parameter types */ /* make sure all is well with parameter types */
check_variable_parameters(pstate, query); check_variable_parameters(pstate, query);
if (post_parse_analyze_hook)
(*post_parse_analyze_hook) (pstate, query);
free_parsestate(pstate); free_parsestate(pstate);
return query; return query;
......
...@@ -2157,6 +2157,7 @@ RewriteQuery(Query *parsetree, List *rewrite_events) ...@@ -2157,6 +2157,7 @@ RewriteQuery(Query *parsetree, List *rewrite_events)
List * List *
QueryRewrite(Query *parsetree) QueryRewrite(Query *parsetree)
{ {
uint32 input_query_id = parsetree->queryId;
List *querylist; List *querylist;
List *results; List *results;
ListCell *l; ListCell *l;
...@@ -2181,6 +2182,8 @@ QueryRewrite(Query *parsetree) ...@@ -2181,6 +2182,8 @@ QueryRewrite(Query *parsetree)
* Step 2 * Step 2
* *
* Apply all the RIR rules on each query * Apply all the RIR rules on each query
*
* This is also a handy place to mark each query with the original queryId
*/ */
results = NIL; results = NIL;
foreach(l, querylist) foreach(l, querylist)
...@@ -2188,6 +2191,9 @@ QueryRewrite(Query *parsetree) ...@@ -2188,6 +2191,9 @@ QueryRewrite(Query *parsetree)
Query *query = (Query *) lfirst(l); Query *query = (Query *) lfirst(l);
query = fireRIRrules(query, NIL, false); query = fireRIRrules(query, NIL, false);
query->queryId = input_query_id;
results = lappend(results, query); results = lappend(results, query);
} }
......
...@@ -626,6 +626,9 @@ pg_analyze_and_rewrite_params(Node *parsetree, ...@@ -626,6 +626,9 @@ pg_analyze_and_rewrite_params(Node *parsetree,
query = transformTopLevelStmt(pstate, parsetree); query = transformTopLevelStmt(pstate, parsetree);
if (post_parse_analyze_hook)
(*post_parse_analyze_hook) (pstate, query);
free_parsestate(pstate); free_parsestate(pstate);
if (log_parser_stats) if (log_parser_stats)
......
...@@ -103,6 +103,8 @@ typedef struct Query ...@@ -103,6 +103,8 @@ typedef struct Query
QuerySource querySource; /* where did I come from? */ QuerySource querySource; /* where did I come from? */
uint32 queryId; /* query identifier (can be set by plugins) */
bool canSetTag; /* do I set the command result tag? */ bool canSetTag; /* do I set the command result tag? */
Node *utilityStmt; /* non-null if this is DECLARE CURSOR or a Node *utilityStmt; /* non-null if this is DECLARE CURSOR or a
......
...@@ -37,6 +37,8 @@ typedef struct PlannedStmt ...@@ -37,6 +37,8 @@ typedef struct PlannedStmt
CmdType commandType; /* select|insert|update|delete */ CmdType commandType; /* select|insert|update|delete */
uint32 queryId; /* query identifier (copied from Query) */
bool hasReturning; /* is it insert|update|delete RETURNING? */ bool hasReturning; /* is it insert|update|delete RETURNING? */
bool hasModifyingCTE; /* has insert|update|delete in WITH? */ bool hasModifyingCTE; /* has insert|update|delete in WITH? */
......
...@@ -16,6 +16,11 @@ ...@@ -16,6 +16,11 @@
#include "parser/parse_node.h" #include "parser/parse_node.h"
/* Hook for plugins to get control at end of parse analysis */
typedef void (*post_parse_analyze_hook_type) (ParseState *pstate,
Query *query);
extern PGDLLIMPORT post_parse_analyze_hook_type post_parse_analyze_hook;
extern Query *parse_analyze(Node *parseTree, const char *sourceText, extern Query *parse_analyze(Node *parseTree, const char *sourceText,
Oid *paramTypes, int numParams); Oid *paramTypes, int numParams);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment