OSDN Git Service

Took in several improvements of pg_stat_statements
authorKyotaro Horiguchi <horiguchi.kyotaro@lab.ntt.co.jp>
Fri, 8 Jun 2018 03:27:03 +0000 (12:27 +0900)
committerKyotaro Horiguchi <horiguchi.kyotaro@lab.ntt.co.jp>
Tue, 13 Nov 2018 06:37:51 +0000 (15:37 +0900)
Following two commits are took in.

83f2061dd0 Teach contrib/pg_stat_statements to handle multi-statement commands better.
0bb51aa967 Improve parsetree representation of special functions such as CURRENT_DATE.

The following one makes change of documented behavior of pg_hint_plan
so it is not took in.

a6f22e8356 Show ignored constants as "$N" rather than "?" in pg_stat_statements.

normalize_query.h
pg_hint_plan.c
pg_stat_statements.c

index d197de9..fab1e6b 100644 (file)
@@ -40,11 +40,14 @@ typedef struct pgssJumbleState
 
        /* Current number of valid entries in clocations array */
        int                     clocations_count;
 
        /* Current number of valid entries in clocations array */
        int                     clocations_count;
+
+       /* highest Param id we've seen, in order to start normalization correctly */
+       int                     highest_extern_param_id;
 } pgssJumbleState;
 
 static char *
 generate_normalized_query(pgssJumbleState *jstate, const char *query,
 } pgssJumbleState;
 
 static char *
 generate_normalized_query(pgssJumbleState *jstate, const char *query,
-                                                 int *query_len_p, int encoding);
+                                                 int query_loc, int *query_len_p, int encoding);
 static void JumbleQuery(pgssJumbleState *jstate, Query *query);
 
 #define JUMBLE_SIZE            1024
 static void JumbleQuery(pgssJumbleState *jstate, Query *query);
 
 #define JUMBLE_SIZE            1024
index 780d70a..3c99581 100644 (file)
@@ -2836,6 +2836,7 @@ pg_hint_plan_post_parse_analyze(ParseState *pstate, Query *query)
                        query_len = strlen(query_str) + 1;
                        normalized_query =
                                generate_normalized_query(&jstate, query_str,
                        query_len = strlen(query_str) + 1;
                        normalized_query =
                                generate_normalized_query(&jstate, query_str,
+                                                                                 query->stmt_location,
                                                                                  &query_len,
                                                                                  GetDatabaseEncoding());
 
                                                                                  &query_len,
                                                                                  GetDatabaseEncoding());
 
index 7fc34a4..8f74903 100644 (file)
@@ -2,9 +2,9 @@
  *
  * pg_stat_statements.c
  * 
  *
  * pg_stat_statements.c
  * 
- * Part of pg_stat_statements.c in PostgreSQL 9.5.
+ * Part of pg_stat_statements.c in PostgreSQL 10.
  *
  *
- * Copyright (c) 2008-2016, PostgreSQL Global Development Group
+ * Copyright (c) 2008-2017, PostgreSQL Global Development Group
  *
  *-------------------------------------------------------------------------
  */
  *
  *-------------------------------------------------------------------------
  */
@@ -21,7 +21,10 @@ static void JumbleQuery(pgssJumbleState *jstate, Query *query);
 static void JumbleRangeTable(pgssJumbleState *jstate, List *rtable);
 static void JumbleExpr(pgssJumbleState *jstate, Node *node);
 static void RecordConstLocation(pgssJumbleState *jstate, int location);
 static void JumbleRangeTable(pgssJumbleState *jstate, List *rtable);
 static void JumbleExpr(pgssJumbleState *jstate, Node *node);
 static void RecordConstLocation(pgssJumbleState *jstate, int location);
