From dfe2b9d15788fe04c9205738ba66201c0730fe90 Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Thu, 16 Feb 2023 09:17:32 +0900
Subject: [PATCH v4 4/4] Remove normalization of A_Const nodes

Doing so leads to weird cases with commands that can define a
transaction isolation (SET TRANSACTION and BEGIN), as the normalization
is not able to copy with the full field, yet.

Applying normalization of Const nodes to DDLs changes the states of the
following commands:
- DECLARE
- EXPLAIN
- CREATE MATERIALIZED VIEW
- CTAS

At the end, this should be merged with the previous patch, but keeping
it separate shows the difference of behavior between the two approaches
in the regression tests of pg_stat_statements.
---
 src/backend/nodes/queryjumblefuncs.c          |  23 ++-
 .../expected/level_tracking.out               |  20 +--
 .../pg_stat_statements/expected/utility.out   | 136 ++++++++++--------
 3 files changed, 107 insertions(+), 72 deletions(-)

diff --git a/src/backend/nodes/queryjumblefuncs.c b/src/backend/nodes/queryjumblefuncs.c
index 0f08f4c75e..d7fd72d70f 100644
--- a/src/backend/nodes/queryjumblefuncs.c
+++ b/src/backend/nodes/queryjumblefuncs.c
@@ -323,8 +323,29 @@ _jumbleA_Const(JumbleState *jstate, Node *node)
 	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;
+		}
 	}
-	JUMBLE_LOCATION(location);
 }
 
 static void
diff --git a/contrib/pg_stat_statements/expected/level_tracking.out b/contrib/pg_stat_statements/expected/level_tracking.out
index 615be0775f..c824ebdac5 100644
--- a/contrib/pg_stat_statements/expected/level_tracking.out
+++ b/contrib/pg_stat_statements/expected/level_tracking.out
@@ -49,22 +49,22 @@ BEGIN
 END; $$;
 SELECT toplevel, calls, query FROM pg_stat_statements
   ORDER BY query COLLATE "C", toplevel;
- toplevel | calls |               query               
-----------+-------+-----------------------------------
+ toplevel | calls |                query                 
+----------+-------+--------------------------------------
  f        |     1 | DELETE FROM stats_track_tab
  t        |     1 | DELETE FROM stats_track_tab
- t        |     1 | DO $$                            +
-          |       | BEGIN                            +
-          |       |   DELETE FROM stats_track_tab;   +
+ t        |     1 | DO $$                               +
+          |       | BEGIN                               +
+          |       |   DELETE FROM stats_track_tab;      +
           |       | END; $$
- t        |     1 | DO LANGUAGE plpgsql $$           +
-          |       | BEGIN                            +
-          |       |   -- this is a SELECT            +
-          |       |   PERFORM 'hello world'::TEXT;   +
+ t        |     1 | DO LANGUAGE plpgsql $$              +
+          |       | BEGIN                               +
+          |       |   -- this is a SELECT               +
+          |       |   PERFORM 'hello world'::TEXT;      +
           |       | END; $$
  f        |     1 | SELECT $1::TEXT
  t        |     1 | SELECT pg_stat_statements_reset()
- t        |     1 | SET pg_stat_statements.track = $1
+ t        |     1 | SET pg_stat_statements.track = 'all'
 (7 rows)
 
 -- PL/pgSQL function - top-level tracking.
diff --git a/contrib/pg_stat_statements/expected/utility.out b/contrib/pg_stat_statements/expected/utility.out
index f50de29440..826ada4eaa 100644
--- a/contrib/pg_stat_statements/expected/utility.out
+++ b/contrib/pg_stat_statements/expected/utility.out
@@ -24,13 +24,13 @@ SELECT calls, rows, query FROM pg_stat_statements ORDER BY query COLLATE "C";
 NOTICE:  table "tab_stats" does not exist, skipping
 NOTICE:  table "tab_stats" does not exist, skipping
 NOTICE:  table "tab_stats" does not exist, skipping
