From 9c4d7501877ef0b8a2680196f7c86950ac80c430 Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Thu, 16 Feb 2023 09:17:32 +0900
Subject: [PATCH v3 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/pg_stat_statements.out           |   2 +-
 .../pg_stat_statements/expected/utility.out   | 224 +++++++++---------
 3 files changed, 141 insertions(+), 108 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/pg_stat_statements.out b/contrib/pg_stat_statements/expected/pg_stat_statements.out
index da0909a6b2..05722db413 100644
--- a/contrib/pg_stat_statements/expected/pg_stat_statements.out
+++ b/contrib/pg_stat_statements/expected/pg_stat_statements.out
@@ -311,7 +311,7 @@ FROM pg_stat_statements ORDER BY query COLLATE "C";
  wal_records > $2 as wal_records_generated,               +|       |      |                     |                       | 
  wal_records >= rows as wal_records_ge_rows               +|       |      |                     |                       | 
  FROM pg_stat_statements ORDER BY query COLLATE "C"        |       |      |                     |                       | 
- SET pg_stat_statements.track_utility = $1                 |     1 |    0 | f                   | f                     | t
+ SET pg_stat_statements.track_utility = FALSE              |     1 |    0 | f                   | f                     | t
  UPDATE pgss_test SET b = $1 WHERE a > $2                  |     1 |    3 | t                   | t                     | t
 (7 rows)
 
diff --git a/contrib/pg_stat_statements/expected/utility.out b/contrib/pg_stat_statements/expected/utility.out
index 62601e1787..061898e003 100644
--- a/contrib/pg_stat_statements/expected/utility.out
+++ b/contrib/pg_stat_statements/expected/utility.out
@@ -24,16 +24,16 @@ SELECT query, calls, rows 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
-                                    query                                    | calls | rows 
------------------------------------------------------------------------------+-------+------
- 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))                             |     1 |    0
- DROP TABLE IF EXISTS tab_stats                                              |     3 |    0
- DROP TABLE tab_stats                                                        |     1 |    0
- SELECT pg_stat_statements_reset()                                           |     1 |    1
+                                        query                                         | calls | rows 
+--------------------------------------------------------------------------------------+-------+------
+ 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))                                      |     1 |    0
+ DROP TABLE IF EXISTS tab_stats                                                       |     3 |    0
+ DROP TABLE tab_stats                                                                 |     1 |    0
+ SELECT pg_stat_statements_reset()                                                    |     1 |    1
 (8 rows)
 
 SELECT pg_stat_statements_reset();