-static void fill_in_constant_lengths(pgssJumbleState *jstate, const char *query);
+static char *generate_normalized_query(pgssJumbleState *jstate, const char *query,
+                                                 int query_loc, int *query_len_p, int encoding);
+static void fill_in_constant_lengths(pgssJumbleState *jstate, const char *query,
+                                                int query_loc);
 static int     comp_location(const void *a, const void *b);
 
 /*
 static int     comp_location(const void *a, const void *b);
 
 /*
@@ -113,9 +116,8 @@ JumbleRangeTable(pgssJumbleState *jstate, List *rtable)
 
        foreach(lc, rtable)
        {
 
        foreach(lc, rtable)
        {
-               RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
+               RangeTblEntry *rte = lfirst_node(RangeTblEntry, lc);
 
 
-               Assert(IsA(rte, RangeTblEntry));
                APP_JUMB(rte->rtekind);
                switch (rte->rtekind)
                {
                APP_JUMB(rte->rtekind);
                switch (rte->rtekind)
                {
@@ -132,6 +134,9 @@ JumbleRangeTable(pgssJumbleState *jstate, List *rtable)
                        case RTE_FUNCTION:
                                JumbleExpr(jstate, (Node *) rte->functions);
                                break;
                        case RTE_FUNCTION:
                                JumbleExpr(jstate, (Node *) rte->functions);
                                break;
+                       case RTE_TABLEFUNC:
+                               JumbleExpr(jstate, (Node *) rte->tablefunc);
+                               break;
                        case RTE_VALUES:
                                JumbleExpr(jstate, (Node *) rte->values_lists);
                                break;
                        case RTE_VALUES:
                                JumbleExpr(jstate, (Node *) rte->values_lists);
                                break;
@@ -144,6 +149,9 @@ JumbleRangeTable(pgssJumbleState *jstate, List *rtable)
                                APP_JUMB_STRING(rte->ctename);
                                APP_JUMB(rte->ctelevelsup);
                                break;
                                APP_JUMB_STRING(rte->ctename);
                                APP_JUMB(rte->ctelevelsup);
                                break;
+                       case RTE_NAMEDTUPLESTORE:
+                               APP_JUMB_STRING(rte->enrname);
+                               break;
                        default:
                                elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind);
                                break;
                        default:
                                elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind);
                                break;
@@ -210,6 +218,10 @@ JumbleExpr(pgssJumbleState *jstate, Node *node)
                                APP_JUMB(p->paramkind);
                                APP_JUMB(p->paramid);
                                APP_JUMB(p->paramtype);
                                APP_JUMB(p->paramkind);
                                APP_JUMB(p->paramid);
                                APP_JUMB(p->paramtype);
+                               /* Also, track the highest external Param id */
+                               if (p->paramkind == PARAM_EXTERN &&
+                                       p->paramid > jstate->highest_extern_param_id)
+                                       jstate->highest_extern_param_id = p->paramid;
                        }
                        break;
                case T_Aggref:
                        }
                        break;
                case T_Aggref:
@@ -301,7 +313,7 @@ JumbleExpr(pgssJumbleState *jstate, Node *node)
                                APP_JUMB(sublink->subLinkType);
                                APP_JUMB(sublink->subLinkId);
                                JumbleExpr(jstate, (Node *) sublink->testexpr);
                                APP_JUMB(sublink->subLinkType);
                                APP_JUMB(sublink->subLinkId);
                                JumbleExpr(jstate, (Node *) sublink->testexpr);
-                               JumbleQuery(jstate, (Query *) sublink->subselect);
+                               JumbleQuery(jstate, castNode(Query, sublink->subselect));
                        }
                        break;
                case T_FieldSelect:
                        }
                        break;
                case T_FieldSelect:
@@ -367,9 +379,8 @@ JumbleExpr(pgssJumbleState *jstate, Node *node)
                                JumbleExpr(jstate, (Node *) caseexpr->arg);
                                foreach(temp, caseexpr->args)
                                {
                                JumbleExpr(jstate, (Node *) caseexpr->arg);
                                foreach(temp, caseexpr->args)
                                {
-                                       CaseWhen   *when = (CaseWhen *) lfirst(temp);
+                                       CaseWhen   *when = lfirst_node(CaseWhen, temp);
 
 
-                                       Assert(IsA(when, CaseWhen));
                                        JumbleExpr(jstate, (Node *) when->expr);
                                        JumbleExpr(jstate, (Node *) when->result);
                                }
                                        JumbleExpr(jstate, (Node *) when->expr);
                                        JumbleExpr(jstate, (Node *) when->result);
                                }
@@ -409,6 +420,15 @@ JumbleExpr(pgssJumbleState *jstate, Node *node)
                                JumbleExpr(jstate, (Node *) mmexpr->args);
                        }
                        break;
                                JumbleExpr(jstate, (Node *) mmexpr->args);
                        }
                        break;
+               case T_SQLValueFunction:
+                       {
+                               SQLValueFunction *svf = (SQLValueFunction *) node;
+
+                               APP_JUMB(svf->op);
+                               /* type is fully determined by op */
+                               APP_JUMB(svf->typmod);
+                       }
+                       break;
                case T_XmlExpr:
                        {
                                XmlExpr    *xexpr = (XmlExpr *) node;
                case T_XmlExpr:
                        {
                                XmlExpr    *xexpr = (XmlExpr *) node;
@@ -466,6 +486,14 @@ JumbleExpr(pgssJumbleState *jstate, Node *node)
                                APP_JUMB(ce->cursor_param);
                        }
                        break;
                                APP_JUMB(ce->cursor_param);
                        }
                        break;