- calls | rows |                                    query                                    
--------+------+-----------------------------------------------------------------------------
-     1 |    0 | ALTER TABLE tab_stats ADD CONSTRAINT a_nonzero CHECK (a <> $1)
-     1 |    0 | ALTER TABLE tab_stats ALTER COLUMN b TYPE text USING $1 || b
-     1 |    0 | ALTER TABLE tab_stats ALTER COLUMN b set default $1
-     1 |    0 | CREATE INDEX index_stats ON tab_stats(b, (b || $1), (b || $2)) WHERE a > $3
-     1 |    0 | CREATE TEMP TABLE tab_stats (a int, b char($1))
+ calls | rows |                                        query                                         
+-------+------+--------------------------------------------------------------------------------------
+     1 |    0 | ALTER TABLE tab_stats ADD CONSTRAINT a_nonzero CHECK (a <> 0)
+     1 |    0 | ALTER TABLE tab_stats ALTER COLUMN b TYPE text USING 'data' || b
+     1 |    0 | ALTER TABLE tab_stats ALTER COLUMN b set default 'a'
+     1 |    0 | CREATE INDEX index_stats ON tab_stats(b, (b || 'data1'), (b || 'data2')) WHERE a > 0
+     1 |    0 | CREATE TEMP TABLE tab_stats (a int, b char(20))
      3 |    0 | DROP TABLE IF EXISTS tab_stats
      1 |    0 | DROP TABLE tab_stats
      1 |    1 | SELECT pg_stat_statements_reset()
@@ -96,40 +96,40 @@ CREATE TABLE tab_expr_stats (a int, b int);
 CREATE STATISTICS tab_expr_stats_1 (mcv) ON a, (2*a), (3*b) FROM tab_expr_stats;
 DROP TABLE tab_expr_stats;
 SELECT calls, rows, query FROM pg_stat_statements ORDER BY query COLLATE "C";
- calls | rows |                                       query                                       
--------+------+-----------------------------------------------------------------------------------
-     1 |    0 | ALTER FOREIGN TABLE foreign_stats ADD COLUMN b integer DEFAULT $1
-     1 |    0 | ALTER FOREIGN TABLE foreign_stats ADD CONSTRAINT b_nonzero CHECK (b <> $1)
+ calls | rows |                                        query                                        
+-------+------+-------------------------------------------------------------------------------------
+     1 |    0 | ALTER FOREIGN TABLE foreign_stats ADD COLUMN b integer DEFAULT 1
+     1 |    0 | ALTER FOREIGN TABLE foreign_stats ADD CONSTRAINT b_nonzero CHECK (b <> 0)
      1 |    0 | ALTER INDEX pt_stats_index ATTACH PARTITION pt_stats2_index
-     1 |    0 | ALTER TABLE pt_stats ATTACH PARTITION pt_stats1 FOR VALUES FROM ($1) TO ($2)
-     1 |    0 | ALTER VIEW view_stats ALTER COLUMN a SET DEFAULT $1
+     1 |    0 | ALTER TABLE pt_stats ATTACH PARTITION pt_stats1 FOR VALUES FROM (0) TO (100)
+     1 |    0 | ALTER VIEW view_stats ALTER COLUMN a SET DEFAULT 2
      1 |    0 | CREATE FOREIGN DATA WRAPPER wrapper_stats
      1 |    0 | CREATE FOREIGN TABLE foreign_stats (a int) SERVER server_stats
-     1 |    0 | CREATE FUNCTION func_stats(a text DEFAULT $1, b text DEFAULT lower($2))          +
+     1 |    0 | CREATE FUNCTION func_stats(a text DEFAULT 'a_data', b text DEFAULT lower('b_data'))+
        |      |   RETURNS text AS $$ SELECT $1::text || '_' || $2::text; $$ LANGUAGE SQL
-     1 |    0 | CREATE FUNCTION trigger_func_stats () RETURNS trigger LANGUAGE plpgsql           +
+     1 |    0 | CREATE FUNCTION trigger_func_stats () RETURNS trigger LANGUAGE plpgsql             +
        |      |   AS $$ BEGIN return OLD; end; $$
      1 |    0 | CREATE INDEX pt_stats2_index ON ONLY pt_stats2 (a)
      1 |    0 | CREATE INDEX pt_stats_index ON ONLY pt_stats (a)