@@ -96,53 +96,53 @@ 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 query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
-                                       query                                       | calls | rows 
------------------------------------------------------------------------------------+-------+------
- 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)        |     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
- 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
-   RETURNS text AS $$ SELECT $1::text || '_' || $2::text; $$ LANGUAGE SQL          |       | 
- CREATE FUNCTION trigger_func_stats () RETURNS trigger LANGUAGE plpgsql           +|     1 |    0
-   AS $$ BEGIN return OLD; end; $$                                                 |       | 
- 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                +|     1 |    0
-   INSERT INTO tab_rule_stats_2 VALUES(new.*, $1, $2)                              |       | 
- 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 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 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                                                 +|     1 |    0
-     AFTER UPDATE ON trigger_tab_stats                                            +|       | 
-     FOR EACH ROW WHEN (OLD.a < $1 AND OLD.b < $2 AND $3)                         +|       | 
-     EXECUTE FUNCTION trigger_func_stats()                                         |       | 
- 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
- DROP FOREIGN DATA WRAPPER wrapper_stats                                           |     1 |    0
- DROP FOREIGN TABLE foreign_stats                                                  |     1 |    0
- DROP FUNCTION func_stats                                                          |     1 |    0
- DROP RULE rules_stats ON tab_rule_stats                                           |     1 |    0
- DROP SERVER server_stats                                                          |     1 |    0
- DROP TABLE pt_stats                                                               |     1 |    0
- DROP TABLE tab_expr_stats                                                         |     1 |    0
- DROP TABLE tab_policy_stats                                                       |     1 |    0
- DROP TABLE tab_rule_stats, tab_rule_stats_2                                       |     1 |    0
- DROP TABLE trigger_tab_stats                                                      |     1 |    0
- DROP TYPE stats_type                                                              |     1 |    0
- DROP VIEW view_stats                                                              |     1 |    0
- SELECT pg_stat_statements_reset()                                                 |     1 |    1
+                                        query                                        | calls | rows 
+-------------------------------------------------------------------------------------+-------+------
+ 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 (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 'a_data', b text DEFAULT lower('b_data'))+|     1 |    0
+   RETURNS text AS $$ SELECT $1::text || '_' || $2::text; $$ LANGUAGE SQL            |       | 
+ CREATE FUNCTION trigger_func_stats () RETURNS trigger LANGUAGE plpgsql             +|     1 |    0
+   AS $$ BEGIN return OLD; end; $$                                                   |       | 
+ 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 = 5) WITH CHECK (b < 5)     |     1 |    0
+ CREATE RULE rules_stats AS ON INSERT TO tab_rule_stats DO INSTEAD                  +|     1 |    0
+   INSERT INTO tab_rule_stats_2 VALUES(new.*, 1, 2)                                  |       | 
+ CREATE SERVER server_stats FOREIGN DATA WRAPPER wrapper_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 (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                                                   +|     1 |    0
+     AFTER UPDATE ON trigger_tab_stats                                              +|       | 
+     FOR EACH ROW WHEN (OLD.a < 0 AND OLD.b < 1 AND true)                           +|       | 
+     EXECUTE FUNCTION trigger_func_stats()                                           |       | 
+ 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                                                            |     1 |    0
+ DROP RULE rules_stats ON tab_rule_stats                                             |     1 |    0
+ DROP SERVER server_stats                                                            |     1 |    0
+ DROP TABLE pt_stats                                                                 |     1 |    0
+ DROP TABLE tab_expr_stats                                                           |     1 |    0
+ DROP TABLE tab_policy_stats                                                         |     1 |    0
+ DROP TABLE tab_rule_stats, tab_rule_stats_2                                         |     1 |    0
+ DROP TABLE trigger_tab_stats                                                        |     1 |    0
+ DROP TYPE stats_type                                                                |     1 |    0
+ DROP VIEW view_stats                                                                |     1 |    0
+ SELECT pg_stat_statements_reset()                                                   |     1 |    1
 (39 rows)
 
 -- Transaction statements
@@ -177,15 +177,15 @@ COMMIT;
 BEGIN TRANSACTION READ ONLY, READ WRITE, DEFERRABLE, NOT DEFERRABLE;
 COMMIT;
 SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
-                         query                          | calls | rows 
---------------------------------------------------------+-------+------
- ABORT                                                  |     4 |    0
- BEGIN                                                  |     6 |    0
- BEGIN ISOLATION LEVEL $1                               |     2 |    0
- BEGIN TRANSACTION $1                                   |     1 |    0
- BEGIN TRANSACTION $1 ONLY, $2 WRITE, $3, $4 DEFERRABLE |     1 |    0
- COMMIT WORK                                            |     6 |    0
- SELECT pg_stat_statements_reset()                      |     1 |    1
+                                query                                | calls | rows 
+---------------------------------------------------------------------+-------+------
+ ABORT                                                               |     4 |    0
+ BEGIN                                                               |     6 |    0
+ BEGIN ISOLATION LEVEL SERIALIZABLE                                  |     2 |    0
+ BEGIN TRANSACTION DEFERRABLE                                        |     1 |    0
+ BEGIN TRANSACTION READ ONLY, READ WRITE, DEFERRABLE, NOT DEFERRABLE |     1 |    0
+ COMMIT WORK                                                         |     6 |    0
+ SELECT pg_stat_statements_reset()                                   |     1 |    1
 (7 rows)
 
 SELECT pg_stat_statements_reset();
@@ -256,10 +256,12 @@ CALL sum_two(1,2);
 SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
                query               | calls | rows 
 -----------------------------------+-------+------
- CALL sum_one($1)                  |     2 |    0
- CALL sum_two($1,$2)               |     2 |    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 |    0
  SELECT pg_stat_statements_reset() |     1 |    1
-(3 rows)
+(5 rows)
 
 -- COPY
 CREATE TABLE copy_stats (a int, b int);
@@ -287,14 +289,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 query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
-                                query                                | calls | rows 
----------------------------------------------------------------------+-------+------
- COPY (DELETE FROM copy_stats WHERE a = $1 RETURNING *) TO STDOUT    |     1 |    1
- COPY (INSERT INTO copy_stats VALUES ($1, $2) RETURNING *) TO STDOUT |     2 |    2
- COPY (SELECT $1) TO STDOUT                                          |     2 |    2
- COPY (UPDATE copy_stats SET b = b + $1 RETURNING *) TO STDOUT       |     2 |    4
- SELECT pg_stat_statements_reset()                                   |     1 |    1
-(5 rows)
+                               query                               | calls | rows 
+-------------------------------------------------------------------+-------+------
+ 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 |    1
+ 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 |    2
+ SELECT pg_stat_statements_reset()                                 |     1 |    1
+(8 rows)
 
 DROP TABLE copy_stats;
 SELECT pg_stat_statements_reset();
@@ -371,14 +376,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 query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
-                               query                                | calls | rows 
---------------------------------------------------------------------+-------+------
- CREATE VIEW view_stats_1 AS                                       +|     2 |    0
-   SELECT a AS col1, $1::int AS col2                               +|       | 
-     FROM generate_series($2, $3) AS tab(a) WHERE a < $4 AND a > $5 |       | 
- DROP VIEW view_stats_1                                             |     2 |    0
- SELECT pg_stat_statements_reset()                                  |     1 |    1
-(3 rows)
+                              query                              | calls | rows 
+-----------------------------------------------------------------+-------+------
+ CREATE VIEW view_stats_1 AS                                    +|     1 |    0
+   SELECT a AS col1, 2::int AS col2                             +|       | 
+     FROM generate_series(1, 10) AS tab(a) WHERE a < 5 AND a > 2 |       | 
+ CREATE VIEW view_stats_1 AS                                    +|     1 |    0
+   SELECT a AS col1, 4::int AS col2                             +|       | 
+     FROM generate_series(1, 5) AS tab(a) WHERE a < 4 AND a > 3  |       | 
+ DROP VIEW view_stats_1                                          |     2 |    0
+ SELECT pg_stat_statements_reset()                               |     1 |    1
+(4 rows)
 
 SELECT pg_stat_statements_reset();
  pg_stat_statements_reset 
@@ -392,13 +400,13 @@ ALTER DOMAIN domain_stats SET DEFAULT '3';
 ALTER DOMAIN domain_stats ADD CONSTRAINT higher_than_one CHECK (VALUE > 1);
 DROP DOMAIN domain_stats;
 SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
-                                    query                                    | calls | rows 
------------------------------------------------------------------------------+-------+------
- 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)                        |     1 |    0
- DROP DOMAIN domain_stats                                                    |     1 |    0
- SELECT pg_stat_statements_reset()                                           |     1 |    1
+                                   query                                    | calls | rows 
+----------------------------------------------------------------------------+-------+------
+ 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 |    0
+ SELECT pg_stat_statements_reset()                                          |     1 |    1
 (5 rows)
 
 SELECT pg_stat_statements_reset();
