]> granicus.if.org Git - postgresql/commitdiff
Add some infrastructure for contrib/pg_stat_statements.
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 27 Mar 2012 19:14:13 +0000 (15:14 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 27 Mar 2012 19:17:40 +0000 (15:17 -0400)
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

src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/nodes/outfuncs.c
src/backend/nodes/readfuncs.c
src/backend/optimizer/plan/planner.c
src/backend/parser/analyze.c
src/backend/rewrite/rewriteHandler.c
src/backend/tcop/postgres.c
src/include/nodes/parsenodes.h
src/include/nodes/plannodes.h
src/include/parser/analyze.h

index cf23b0887242f4d3a008599b5464bade86cc412b..33ee62f40d05bc08a99934440d7a07970ecf009b 100644 (file)
@@ -78,6 +78,7 @@ _copyPlannedStmt(const PlannedStmt *from)
        PlannedStmt *newnode = makeNode(PlannedStmt);
 
        COPY_SCALAR_FIELD(commandType);
+       COPY_SCALAR_FIELD(queryId);
        COPY_SCALAR_FIELD(hasReturning);
        COPY_SCALAR_FIELD(hasModifyingCTE);
        COPY_SCALAR_FIELD(canSetTag);
@@ -2402,6 +2403,7 @@ _copyQuery(const Query *from)
 
        COPY_SCALAR_FIELD(commandType);
        COPY_SCALAR_FIELD(querySource);
+       COPY_SCALAR_FIELD(queryId);
        COPY_SCALAR_FIELD(canSetTag);
        COPY_NODE_FIELD(utilityStmt);
        COPY_SCALAR_FIELD(resultRelation);
index 5e691f96f79ac1e0a4177ab3edd42b3ab265d895..b749e9bbe30b16a16fd954c35f4d25b2153decfc 100644 (file)
@@ -897,6 +897,7 @@ _equalQuery(const Query *a, const Query *b)
 {
        COMPARE_SCALAR_FIELD(commandType);
        COMPARE_SCALAR_FIELD(querySource);
+       /* we intentionally ignore queryId, since it might not be set */
        COMPARE_SCALAR_FIELD(canSetTag);
        COMPARE_NODE_FIELD(utilityStmt);
        COMPARE_SCALAR_FIELD(resultRelation);
index e925434eb3943fa5dda043d45141e8fd21b9a658..594b3fdea85c571bd04e2c07a8da20fffce1af7a 100644 (file)
@@ -242,6 +242,7 @@ _outPlannedStmt(StringInfo str, const PlannedStmt *node)
        WRITE_NODE_TYPE("PLANNEDSTMT");
 
        WRITE_ENUM_FIELD(commandType, CmdType);
+       WRITE_UINT_FIELD(queryId);
        WRITE_BOOL_FIELD(hasReturning);
        WRITE_BOOL_FIELD(hasModifyingCTE);
        WRITE_BOOL_FIELD(canSetTag);
@@ -2152,6 +2153,7 @@ _outQuery(StringInfo str, const Query *node)
 
        WRITE_ENUM_FIELD(commandType, CmdType);
        WRITE_ENUM_FIELD(querySource, QuerySource);
+       /* we intentionally do not print the queryId field */
        WRITE_BOOL_FIELD(canSetTag);
 
        /*
index 9b579560c5e855aaaa89074eb506c9430e9db855..7960793641c71b569783b1f1abe87308231c9b1a 100644 (file)
@@ -195,6 +195,7 @@ _readQuery(void)
 
        READ_ENUM_FIELD(commandType, CmdType);
        READ_ENUM_FIELD(querySource, QuerySource);
+       local_node->queryId = 0;                        /* not saved in output format */
        READ_BOOL_FIELD(canSetTag);
        READ_NODE_FIELD(utilityStmt);
        READ_INT_FIELD(resultRelation);
index 6b0541b9b59346d5166e88ba78e5b5172ac6edaf..dcf32c0744456b5680b525a6310f29d4ac555314 100644 (file)
@@ -225,6 +225,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
        result = makeNode(PlannedStmt);
 
        result->commandType = parse->commandType;
+       result->queryId = parse->queryId;
        result->hasReturning = (parse->returningList != NIL);
        result->hasModifyingCTE = parse->hasModifyingCTE;
        result->canSetTag = parse->canSetTag;
index 485d686b058f1281abb4a10f4e3f821483f3a05f..15d848ff4fe262fe9cd2c1f113af4dd9e2e18da3 100644 (file)
@@ -44,6 +44,9 @@
 #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 *transformInsertStmt(ParseState *pstate, InsertStmt *stmt);
 static List *transformInsertRow(ParseState *pstate, List *exprlist,
@@ -95,6 +98,9 @@ parse_analyze(Node *parseTree, const char *sourceText,
 
        query = transformTopLevelStmt(pstate, parseTree);
 
+       if (post_parse_analyze_hook)
+               (*post_parse_analyze_hook) (pstate, query);
+
        free_parsestate(pstate);
 
        return query;
@@ -125,6 +131,9 @@ parse_analyze_varparams(Node *parseTree, const char *sourceText,
        /* make sure all is well with parameter types */
        check_variable_parameters(pstate, query);
 
+       if (post_parse_analyze_hook)
+               (*post_parse_analyze_hook) (pstate, query);
+
        free_parsestate(pstate);
 
        return query;
index 04f9622f788cd4fd2bf48895e44a7e91a43efea1..8f75948d0dd399e21fab2053064cfd43d7b38c43 100644 (file)
@@ -2157,6 +2157,7 @@ RewriteQuery(Query *parsetree, List *rewrite_events)
 List *
 QueryRewrite(Query *parsetree)
 {
+       uint32          input_query_id = parsetree->queryId;
        List       *querylist;
        List       *results;
        ListCell   *l;
@@ -2181,6 +2182,8 @@ QueryRewrite(Query *parsetree)
         * Step 2
         *
         * Apply all the RIR rules on each query
+        *
+        * This is also a handy place to mark each query with the original queryId
         */
        results = NIL;
        foreach(l, querylist)
@@ -2188,6 +2191,9 @@ QueryRewrite(Query *parsetree)
                Query      *query = (Query *) lfirst(l);
 
                query = fireRIRrules(query, NIL, false);
+
+               query->queryId = input_query_id;
+
                results = lappend(results, query);
        }
 
index 14ca7681392e93a6679cadf7a9c36108663f48e8..02be36362ce99f57fe7b05b76f391f3dceb3e835 100644 (file)
@@ -626,6 +626,9 @@ pg_analyze_and_rewrite_params(Node *parsetree,
 
        query = transformTopLevelStmt(pstate, parsetree);
 
+       if (post_parse_analyze_hook)
+               (*post_parse_analyze_hook) (pstate, query);
+
        free_parsestate(pstate);
 
        if (log_parser_stats)
index 07a1ab75502a5521658a88d239c91b02d4773abd..bc9b6bd774c9a47e50a7cfb29f4b4e7627fe6148 100644 (file)
@@ -103,6 +103,8 @@ typedef struct Query
 
        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? */
 
        Node       *utilityStmt;        /* non-null if this is DECLARE CURSOR or a
index c7c1a154fc47df9c137754359a3522ee09dfc41f..fb9a863e15c043613831b5277bfdc0fb05ff1b2c 100644 (file)
@@ -37,6 +37,8 @@ typedef struct PlannedStmt
 
        CmdType         commandType;    /* select|insert|update|delete */
 
+       uint32          queryId;                /* query identifier (copied from Query) */
+
        bool            hasReturning;   /* is it insert|update|delete RETURNING? */
 
        bool            hasModifyingCTE;        /* has insert|update|delete in WITH? */
index 8367db8b8c58f7ddedc9ddca39e73a83d8fe9e7c..fe7f80a5aaa7a7d46370b07b3e66656d3b44bf20 100644 (file)
 
 #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,
                          Oid *paramTypes, int numParams);