-     1 |    0 | CREATE POLICY policy_stats ON tab_policy_stats USING (a = $1) WITH CHECK (b < $2)
-     1 |    0 | CREATE RULE rules_stats AS ON INSERT TO tab_rule_stats DO INSTEAD                +
-       |      |   INSERT INTO tab_rule_stats_2 VALUES(new.*, $1, $2)
+     1 |    0 | CREATE POLICY policy_stats ON tab_policy_stats USING (a = 5) WITH CHECK (b < 5)
+     1 |    0 | CREATE RULE rules_stats AS ON INSERT TO tab_rule_stats DO INSTEAD                  +
+       |      |   INSERT INTO tab_rule_stats_2 VALUES(new.*, 1, 2)
      1 |    0 | CREATE SERVER server_stats FOREIGN DATA WRAPPER wrapper_stats
-     1 |    0 | CREATE STATISTICS tab_expr_stats_1 (mcv) ON a, ($1*a), ($2*b) FROM tab_expr_stats
+     1 |    0 | CREATE STATISTICS tab_expr_stats_1 (mcv) ON a, (2*a), (3*b) FROM tab_expr_stats
      1 |    0 | CREATE TABLE pt_stats (a int, b int) PARTITION BY range (a)
      1 |    0 | CREATE TABLE pt_stats1 (a int, b int)
-     1 |    0 | CREATE TABLE pt_stats2 PARTITION OF pt_stats FOR VALUES FROM ($1) TO ($2)
+     1 |    0 | CREATE TABLE pt_stats2 PARTITION OF pt_stats FOR VALUES FROM (100) TO (200)
      1 |    0 | CREATE TABLE tab_expr_stats (a int, b int)
      1 |    0 | CREATE TABLE tab_policy_stats (a int, b int)
      1 |    0 | CREATE TABLE tab_rule_stats (a int, b int)
      1 |    0 | CREATE TABLE tab_rule_stats_2 (a int, b int, c int, d int)
      1 |    0 | CREATE TABLE trigger_tab_stats (a int, b int)
-     1 |    0 | CREATE TRIGGER trigger_tab_stats                                                 +
-       |      |     AFTER UPDATE ON trigger_tab_stats                                            +
-       |      |     FOR EACH ROW WHEN (OLD.a < $1 AND OLD.b < $2 AND $3)                         +
+     1 |    0 | CREATE TRIGGER trigger_tab_stats                                                   +
+       |      |     AFTER UPDATE ON trigger_tab_stats                                              +
+       |      |     FOR EACH ROW WHEN (OLD.a < 0 AND OLD.b < 1 AND true)                           +
        |      |     EXECUTE FUNCTION trigger_func_stats()
-     1 |    0 | CREATE TYPE stats_type as (f1 numeric($1, $2), f2 numeric($3, $4))
-     1 |    0 | CREATE VIEW view_stats AS SELECT $1::int AS a, $2::int AS b
+     1 |    0 | CREATE TYPE stats_type as (f1 numeric(35, 6), f2 numeric(35, 2))
+     1 |    0 | CREATE VIEW view_stats AS SELECT 1::int AS a, 2::int AS b
      1 |    0 | DROP FOREIGN DATA WRAPPER wrapper_stats
      1 |    0 | DROP FOREIGN TABLE foreign_stats
      1 |    0 | DROP FUNCTION func_stats
@@ -179,14 +179,14 @@ COMMIT;
 BEGIN TRANSACTION NOT DEFERRABLE, READ ONLY, READ WRITE, DEFERRABLE;
 COMMIT;
 SELECT calls, rows, query FROM pg_stat_statements ORDER BY query COLLATE "C";
- calls | rows |                         query                          
--------+------+--------------------------------------------------------
+ calls | rows |                                query                                
+-------+------+---------------------------------------------------------------------
      4 |    0 | ABORT
      6 |    0 | BEGIN