@@ -430,20 +438,24 @@ SET LOCAL SESSION AUTHORIZATION DEFAULT;
 RESET SESSION AUTHORIZATION;
 COMMIT;
 SELECT query, calls, rows FROM pg_stat_statements ORDER BY query COLLATE "C";
-                    query                     | calls | rows 
-----------------------------------------------+-------+------
- BEGIN                                        |     2 |    0
- COMMIT                                       |     2 |    0
- RESET SESSION AUTHORIZATION                  |     2 |    0
- RESET enable_seqscan                         |     1 |    0
- RESET work_mem                               |     1 |    0
- SELECT pg_stat_statements_reset()            |     1 |    1
- SET LOCAL SESSION AUTHORIZATION DEFAULT      |     1 |    0
- SET SESSION SESSION AUTHORIZATION DEFAULT    |     1 |    0
- SET TRANSACTION ISOLATION LEVEL $1 COMMITTED |     3 |    0
- SET enable_seqscan = $1                      |     2 |    0
- SET work_mem = $1                            |     3 |    0
-(11 rows)
+                      query                      | calls | rows 
+-------------------------------------------------+-------+------
+ BEGIN                                           |     2 |    0
+ COMMIT                                          |     2 |    0
+ RESET SESSION AUTHORIZATION                     |     2 |    0
+ RESET enable_seqscan                            |     1 |    0
+ RESET work_mem                                  |     1 |    0
+ SELECT pg_stat_statements_reset()               |     1 |    1
+ SET LOCAL SESSION AUTHORIZATION DEFAULT         |     1 |    0
+ SET SESSION SESSION AUTHORIZATION DEFAULT       |     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                         |     1 |    0
+ SET work_mem = '1MB'                            |     2 |    0
+ SET work_mem = '2MB'                            |     1 |    0
+(15 rows)
 
 SELECT pg_stat_statements_reset();
  pg_stat_statements_reset 
-- 
2.39.1