+               case T_NextValueExpr:
+                       {
+                               NextValueExpr *nve = (NextValueExpr *) node;
+
+                               APP_JUMB(nve->seqid);
+                               APP_JUMB(nve->typeId);
+                       }
+                       break;
                case T_InferenceElem:
                        {
                                InferenceElem *ie = (InferenceElem *) node;
                case T_InferenceElem:
                        {
                                InferenceElem *ie = (InferenceElem *) node;
@@ -572,7 +600,7 @@ JumbleExpr(pgssJumbleState *jstate, Node *node)
 
                                /* we store the string name because RTE_CTE RTEs need it */
                                APP_JUMB_STRING(cte->ctename);
 
                                /* we store the string name because RTE_CTE RTEs need it */
                                APP_JUMB_STRING(cte->ctename);
-                               JumbleQuery(jstate, (Query *) cte->ctequery);
+                               JumbleQuery(jstate, castNode(Query, cte->ctequery));
                        }
                        break;
                case T_SetOperationStmt:
                        }
                        break;
                case T_SetOperationStmt:
@@ -592,6 +620,15 @@ JumbleExpr(pgssJumbleState *jstate, Node *node)
                                JumbleExpr(jstate, rtfunc->funcexpr);
                        }
                        break;
                                JumbleExpr(jstate, rtfunc->funcexpr);
                        }
                        break;