-     2 |    0 | BEGIN ISOLATION LEVEL $1
-     1 |    0 | BEGIN TRANSACTION $1
-     1 |    0 | BEGIN TRANSACTION $1 DEFERRABLE, $2 ONLY, $3 WRITE, $4
-     1 |    0 | BEGIN TRANSACTION $1 ONLY, $2 WRITE, $3, $4 DEFERRABLE
+     2 |    0 | BEGIN ISOLATION LEVEL SERIALIZABLE
+     1 |    0 | BEGIN TRANSACTION DEFERRABLE
+     1 |    0 | BEGIN TRANSACTION NOT DEFERRABLE, READ ONLY, READ WRITE, DEFERRABLE
+     1 |    0 | BEGIN TRANSACTION READ ONLY, READ WRITE, DEFERRABLE, NOT DEFERRABLE
      7 |    0 | COMMIT WORK
      1 |    1 | SELECT pg_stat_statements_reset()
 (8 rows)
@@ -259,10 +259,12 @@ CALL sum_two(1,2);
 SELECT calls, rows, query FROM pg_stat_statements ORDER BY query COLLATE "C";
  calls | rows |               query               
 -------+------+-----------------------------------
-     2 |    0 | CALL sum_one($1)
-     2 |    0 | CALL sum_two($1,$2)
+     1 |    0 | CALL sum_one(199)
+     1 |    0 | CALL sum_one(3)
+     1 |    0 | CALL sum_two(1,1)
+     1 |    0 | CALL sum_two(1,2)
      1 |    1 | SELECT pg_stat_statements_reset()
-(3 rows)
+(5 rows)
 
 -- COPY
 CREATE TABLE copy_stats (a int, b int);
@@ -290,14 +292,17 @@ COPY (UPDATE copy_stats SET b = b + 2 RETURNING *) TO STDOUT;
 COPY (DELETE FROM copy_stats WHERE a = 1 RETURNING *) TO STDOUT;
 1	4
 SELECT calls, rows, query FROM pg_stat_statements ORDER BY query COLLATE "C";
- calls | rows |                                query                                
--------+------+---------------------------------------------------------------------
-     1 |    1 | COPY (DELETE FROM copy_stats WHERE a = $1 RETURNING *) TO STDOUT
-     2 |    2 | COPY (INSERT INTO copy_stats VALUES ($1, $2) RETURNING *) TO STDOUT
-     2 |    2 | COPY (SELECT $1) TO STDOUT
-     2 |    4 | COPY (UPDATE copy_stats SET b = b + $1 RETURNING *) TO STDOUT
+ calls | rows |                               query                               
+-------+------+-------------------------------------------------------------------
+     1 |    1 | COPY (DELETE FROM copy_stats WHERE a = 1 RETURNING *) TO STDOUT
+     1 |    1 | COPY (INSERT INTO copy_stats VALUES (1, 1) RETURNING *) TO STDOUT
+     1 |    1 | COPY (INSERT INTO copy_stats VALUES (2, 2) RETURNING *) TO STDOUT
+     1 |    1 | COPY (SELECT 1) TO STDOUT
+     1 |    1 | COPY (SELECT 2) TO STDOUT
+     1 |    2 | COPY (UPDATE copy_stats SET b = b + 1 RETURNING *) TO STDOUT
+     1 |    2 | COPY (UPDATE copy_stats SET b = b + 2 RETURNING *) TO STDOUT
      1 |    1 | SELECT pg_stat_statements_reset()
-(5 rows)
+(8 rows)
 
 DROP TABLE copy_stats;
 SELECT pg_stat_statements_reset();
@@ -374,14 +379,17 @@ CREATE VIEW view_stats_1 AS
     FROM generate_series(1, 5) AS tab(a) WHERE a < 4 AND a > 3;
 DROP VIEW view_stats_1;
 SELECT calls, rows, query FROM pg_stat_statements ORDER BY query COLLATE "C";
- calls | rows |                               query                                
--------+------+--------------------------------------------------------------------
-     2 |    0 | CREATE VIEW view_stats_1 AS                                       +
-       |      |   SELECT a AS col1, $1::int AS col2                               +
-       |      |     FROM generate_series($2, $3) AS tab(a) WHERE a < $4 AND a > $5
+ calls | rows |                              query                              
+-------+------+-----------------------------------------------------------------
+     1 |    0 | CREATE VIEW view_stats_1 AS                                    +
+       |      |   SELECT a AS col1, 2::int AS col2                             +
+       |      |     FROM generate_series(1, 10) AS tab(a) WHERE a < 5 AND a > 2
+     1 |    0 | CREATE VIEW view_stats_1 AS                                    +
+       |      |   SELECT a AS col1, 4::int AS col2                             +
+       |      |     FROM generate_series(1, 5) AS tab(a) WHERE a < 4 AND a > 3
      2 |    0 | DROP VIEW view_stats_1
      1 |    1 | SELECT pg_stat_statements_reset()
