Include values of A_Const nodes in query jumbling
authorMichael Paquier <michael@paquier.xyz>
Tue, 7 Feb 2023 00:03:54 +0000 (09:03 +0900)
committerMichael Paquier <michael@paquier.xyz>
Tue, 7 Feb 2023 00:03:54 +0000 (09:03 +0900)
Like the implementation for node copy, write and read, this node
requires a custom implementation so as the query jumbling is able to
consider the correct value assigned to it, depending on its type (int,
float, bool, string, bitstring).

Based on a dump of pg_stat_statements from the regression database, this
would confuse the query jumbling of the following queries:
- SET.
- COPY TO with SELECT queries.
- START TRANSACTION with different isolation levels.
- ALTER TABLE with default expressions.
- CREATE TABLE with partition bounds.

Note that there may be a long-term argument in tracking the location of
such nodes so as query strings holding such nodes could be normalized,
but this is left as a separate discussion.

Oversight in 3db72eb.

Discussion: https://postgr.es/m/Y9+HuYslMAP6yyPb@paquier.xyz

contrib/pg_stat_statements/expected/pg_stat_statements.out
contrib/pg_stat_statements/sql/pg_stat_statements.sql
src/backend/nodes/queryjumblefuncs.c
src/include/nodes/parsenodes.h

index fb9ccd920f6459c733635fcc8ee3446c11e8ae77..8c0b2235e816688646a0526fa8dd28a0c1202413 100644 (file)
@@ -579,6 +579,14 @@ NOTICE:  table "test" does not exist, skipping
 NOTICE:  table "test" does not exist, skipping
 NOTICE:  function plus_one(pg_catalog.int4) does not exist, skipping
 DROP FUNCTION PLUS_TWO(INTEGER);
+-- This SET query uses two different strings, still they count as one entry.
+SET work_mem = '1MB';
+Set work_mem = '1MB';
+SET work_mem = '2MB';
+RESET work_mem;
+SET enable_seqscan = off;
+SET enable_seqscan = on;
+RESET enable_seqscan;
 SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
                                     query                                     | calls | rows 
 ------------------------------------------------------------------------------+-------+------
@@ -588,10 +596,16 @@ SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
  DROP FUNCTION PLUS_TWO(INTEGER)                                              |     1 |    0
  DROP TABLE IF EXISTS test                                                    |     3 |    0
  DROP TABLE test                                                              |     1 |    0
+ RESET enable_seqscan                                                         |     1 |    0
+ RESET work_mem                                                               |     1 |    0
  SELECT $1                                                                    |     1 |    1
  SELECT pg_stat_statements_reset()                                            |     1 |    1
  SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C" |     0 |    0
-(9 rows)
+ SET enable_seqscan = off                                                     |     1 |    0
+ SET enable_seqscan = on                                                      |     1 |    0
+ SET work_mem = '1MB'                                                         |     2 |    0
+ SET work_mem = '2MB'                                                         |     1 |    0
+(15 rows)
 
 --
 -- Track the total number of rows retrieved or affected by the utility
index b82cddf16f1f2fbeaad7de2a30ecc6137811412c..cebde7392b1c95a4ce46dcdb87e07d5600089966 100644 (file)
@@ -270,6 +270,14 @@ DROP TABLE IF EXISTS test \;
 Drop Table If Exists test \;
 DROP FUNCTION IF EXISTS PLUS_ONE(INTEGER);
 DROP FUNCTION PLUS_TWO(INTEGER);
+-- This SET query uses two different strings, still they count as one entry.
+SET work_mem = '1MB';
+Set work_mem = '1MB';
+SET work_mem = '2MB';
+RESET work_mem;
+SET enable_seqscan = off;
+SET enable_seqscan = on;
+RESET enable_seqscan;
 
 SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
 
index 223d1bc826260e2eaf3eaac7d5f01e4493d6576f..d7fd72d70f202daffa3b7896d79b90a57a27df3d 100644 (file)
@@ -49,6 +49,7 @@ static void AppendJumble(JumbleState *jstate,
                         const unsigned char *item, Size size);
 static void RecordConstLocation(JumbleState *jstate, int location);
 static void _jumbleNode(JumbleState *jstate, Node *node);
+static void _jumbleA_Const(JumbleState *jstate, Node *node);
 static void _jumbleList(JumbleState *jstate, Node *node);
 static void _jumbleRangeTblEntry(JumbleState *jstate, Node *node);
 
@@ -313,6 +314,40 @@ _jumbleList(JumbleState *jstate, Node *node)
    }
 }
 
+static void
+_jumbleA_Const(JumbleState *jstate, Node *node)
+{
+   A_Const    *expr = (A_Const *) node;
+
+   JUMBLE_FIELD(isnull);
+   if (!expr->isnull)
+   {
+       JUMBLE_FIELD(val.node.type);
+       switch (nodeTag(&expr->val))
+       {
+           case T_Integer:
+               JUMBLE_FIELD(val.ival.ival);
+               break;
+           case T_Float:
+               JUMBLE_STRING(val.fval.fval);
+               break;
+           case T_Boolean:
+               JUMBLE_FIELD(val.boolval.boolval);
+               break;
+           case T_String:
+               JUMBLE_STRING(val.sval.sval);
+               break;
+           case T_BitString:
+               JUMBLE_STRING(val.bsval.bsval);
+               break;
+           default:
+               elog(ERROR, "unrecognized node type: %d",
+                    (int) nodeTag(&expr->val));
+               break;
+       }
+   }
+}
+
 static void
 _jumbleRangeTblEntry(JumbleState *jstate, Node *node)
 {
index 3d67787e7af06925d3802ec1d63c49341f38bf3b..855da99ec02bcb8f32e5216f33b80ddc5db448d0 100644 (file)
@@ -355,7 +355,7 @@ union ValUnion
 
 typedef struct A_Const
 {
-   pg_node_attr(custom_copy_equal, custom_read_write)
+   pg_node_attr(custom_copy_equal, custom_read_write, custom_query_jumble)
 
    NodeTag     type;
    union ValUnion val;