+               case T_TableFunc:
+                       {
+                               TableFunc  *tablefunc = (TableFunc *) node;
+
+                               JumbleExpr(jstate, tablefunc->docexpr);
+                               JumbleExpr(jstate, tablefunc->rowexpr);
+                               JumbleExpr(jstate, (Node *) tablefunc->colexprs);
+                       }
+                       break;
                case T_TableSampleClause:
                        {
                                TableSampleClause *tsc = (TableSampleClause *) node;
                case T_TableSampleClause:
                        {
                                TableSampleClause *tsc = (TableSampleClause *) node;
@@ -643,32 +680,48 @@ RecordConstLocation(pgssJumbleState *jstate, int location)
  * just which "equivalent" query is used to create the hashtable entry.
  * We assume this is OK.
  *
  * just which "equivalent" query is used to create the hashtable entry.
  * We assume this is OK.
  *
+ * If query_loc > 0, then "query" has been advanced by that much compared to
+ * the original string start, so we need to translate the provided locations
+ * to compensate.  (This lets us avoid re-scanning statements before the one
+ * of interest, so it's worth doing.)
+ *
  * *query_len_p contains the input string length, and is updated with
  * *query_len_p contains the input string length, and is updated with
- * the result string length (which cannot be longer) on exit.
+ * the result string length on exit.  The resulting string might be longer
+ * or shorter depending on what happens with replacement of constants.
  *
  * Returns a palloc'd string.
  */
 static char *
 generate_normalized_query(pgssJumbleState *jstate, const char *query,
  *
  * Returns a palloc'd string.
  */
 static char *
 generate_normalized_query(pgssJumbleState *jstate, const char *query,
-                                                 int *query_len_p, int encoding)
+                                                 int query_loc, int *query_len_p, int encoding)
 {
        char       *norm_query;
        int                     query_len = *query_len_p;
        int                     i,
 {
        char       *norm_query;
        int                     query_len = *query_len_p;
        int                     i,
+                               norm_query_buflen,      /* Space allowed for norm_query */
                                len_to_wrt,             /* Length (in bytes) to write */
                                quer_loc = 0,   /* Source query byte location */
                                n_quer_loc = 0, /* Normalized query byte location */
                                last_off = 0,   /* Offset from start for previous tok */
                                len_to_wrt,             /* Length (in bytes) to write */
                                quer_loc = 0,   /* Source query byte location */
                                n_quer_loc = 0, /* Normalized query byte location */
                                last_off = 0,   /* Offset from start for previous tok */
-                               last_tok_len = 0;               /* Length (in bytes) of that tok */
+                               last_tok_len = 0;       /* Length (in bytes) of that tok */
 
        /*
         * Get constants' lengths (core system only gives us locations).  Note
         * this also ensures the items are sorted by location.
         */
 
        /*
         * Get constants' lengths (core system only gives us locations).  Note
         * this also ensures the items are sorted by location.
         */
-       fill_in_constant_lengths(jstate, query);
+       fill_in_constant_lengths(jstate, query, query_loc);
+
+       /*
+        * Allow for $n symbols to be longer than the constants they replace.
+        * Constants must take at least one byte in text form, while a $n symbol
+        * certainly isn't more than 11 bytes, even if n reaches INT_MAX.  We
+        * could refine that limit based on the max value of n for the current
+        * query, but it hardly seems worth any extra effort to do so.
+        */
+       norm_query_buflen = query_len + jstate->clocations_count * 10;
 
        /* Allocate result buffer */
 
        /* Allocate result buffer */
-       norm_query = palloc(query_len + 1);
+       norm_query = palloc(norm_query_buflen + 1);
 
        for (i = 0; i < jstate->clocations_count; i++)
        {
 
        for (i = 0; i < jstate->clocations_count; i++)
        {
@@ -676,6 +729,9 @@ generate_normalized_query(pgssJumbleState *jstate, const char *query,
                                        tok_len;        /* Length (in bytes) of that tok */
 
                off = jstate->clocations[i].location;
                                        tok_len;        /* Length (in bytes) of that tok */
 
                off = jstate->clocations[i].location;
+               /* Adjust recorded location if we're dealing with partial string */
+               off -= query_loc;
+
                tok_len = jstate->clocations[i].length;
 
                if (tok_len < 0)
                tok_len = jstate->clocations[i].length;
 
                if (tok_len < 0)
@@ -689,6 +745,10 @@ generate_normalized_query(pgssJumbleState *jstate, const char *query,
                memcpy(norm_query + n_quer_loc, query + quer_loc, len_to_wrt);
                n_quer_loc += len_to_wrt;
 
                memcpy(norm_query + n_quer_loc, query + quer_loc, len_to_wrt);
                n_quer_loc += len_to_wrt;
 
+               /*
+                * PG_HINT_PLAN: DON'T TAKE IN a6f22e8356 so that the designed behavior
+                * is kept stable.
+                */
                /* And insert a '?' in place of the constant token */
                norm_query[n_quer_loc++] = '?';
 
                /* And insert a '?' in place of the constant token */
                norm_query[n_quer_loc++] = '?';
 
@@ -707,7 +767,7 @@ generate_normalized_query(pgssJumbleState *jstate, const char *query,
        memcpy(norm_query + n_quer_loc, query + quer_loc, len_to_wrt);
        n_quer_loc += len_to_wrt;
 
        memcpy(norm_query + n_quer_loc, query + quer_loc, len_to_wrt);
        n_quer_loc += len_to_wrt;
 
-       Assert(n_quer_loc <= query_len);
+       Assert(n_quer_loc <= norm_query_buflen);
        norm_query[n_quer_loc] = '\0';
 
        *query_len_p = n_quer_loc;
        norm_query[n_quer_loc] = '\0';
 
        *query_len_p = n_quer_loc;
@@ -732,12 +792,18 @@ generate_normalized_query(pgssJumbleState *jstate, const char *query,
  * marked as '-1', so that they are later ignored.  (Actually, we assume the
  * lengths were initialized as -1 to start with, and don't change them here.)
  *
  * marked as '-1', so that they are later ignored.  (Actually, we assume the
  * lengths were initialized as -1 to start with, and don't change them here.)
  *
+ * If query_loc > 0, then "query" has been advanced by that much compared to
+ * the original string start, so we need to translate the provided locations
+ * to compensate.  (This lets us avoid re-scanning statements before the one
+ * of interest, so it's worth doing.)
+ *
  * N.B. There is an assumption that a '-' character at a Const location begins
  * a negative numeric constant.  This precludes there ever being another
  * reason for a constant to start with a '-'.
  */
 static void
  * N.B. There is an assumption that a '-' character at a Const location begins
  * a negative numeric constant.  This precludes there ever being another
  * reason for a constant to start with a '-'.
  */
 static void
-fill_in_constant_lengths(pgssJumbleState *jstate, const char *query)
+fill_in_constant_lengths(pgssJumbleState *jstate, const char *query,
+                                                int query_loc)
 {
        pgssLocationLen *locs;
        core_yyscan_t yyscanner;
 {
        pgssLocationLen *locs;
        core_yyscan_t yyscanner;
@@ -771,6 +837,9 @@ fill_in_constant_lengths(pgssJumbleState *jstate, const char *query)
                int                     loc = locs[i].location;
                int                     tok;
 
                int                     loc = locs[i].location;
                int                     tok;
 
+               /* Adjust recorded location if we're dealing with partial string */
+               loc -= query_loc;
+
                Assert(loc >= 0);
 
                if (loc <= last_loc)
                Assert(loc >= 0);
 
                if (loc <= last_loc)