-(3 rows)
+(4 rows)
 
 SELECT pg_stat_statements_reset();
  pg_stat_statements_reset 
@@ -395,11 +403,11 @@ ALTER DOMAIN domain_stats SET DEFAULT '3';
 ALTER DOMAIN domain_stats ADD CONSTRAINT higher_than_one CHECK (VALUE > 1);
 DROP DOMAIN domain_stats;
 SELECT calls, rows, query FROM pg_stat_statements ORDER BY query COLLATE "C";
- calls | rows |                                    query                                    
--------+------+-----------------------------------------------------------------------------
-     1 |    0 | ALTER DOMAIN domain_stats ADD CONSTRAINT higher_than_one CHECK (VALUE > $1)
-     1 |    0 | ALTER DOMAIN domain_stats SET DEFAULT $1
-     1 |    0 | CREATE DOMAIN domain_stats AS int CHECK (VALUE > $1)
+ calls | rows |                                   query                                    
+-------+------+----------------------------------------------------------------------------
+     1 |    0 | ALTER DOMAIN domain_stats ADD CONSTRAINT higher_than_one CHECK (VALUE > 1)
+     1 |    0 | ALTER DOMAIN domain_stats SET DEFAULT '3'
+     1 |    0 | CREATE DOMAIN domain_stats AS int CHECK (VALUE > 0)
      1 |    0 | DROP DOMAIN domain_stats
      1 |    1 | SELECT pg_stat_statements_reset()
 (5 rows)
@@ -433,8 +441,8 @@ SET LOCAL SESSION AUTHORIZATION DEFAULT;
 RESET SESSION AUTHORIZATION;
 COMMIT;
 SELECT calls, rows, query FROM pg_stat_statements ORDER BY query COLLATE "C";
- calls | rows |                    query                     
--------+------+----------------------------------------------
+ calls | rows |                      query                      
+-------+------+-------------------------------------------------
      2 |    0 | BEGIN
      2 |    0 | COMMIT
      2 |    0 | RESET SESSION AUTHORIZATION
@@ -443,10 +451,14 @@ SELECT calls, rows, query FROM pg_stat_statements ORDER BY query COLLATE "C";
      1 |    1 | SELECT pg_stat_statements_reset()
      1 |    0 | SET LOCAL SESSION AUTHORIZATION DEFAULT
      1 |    0 | SET SESSION SESSION AUTHORIZATION DEFAULT
-     3 |    0 | SET TRANSACTION ISOLATION LEVEL $1 COMMITTED
-     2 |    0 | SET enable_seqscan = $1
-     3 |    0 | SET work_mem = $1
-(11 rows)
+     1 |    0 | SET TRANSACTION ISOLATION LEVEL READ COMMITTED
+     1 |    0 | SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
+     1 |    0 | SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
+     1 |    0 | SET enable_seqscan = off
+     1 |    0 | SET enable_seqscan = on
+     2 |    0 | SET work_mem = '1MB'
+     1 |    0 | SET work_mem = '2MB'
+(15 rows)
 
 SELECT pg_stat_statements_reset();
  pg_stat_statements_reset 
@@ -536,7 +548,9 @@ SELECT calls, rows, query FROM pg_stat_statements ORDER BY query COLLATE "C";
      1 |    0 | RESET enable_seqscan
      1 |    0 | RESET work_mem
      1 |    1 | SELECT pg_stat_statements_reset()
-     2 |    0 | SET enable_seqscan = $1
-     3 |    0 | SET work_mem = $1
-(5 rows)
+     1 |    0 | SET enable_seqscan = off
+     1 |    0 | SET enable_seqscan = on
+     2 |    0 | SET work_mem = '1MB'
+     1 |    0 | SET work_mem = '2MB'
+(7 rows)
 
-- 
2.39.2

