From 318605685954a86ff61624ec9404fb2a0e780934 Mon Sep 17 00:00:00 2001
From: Dmitrii Dolgov <9erthalion6@gmail.com>
Date: Tue, 20 May 2025 16:12:05 +0200
Subject: [PATCH v9 1/2] Enhanced query jumbling squashing tests

Testing coverage for ARRAY expressions is not enough. Add more test
cases, similar to already existing ones. Also, enhance tests for the
negative cases of RelabelType, CoerceViaIO and FuncExpr. While at it,
re-organized some parts of the tests and correct minor spacing issues.
---
 .../pg_stat_statements/expected/squashing.out | 540 +++++++++++++++---
 contrib/pg_stat_statements/sql/squashing.sql  | 190 +++++-
 2 files changed, 621 insertions(+), 109 deletions(-)

diff --git a/contrib/pg_stat_statements/expected/squashing.out b/contrib/pg_stat_statements/expected/squashing.out
index 7b138af098c..b8724e3356c 100644
--- a/contrib/pg_stat_statements/expected/squashing.out
+++ b/contrib/pg_stat_statements/expected/squashing.out
@@ -2,9 +2,11 @@
 -- Const squashing functionality
 --
 CREATE EXTENSION pg_stat_statements;
+--
+--Simple Lists
+--
 CREATE TABLE test_squash (id int, data int);
--- IN queries
--- Normal scenario, too many simple constants for an IN query
+-- single element will not be squashed
 SELECT pg_stat_statements_reset() IS NOT NULL AS t;
  t 
 ---
@@ -16,42 +18,149 @@ SELECT * FROM test_squash WHERE id IN (1);
 ----+------
 (0 rows)
 
+SELECT ARRAY[1];
+ array 
+-------
+ {1}
+(1 row)
+
+SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
+                       query                        | calls 
+----------------------------------------------------+-------
+ SELECT * FROM test_squash WHERE id IN ($1)         |     1
+ SELECT ARRAY[$1]                                   |     1
+ SELECT pg_stat_statements_reset() IS NOT NULL AS t |     1
+(3 rows)
+
+-- more than 1 element in a list will be squashed
+SELECT pg_stat_statements_reset() IS NOT NULL AS t;
+ t 
+---
+ t
+(1 row)
+
 SELECT * FROM test_squash WHERE id IN (1, 2, 3);
  id | data 
 ----+------
 (0 rows)
 
+SELECT * FROM test_squash WHERE id IN (1, 2, 3, 4);
+ id | data 
+----+------
+(0 rows)
+
+SELECT * FROM test_squash WHERE id IN (1, 2, 3, 4, 5);
+ id | data 
+----+------
+(0 rows)
+
+SELECT ARRAY[1, 2, 3];
+  array  
+---------
+ {1,2,3}
+(1 row)
+
+SELECT ARRAY[1, 2, 3, 4];
+   array   
+-----------
+ {1,2,3,4}
+(1 row)
+
+SELECT ARRAY[1, 2, 3, 4, 5];
+    array    
+-------------
+ {1,2,3,4,5}
+(1 row)
+
 SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
                          query                         | calls 
 -------------------------------------------------------+-------
- SELECT * FROM test_squash WHERE id IN ($1 /*, ... */) |     1
- SELECT * FROM test_squash WHERE id IN ($1)            |     1
+ SELECT * FROM test_squash WHERE id IN ($1 /*, ... */) |     3
+ SELECT ARRAY[$1 /*, ... */]                           |     3
  SELECT pg_stat_statements_reset() IS NOT NULL AS t    |     1
 (3 rows)
 
-SELECT * FROM test_squash WHERE id IN (1, 2, 3, 4, 5, 6, 7, 8, 9);
+-- built-in functions will be squashed
+-- the IN and ARRAY forms of this statement will have the same queryId
+SELECT pg_stat_statements_reset() IS NOT NULL AS t;
+ t 
+---
+ t
+(1 row)
+
+SELECT WHERE 1 IN (1, int4(1), int4(2), 2);
+--
+(1 row)
+
+SELECT WHERE 1 = ANY (ARRAY[1, int4(1), int4(2), 2]);
+--
+(1 row)
+
+SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
+                       query                        | calls 
+----------------------------------------------------+-------
+ SELECT WHERE $1 IN ($2 /*, ... */)                 |     2
+ SELECT pg_stat_statements_reset() IS NOT NULL AS t |     1
+(2 rows)
+
+-- external parameters will not be squashed
+SELECT pg_stat_statements_reset() IS NOT NULL AS t;
+ t 
+---
+ t
+(1 row)
+
+SELECT * FROM test_squash WHERE id IN ($1, $2, $3, $4, $5)  \bind 1 2 3 4 5
+;
  id | data 
 ----+------
 (0 rows)
 
-SELECT * FROM test_squash WHERE id IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
- id | data 
-----+------
-(0 rows)
-
-SELECT * FROM test_squash WHERE id IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
+SELECT * FROM test_squash WHERE id::text = ANY(ARRAY[$1, $2, $3, $4, $5]) \bind 1 2 3 4 5
+;
  id | data 
 ----+------
 (0 rows)
 
 SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
-                                 query                                  | calls 
-------------------------------------------------------------------------+-------
- SELECT * FROM test_squash WHERE id IN ($1 /*, ... */)                  |     4
- SELECT * FROM test_squash WHERE id IN ($1)                             |     1
- SELECT pg_stat_statements_reset() IS NOT NULL AS t                     |     1
- SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C" |     1
-(4 rows)
+                                   query                                   | calls 
+---------------------------------------------------------------------------+-------
+ SELECT * FROM test_squash WHERE id IN ($1, $2, $3, $4, $5)                |     1
+ SELECT * FROM test_squash WHERE id::text = ANY(ARRAY[$1, $2, $3, $4, $5]) |     1
+ SELECT pg_stat_statements_reset() IS NOT NULL AS t                        |     1
+(3 rows)
+
+-- neither are prepared statements
+-- the IN and ARRAY forms of this statement will have the same queryId
+SELECT pg_stat_statements_reset() IS NOT NULL AS t;
+ t 
+---
+ t
+(1 row)
+
+PREPARE p1(int, int, int, int, int) AS
+SELECT * FROM test_squash WHERE id IN ($1, $2, $3, $4, $5);
+EXECUTE p1(1, 2, 3, 4, 5);
+ id | data 
+----+------
+(0 rows)
+
+DEALLOCATE p1;
+PREPARE p1(int, int, int, int, int) AS
+SELECT * FROM test_squash WHERE id = ANY(ARRAY[$1, $2, $3, $4, $5]);
+EXECUTE p1(1, 2, 3, 4, 5);
+ id | data 
+----+------
+(0 rows)
+
+DEALLOCATE p1;
+SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
+                           query                            | calls 
+------------------------------------------------------------+-------
+ DEALLOCATE $1                                              |     2
+ SELECT * FROM test_squash WHERE id IN ($1, $2, $3, $4, $5) |     2
+ SELECT pg_stat_statements_reset() IS NOT NULL AS t         |     1
+(3 rows)
 
 -- More conditions in the query
 SELECT pg_stat_statements_reset() IS NOT NULL AS t;
@@ -75,10 +184,25 @@ SELECT * FROM test_squash WHERE id IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11) AND da
 ----+------
 (0 rows)
 
+SELECT * FROM test_squash WHERE id = ANY (ARRAY[1, 2, 3, 4, 5, 6, 7, 8, 9]) AND data = 2;
+ id | data 
+----+------
+(0 rows)
+
+SELECT * FROM test_squash WHERE id = ANY (ARRAY[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) AND data = 2;
+ id | data 
+----+------
+(0 rows)
+
+SELECT * FROM test_squash WHERE id = ANY (ARRAY[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]) AND data = 2;
+ id | data 
+----+------
+(0 rows)
+
 SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
                                 query                                | calls 
 ---------------------------------------------------------------------+-------
- SELECT * FROM test_squash WHERE id IN ($1 /*, ... */) AND data = $2 |     3
+ SELECT * FROM test_squash WHERE id IN ($1 /*, ... */) AND data = $2 |     6
  SELECT pg_stat_statements_reset() IS NOT NULL AS t                  |     1
 (2 rows)
 
@@ -107,24 +231,46 @@ SELECT * FROM test_squash WHERE id IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)
 ----+------
 (0 rows)
 
+SELECT * FROM test_squash WHERE id = ANY (ARRAY[1, 2, 3, 4, 5, 6, 7, 8, 9])
+    AND data = ANY (ARRAY[1, 2, 3, 4, 5, 6, 7, 8, 9]);
+ id | data 
+----+------
+(0 rows)
+
+SELECT * FROM test_squash WHERE id = ANY (ARRAY[1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
+    AND data = ANY (ARRAY[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
+ id | data 
+----+------
+(0 rows)
+
+SELECT * FROM test_squash WHERE id = ANY (ARRAY[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
+    AND data = ANY (ARRAY[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
+ id | data 
+----+------
+(0 rows)
+
 SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
                          query                         | calls 
 -------------------------------------------------------+-------
- SELECT * FROM test_squash WHERE id IN ($1 /*, ... */)+|     3
+ SELECT * FROM test_squash WHERE id IN ($1 /*, ... */)+|     6
      AND data IN ($2 /*, ... */)                       | 
  SELECT pg_stat_statements_reset() IS NOT NULL AS t    |     1
 (2 rows)
 
--- No constants simplification for OpExpr
 SELECT pg_stat_statements_reset() IS NOT NULL AS t;
  t 
 ---
  t
 (1 row)
 
--- In the following two queries the operator expressions (+) and (@) have
--- different oppno, and will be given different query_id if squashed, even though
--- the normalized query will be the same
+-- No constants squashing for OpExpr
+-- The IN and ARRAY forms of this statement will have the same queryId
+SELECT pg_stat_statements_reset() IS NOT NULL AS t;
+ t 
+---
+ t
+(1 row)
+
 SELECT * FROM test_squash WHERE id IN
 	(1 + 1, 2 + 2, 3 + 3, 4 + 4, 5 + 5, 6 + 6, 7 + 7, 8 + 8, 9 + 9);
  id | data 
@@ -137,19 +283,35 @@ SELECT * FROM test_squash WHERE id IN
 ----+------
 (0 rows)
 
+SELECT * FROM test_squash WHERE id = ANY(ARRAY
+	[1 + 1, 2 + 2, 3 + 3, 4 + 4, 5 + 5, 6 + 6, 7 + 7, 8 + 8, 9 + 9]);
+ id | data 
+----+------
+(0 rows)
+
+SELECT * FROM test_squash WHERE id = ANY(ARRAY
+	[@ '-1', @ '-2', @ '-3', @ '-4', @ '-5', @ '-6', @ '-7', @ '-8', @ '-9']);
+ id | data 
+----+------
+(0 rows)
+
 SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
                                                query                                                | calls 
 ----------------------------------------------------------------------------------------------------+-------
- SELECT * FROM test_squash WHERE id IN                                                             +|     1
+ SELECT * FROM test_squash WHERE id IN                                                             +|     2
          ($1 + $2, $3 + $4, $5 + $6, $7 + $8, $9 + $10, $11 + $12, $13 + $14, $15 + $16, $17 + $18) | 
- SELECT * FROM test_squash WHERE id IN                                                             +|     1
+ SELECT * FROM test_squash WHERE id IN                                                             +|     2
          (@ $1, @ $2, @ $3, @ $4, @ $5, @ $6, @ $7, @ $8, @ $9)                                     | 
  SELECT pg_stat_statements_reset() IS NOT NULL AS t                                                 |     1
 (3 rows)
 
+--
 -- FuncExpr
+--
 -- Verify multiple type representation end up with the same query_id
 CREATE TABLE test_float (data float);
+-- The casted ARRAY expressions will have the same queryId as the IN clause
+-- form of the query
 SELECT pg_stat_statements_reset() IS NOT NULL AS t;
  t 
 ---
@@ -181,12 +343,38 @@ SELECT data FROM test_float WHERE data IN (1.0, 1.0);
 ------
 (0 rows)
 
+SELECT data FROM test_float WHERE data = ANY(ARRAY['1'::double precision, '2'::double precision]);
+ data 
+------
+(0 rows)
+
+SELECT data FROM test_float WHERE data = ANY(ARRAY[1.0::double precision, 1.0::double precision]);
+ data 
+------
+(0 rows)
+
+SELECT data FROM test_float WHERE data = ANY(ARRAY[1, 2]);
+ data 
+------
+(0 rows)
+
+SELECT data FROM test_float WHERE data = ANY(ARRAY[1, '2']);
+ data 
+------
+(0 rows)
+
+SELECT data FROM test_float WHERE data = ANY(ARRAY['1', 2]);
+ data 
+------
+(0 rows)
+
 SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
-                           query                           | calls 
------------------------------------------------------------+-------
- SELECT data FROM test_float WHERE data IN ($1 /*, ... */) |     5
- SELECT pg_stat_statements_reset() IS NOT NULL AS t        |     1
-(2 rows)
+                               query                                | calls 
+--------------------------------------------------------------------+-------
+ SELECT data FROM test_float WHERE data = ANY(ARRAY[$1 /*, ... */]) |     3
+ SELECT data FROM test_float WHERE data IN ($1 /*, ... */)          |     7
+ SELECT pg_stat_statements_reset() IS NOT NULL AS t                 |     1
+(3 rows)
 
 -- Numeric type, implicit cast is squashed
 CREATE TABLE test_squash_numeric (id int, data numeric(5, 2));
@@ -201,12 +389,18 @@ SELECT * FROM test_squash_numeric WHERE data IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
 ----+------
 (0 rows)
 
+SELECT * FROM test_squash_numeric WHERE data = ANY(ARRAY[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
+ id | data 
+----+------
+(0 rows)
+
 SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
-                              query                              | calls 
------------------------------------------------------------------+-------
- SELECT * FROM test_squash_numeric WHERE data IN ($1 /*, ... */) |     1
- SELECT pg_stat_statements_reset() IS NOT NULL AS t              |     1
-(2 rows)
+                                  query                                   | calls 
+--------------------------------------------------------------------------+-------
+ SELECT * FROM test_squash_numeric WHERE data = ANY(ARRAY[$1 /*, ... */]) |     1
+ SELECT * FROM test_squash_numeric WHERE data IN ($1 /*, ... */)          |     1
+ SELECT pg_stat_statements_reset() IS NOT NULL AS t                       |     1
+(3 rows)
 
 -- Bigint, implicit cast is squashed
 CREATE TABLE test_squash_bigint (id int, data bigint);
@@ -221,14 +415,20 @@ SELECT * FROM test_squash_bigint WHERE data IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1
 ----+------
 (0 rows)
 
-SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
-                             query                              | calls 
-----------------------------------------------------------------+-------
- SELECT * FROM test_squash_bigint WHERE data IN ($1 /*, ... */) |     1
- SELECT pg_stat_statements_reset() IS NOT NULL AS t             |     1
-(2 rows)
+SELECT * FROM test_squash_bigint WHERE data = ANY(ARRAY[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
+ id | data 
+----+------
+(0 rows)
 
--- Bigint, explicit cast is not squashed
+SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
+                                  query                                  | calls 
+-------------------------------------------------------------------------+-------
+ SELECT * FROM test_squash_bigint WHERE data = ANY(ARRAY[$1 /*, ... */]) |     1
+ SELECT * FROM test_squash_bigint WHERE data IN ($1 /*, ... */)          |     1
+ SELECT pg_stat_statements_reset() IS NOT NULL AS t                      |     1
+(3 rows)
+
+-- Bigint, explicit cast is squashed
 SELECT pg_stat_statements_reset() IS NOT NULL AS t;
  t 
 ---
@@ -242,15 +442,22 @@ SELECT * FROM test_squash_bigint WHERE data IN
 ----+------
 (0 rows)
 
+SELECT * FROM test_squash_bigint WHERE data = ANY(ARRAY[
+	 1::bigint, 2::bigint, 3::bigint, 4::bigint, 5::bigint, 6::bigint,
+	 7::bigint, 8::bigint, 9::bigint, 10::bigint, 11::bigint]);
+ id | data 
+----+------
+(0 rows)
+
 SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
                        query                        | calls 
 ----------------------------------------------------+-------
- SELECT * FROM test_squash_bigint WHERE data IN    +|     1
+ SELECT * FROM test_squash_bigint WHERE data IN    +|     2
          ($1 /*, ... */::bigint)                    | 
  SELECT pg_stat_statements_reset() IS NOT NULL AS t |     1
 (2 rows)
 
--- Bigint, long tokens with parenthesis
+-- Bigint, long tokens with parenthesis, will not squash
 SELECT pg_stat_statements_reset() IS NOT NULL AS t;
  t 
 ---
@@ -264,44 +471,47 @@ SELECT * FROM test_squash_bigint WHERE id IN
 ----+------
 (0 rows)
 
+SELECT * FROM test_squash_bigint WHERE id = ANY(ARRAY[
+	 abs(100), abs(200), abs(300), abs(400), abs(500), abs(600), abs(700),
+	 abs(800), abs(900), abs(1000), ((abs(1100)))]);
+ id | data 
+----+------
+(0 rows)
+
 SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
                                   query                                  | calls 
 -------------------------------------------------------------------------+-------
- SELECT * FROM test_squash_bigint WHERE id IN                           +|     1
+ SELECT * FROM test_squash_bigint WHERE id IN                           +|     2
          (abs($1), abs($2), abs($3), abs($4), abs($5), abs($6), abs($7),+| 
           abs($8), abs($9), abs($10), ((abs($11))))                      | 
  SELECT pg_stat_statements_reset() IS NOT NULL AS t                      |     1
 (2 rows)
 
--- CoerceViaIO, SubLink instead of a Const
-CREATE TABLE test_squash_jsonb (id int, data jsonb);
+-- Multiple FuncExpr's. Will not squash
 SELECT pg_stat_statements_reset() IS NOT NULL AS t;
  t 
 ---
  t
 (1 row)
 
-SELECT * FROM test_squash_jsonb WHERE data IN
-	((SELECT '"1"')::jsonb, (SELECT '"2"')::jsonb, (SELECT '"3"')::jsonb,
-	 (SELECT '"4"')::jsonb, (SELECT '"5"')::jsonb, (SELECT '"6"')::jsonb,
-	 (SELECT '"7"')::jsonb, (SELECT '"8"')::jsonb, (SELECT '"9"')::jsonb,
-	 (SELECT '"10"')::jsonb);
- id | data 
-----+------
-(0 rows)
+SELECT WHERE 1 IN (1::int::bigint::int, 2::int::bigint::int);
+--
+(1 row)
+
+SELECT WHERE 1 = ANY(ARRAY[1::int::bigint::int, 2::int::bigint::int]);
+--
+(1 row)
 
 SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
-                                query                                 | calls 
-----------------------------------------------------------------------+-------
- SELECT * FROM test_squash_jsonb WHERE data IN                       +|     1
-         ((SELECT $1)::jsonb, (SELECT $2)::jsonb, (SELECT $3)::jsonb,+| 
-          (SELECT $4)::jsonb, (SELECT $5)::jsonb, (SELECT $6)::jsonb,+| 
-          (SELECT $7)::jsonb, (SELECT $8)::jsonb, (SELECT $9)::jsonb,+| 
-          (SELECT $10)::jsonb)                                        | 
- SELECT pg_stat_statements_reset() IS NOT NULL AS t                   |     1
+                              query                              | calls 
+-----------------------------------------------------------------+-------
+ SELECT WHERE $1 IN ($2::int::bigint::int, $3::int::bigint::int) |     2
+ SELECT pg_stat_statements_reset() IS NOT NULL AS t              |     1
 (2 rows)
 
+--
 -- CoerceViaIO
+--
 -- Create some dummy type to force CoerceViaIO
 CREATE TYPE casttesttype;
 CREATE FUNCTION casttesttype_in(cstring)
@@ -349,15 +559,25 @@ SELECT * FROM test_squash_cast WHERE data IN
 ----+------
 (0 rows)
 
+SELECT * FROM test_squash_cast WHERE data = ANY (ARRAY
+	[1::int4::casttesttype, 2::int4::casttesttype, 3::int4::casttesttype,
+	 4::int4::casttesttype, 5::int4::casttesttype, 6::int4::casttesttype,
+	 7::int4::casttesttype, 8::int4::casttesttype, 9::int4::casttesttype,
+	 10::int4::casttesttype, 11::int4::casttesttype]);
+ id | data 
+----+------
+(0 rows)
+
 SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
                        query                        | calls 
 ----------------------------------------------------+-------
- SELECT * FROM test_squash_cast WHERE data IN      +|     1
+ SELECT * FROM test_squash_cast WHERE data IN      +|     2
          ($1 /*, ... */::int4::casttesttype)        | 
  SELECT pg_stat_statements_reset() IS NOT NULL AS t |     1
 (2 rows)
 
 -- Some casting expression are simplified to Const
+CREATE TABLE test_squash_jsonb (id int, data jsonb);
 SELECT pg_stat_statements_reset() IS NOT NULL AS t;
  t 
 ---
@@ -366,8 +586,16 @@ SELECT pg_stat_statements_reset() IS NOT NULL AS t;
 
 SELECT * FROM test_squash_jsonb WHERE data IN
 	(('"1"')::jsonb, ('"2"')::jsonb, ('"3"')::jsonb, ('"4"')::jsonb,
-	 ( '"5"')::jsonb, ( '"6"')::jsonb, ( '"7"')::jsonb, ( '"8"')::jsonb,
-	 ( '"9"')::jsonb, ( '"10"')::jsonb);
+	 ('"5"')::jsonb, ('"6"')::jsonb, ('"7"')::jsonb, ('"8"')::jsonb,
+	 ('"9"')::jsonb, ('"10"')::jsonb);
+ id | data 
+----+------
+(0 rows)
+
+SELECT * FROM test_squash_jsonb WHERE data = ANY (ARRAY
+	[('"1"')::jsonb, ('"2"')::jsonb, ('"3"')::jsonb, ('"4"')::jsonb,
+	 ('"5"')::jsonb, ('"6"')::jsonb, ('"7"')::jsonb, ('"8"')::jsonb,
+	 ('"9"')::jsonb, ('"10"')::jsonb]);
  id | data 
 ----+------
 (0 rows)
@@ -375,28 +603,144 @@ SELECT * FROM test_squash_jsonb WHERE data IN
 SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
                        query                        | calls 
 ----------------------------------------------------+-------
- SELECT * FROM test_squash_jsonb WHERE data IN     +|     1
+ SELECT * FROM test_squash_jsonb WHERE data IN     +|     2
          (($1 /*, ... */)::jsonb)                   | 
  SELECT pg_stat_statements_reset() IS NOT NULL AS t |     1
 (2 rows)
 
--- RelabelType
+-- CoerceViaIO, SubLink instead of a Const. Will not squash
 SELECT pg_stat_statements_reset() IS NOT NULL AS t;
  t 
 ---
  t
 (1 row)
 
-SELECT * FROM test_squash WHERE id IN (1::oid, 2::oid, 3::oid, 4::oid, 5::oid, 6::oid, 7::oid, 8::oid, 9::oid);
+SELECT * FROM test_squash_jsonb WHERE data IN
+	((SELECT '"1"')::jsonb, (SELECT '"2"')::jsonb, (SELECT '"3"')::jsonb,
+	 (SELECT '"4"')::jsonb, (SELECT '"5"')::jsonb, (SELECT '"6"')::jsonb,
+	 (SELECT '"7"')::jsonb, (SELECT '"8"')::jsonb, (SELECT '"9"')::jsonb,
+	 (SELECT '"10"')::jsonb);
+ id | data 
+----+------
+(0 rows)
+
+SELECT * FROM test_squash_jsonb WHERE data = ANY(ARRAY
+	[(SELECT '"1"')::jsonb, (SELECT '"2"')::jsonb, (SELECT '"3"')::jsonb,
+	 (SELECT '"4"')::jsonb, (SELECT '"5"')::jsonb, (SELECT '"6"')::jsonb,
+	 (SELECT '"7"')::jsonb, (SELECT '"8"')::jsonb, (SELECT '"9"')::jsonb,
+	 (SELECT '"10"')::jsonb]);
  id | data 
 ----+------
 (0 rows)
 
 SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
-                           query                            | calls 
-------------------------------------------------------------+-------
- SELECT * FROM test_squash WHERE id IN ($1 /*, ... */::oid) |     1
- SELECT pg_stat_statements_reset() IS NOT NULL AS t         |     1
+                                query                                 | calls 
+----------------------------------------------------------------------+-------
+ SELECT * FROM test_squash_jsonb WHERE data IN                       +|     2
+         ((SELECT $1)::jsonb, (SELECT $2)::jsonb, (SELECT $3)::jsonb,+| 
+          (SELECT $4)::jsonb, (SELECT $5)::jsonb, (SELECT $6)::jsonb,+| 
+          (SELECT $7)::jsonb, (SELECT $8)::jsonb, (SELECT $9)::jsonb,+| 
+          (SELECT $10)::jsonb)                                        | 
+ SELECT pg_stat_statements_reset() IS NOT NULL AS t                   |     1
+(2 rows)
+
+-- Multiple CoerceViaIO wrapping a constant. Will not squash
+SELECT pg_stat_statements_reset() IS NOT NULL AS t;
+ t 
+---
+ t
+(1 row)
+
+SELECT WHERE 1 IN (1::text::int::text::int, 1::text::int::text::int);
+--
+(1 row)
+
+SELECT WHERE 1 = ANY(ARRAY[1::text::int::text::int, 1::text::int::text::int]);
+--
+(1 row)
+
+SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
+                                  query                                  | calls 
+-------------------------------------------------------------------------+-------
+ SELECT WHERE $1 IN ($2::text::int::text::int, $3::text::int::text::int) |     2
+ SELECT pg_stat_statements_reset() IS NOT NULL AS t                      |     1
+(2 rows)
+
+--
+-- RelabelType
+--
+SELECT pg_stat_statements_reset() IS NOT NULL AS t;
+ t 
+---
+ t
+(1 row)
+
+-- if there is only one level of RelabelType, the list will be squashable
+SELECT * FROM test_squash WHERE id IN
+	(1::oid, 2::oid, 3::oid, 4::oid, 5::oid, 6::oid, 7::oid, 8::oid, 9::oid);
+ id | data 
+----+------
+(0 rows)
+
+SELECT ARRAY[1::oid, 2::oid, 3::oid, 4::oid, 5::oid, 6::oid, 7::oid, 8::oid, 9::oid];
+        array        
+---------------------
+ {1,2,3,4,5,6,7,8,9}
+(1 row)
+
+-- if there is at least one element with multiple levels of RelabelType,
+-- the list will not be squashable
+SELECT * FROM test_squash WHERE id IN (1::oid, 2::oid::int::oid);
+ id | data 
+----+------
+(0 rows)
+
+SELECT * FROM test_squash WHERE id = ANY(ARRAY[1::oid, 2::oid::int::oid]);
+ id | data 
+----+------
+(0 rows)
+
+SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
+                               query                                | calls 
+--------------------------------------------------------------------+-------
+ SELECT * FROM test_squash WHERE id IN                             +|     1
+         ($1 /*, ... */::oid)                                       | 
+ SELECT * FROM test_squash WHERE id IN ($1::oid, $2::oid::int::oid) |     2
+ SELECT ARRAY[$1 /*, ... */::oid]                                   |     1
+ SELECT pg_stat_statements_reset() IS NOT NULL AS t                 |     1
+(4 rows)
+
+--
+-- edge cases
+--
+SELECT pg_stat_statements_reset() IS NOT NULL AS t;
+ t 
+---
+ t
+(1 row)
+
+-- for nested arrays, only constants are squashed
+SELECT ARRAY[
+    ARRAY[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
+    ARRAY[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
+    ARRAY[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
+    ARRAY[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+    ];
+                                             array                                             
+-----------------------------------------------------------------------------------------------
+ {{1,2,3,4,5,6,7,8,9,10},{1,2,3,4,5,6,7,8,9,10},{1,2,3,4,5,6,7,8,9,10},{1,2,3,4,5,6,7,8,9,10}}
+(1 row)
+
+SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
+                       query                        | calls 
+----------------------------------------------------+-------
+ SELECT ARRAY[                                     +|     1
+     ARRAY[$1 /*, ... */],                         +| 
+     ARRAY[$2 /*, ... */],                         +| 
+     ARRAY[$3 /*, ... */],                         +| 
+     ARRAY[$4 /*, ... */]                          +| 
+     ]                                              | 
+ SELECT pg_stat_statements_reset() IS NOT NULL AS t |     1
 (2 rows)
 
 -- Test constants evaluation in a CTE, which was causing issues in the past
@@ -409,23 +753,59 @@ FROM cte;
 --------
 (0 rows)
 
--- Simple array would be squashed as well
 SELECT pg_stat_statements_reset() IS NOT NULL AS t;
  t 
 ---
  t
 (1 row)
 
-SELECT ARRAY[1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
-         array          
-------------------------
- {1,2,3,4,5,6,7,8,9,10}
+-- Rewritten as an OpExpr, so it will not be squashed
+select where '1' IN ('1'::int, '2'::int::text);
+--
+(1 row)
+
+-- Rewritten as an ArrayExpr, so it will be squashed
+select where '1' IN ('1'::int, '2'::int);
+--
 (1 row)
 
 SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
                        query                        | calls 
 ----------------------------------------------------+-------
- SELECT ARRAY[$1 /*, ... */]                        |     1
  SELECT pg_stat_statements_reset() IS NOT NULL AS t |     1
+ select where $1 IN ($2 /*, ... */::int)            |     1
+ select where $1 IN ($2::int, $3::int::text)        |     1
+(3 rows)
+
+SELECT pg_stat_statements_reset() IS NOT NULL AS t;
+ t 
+---
+ t
+(1 row)
+
+-- Both of these queries will be rewritten as an ArrayExpr, so they
+-- will be squashed, and have a similar queryId
+select where '1' IN ('1'::int::text, '2'::int::text);
+--
+(1 row)
+
+select where '1' = ANY (array['1'::int::text, '2'::int::text]);
+--
+(1 row)
+
+SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
+                       query                        | calls 
+----------------------------------------------------+-------
+ SELECT pg_stat_statements_reset() IS NOT NULL AS t |     1
+ select where $1 IN ($2 /*, ... */::int::text)      |     2
 (2 rows)
 
+--
+-- cleanup
+--
+DROP TABLE test_squash;
+DROP TABLE test_float;
+DROP TABLE test_squash_numeric;
+DROP TABLE test_squash_bigint;
+DROP TABLE test_squash_cast CASCADE;
+DROP TABLE test_squash_jsonb;
diff --git a/contrib/pg_stat_statements/sql/squashing.sql b/contrib/pg_stat_statements/sql/squashing.sql
index 03efd4b40c8..85aae152da8 100644
--- a/contrib/pg_stat_statements/sql/squashing.sql
+++ b/contrib/pg_stat_statements/sql/squashing.sql
@@ -3,101 +3,160 @@
 --
 CREATE EXTENSION pg_stat_statements;
 
+--
+--Simple Lists
+--
+
 CREATE TABLE test_squash (id int, data int);
 
--- IN queries
-
--- Normal scenario, too many simple constants for an IN query
+-- single element will not be squashed
 SELECT pg_stat_statements_reset() IS NOT NULL AS t;
 SELECT * FROM test_squash WHERE id IN (1);
-SELECT * FROM test_squash WHERE id IN (1, 2, 3);
+SELECT ARRAY[1];
 SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
 
-SELECT * FROM test_squash WHERE id IN (1, 2, 3, 4, 5, 6, 7, 8, 9);
-SELECT * FROM test_squash WHERE id IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
-SELECT * FROM test_squash WHERE id IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
+-- more than 1 element in a list will be squashed
+SELECT pg_stat_statements_reset() IS NOT NULL AS t;
+SELECT * FROM test_squash WHERE id IN (1, 2, 3);
+SELECT * FROM test_squash WHERE id IN (1, 2, 3, 4);
+SELECT * FROM test_squash WHERE id IN (1, 2, 3, 4, 5);
+SELECT ARRAY[1, 2, 3];
+SELECT ARRAY[1, 2, 3, 4];
+SELECT ARRAY[1, 2, 3, 4, 5];
+SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
+
+-- built-in functions will be squashed
+-- the IN and ARRAY forms of this statement will have the same queryId
+SELECT pg_stat_statements_reset() IS NOT NULL AS t;
+SELECT WHERE 1 IN (1, int4(1), int4(2), 2);
+SELECT WHERE 1 = ANY (ARRAY[1, int4(1), int4(2), 2]);
+SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
+
+-- external parameters will not be squashed
+SELECT pg_stat_statements_reset() IS NOT NULL AS t;
+SELECT * FROM test_squash WHERE id IN ($1, $2, $3, $4, $5)  \bind 1 2 3 4 5
+;
+SELECT * FROM test_squash WHERE id::text = ANY(ARRAY[$1, $2, $3, $4, $5]) \bind 1 2 3 4 5
+;
+SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
+
+-- neither are prepared statements
+-- the IN and ARRAY forms of this statement will have the same queryId
+SELECT pg_stat_statements_reset() IS NOT NULL AS t;
+PREPARE p1(int, int, int, int, int) AS
+SELECT * FROM test_squash WHERE id IN ($1, $2, $3, $4, $5);
+EXECUTE p1(1, 2, 3, 4, 5);
+DEALLOCATE p1;
+PREPARE p1(int, int, int, int, int) AS
+SELECT * FROM test_squash WHERE id = ANY(ARRAY[$1, $2, $3, $4, $5]);
+EXECUTE p1(1, 2, 3, 4, 5);
+DEALLOCATE p1;
 SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
 
 -- More conditions in the query
 SELECT pg_stat_statements_reset() IS NOT NULL AS t;
-
 SELECT * FROM test_squash WHERE id IN (1, 2, 3, 4, 5, 6, 7, 8, 9) AND data = 2;
 SELECT * FROM test_squash WHERE id IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10) AND data = 2;
 SELECT * FROM test_squash WHERE id IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11) AND data = 2;
+SELECT * FROM test_squash WHERE id = ANY (ARRAY[1, 2, 3, 4, 5, 6, 7, 8, 9]) AND data = 2;
+SELECT * FROM test_squash WHERE id = ANY (ARRAY[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) AND data = 2;
+SELECT * FROM test_squash WHERE id = ANY (ARRAY[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]) AND data = 2;
 SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
 
 -- Multiple squashed intervals
 SELECT pg_stat_statements_reset() IS NOT NULL AS t;
-
 SELECT * FROM test_squash WHERE id IN (1, 2, 3, 4, 5, 6, 7, 8, 9)
     AND data IN (1, 2, 3, 4, 5, 6, 7, 8, 9);
 SELECT * FROM test_squash WHERE id IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
     AND data IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
 SELECT * FROM test_squash WHERE id IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)
     AND data IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
+SELECT * FROM test_squash WHERE id = ANY (ARRAY[1, 2, 3, 4, 5, 6, 7, 8, 9])
+    AND data = ANY (ARRAY[1, 2, 3, 4, 5, 6, 7, 8, 9]);
+SELECT * FROM test_squash WHERE id = ANY (ARRAY[1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
+    AND data = ANY (ARRAY[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
+SELECT * FROM test_squash WHERE id = ANY (ARRAY[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
+    AND data = ANY (ARRAY[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
 SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
-
--- No constants simplification for OpExpr
 SELECT pg_stat_statements_reset() IS NOT NULL AS t;
 
--- In the following two queries the operator expressions (+) and (@) have
--- different oppno, and will be given different query_id if squashed, even though
--- the normalized query will be the same
+-- No constants squashing for OpExpr
+-- The IN and ARRAY forms of this statement will have the same queryId
+SELECT pg_stat_statements_reset() IS NOT NULL AS t;
 SELECT * FROM test_squash WHERE id IN
 	(1 + 1, 2 + 2, 3 + 3, 4 + 4, 5 + 5, 6 + 6, 7 + 7, 8 + 8, 9 + 9);
 SELECT * FROM test_squash WHERE id IN
 	(@ '-1', @ '-2', @ '-3', @ '-4', @ '-5', @ '-6', @ '-7', @ '-8', @ '-9');
+SELECT * FROM test_squash WHERE id = ANY(ARRAY
+	[1 + 1, 2 + 2, 3 + 3, 4 + 4, 5 + 5, 6 + 6, 7 + 7, 8 + 8, 9 + 9]);
+SELECT * FROM test_squash WHERE id = ANY(ARRAY
+	[@ '-1', @ '-2', @ '-3', @ '-4', @ '-5', @ '-6', @ '-7', @ '-8', @ '-9']);
 SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
 
+--
 -- FuncExpr
+--
 
 -- Verify multiple type representation end up with the same query_id
 CREATE TABLE test_float (data float);
+-- The casted ARRAY expressions will have the same queryId as the IN clause
+-- form of the query
 SELECT pg_stat_statements_reset() IS NOT NULL AS t;
 SELECT data FROM test_float WHERE data IN (1, 2);
 SELECT data FROM test_float WHERE data IN (1, '2');
 SELECT data FROM test_float WHERE data IN ('1', 2);
 SELECT data FROM test_float WHERE data IN ('1', '2');
 SELECT data FROM test_float WHERE data IN (1.0, 1.0);
+SELECT data FROM test_float WHERE data = ANY(ARRAY['1'::double precision, '2'::double precision]);
+SELECT data FROM test_float WHERE data = ANY(ARRAY[1.0::double precision, 1.0::double precision]);
+SELECT data FROM test_float WHERE data = ANY(ARRAY[1, 2]);
+SELECT data FROM test_float WHERE data = ANY(ARRAY[1, '2']);
+SELECT data FROM test_float WHERE data = ANY(ARRAY['1', 2]);
 SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
 
 -- Numeric type, implicit cast is squashed
 CREATE TABLE test_squash_numeric (id int, data numeric(5, 2));
 SELECT pg_stat_statements_reset() IS NOT NULL AS t;
 SELECT * FROM test_squash_numeric WHERE data IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
+SELECT * FROM test_squash_numeric WHERE data = ANY(ARRAY[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
 SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
 
 -- Bigint, implicit cast is squashed
 CREATE TABLE test_squash_bigint (id int, data bigint);
 SELECT pg_stat_statements_reset() IS NOT NULL AS t;
 SELECT * FROM test_squash_bigint WHERE data IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
+SELECT * FROM test_squash_bigint WHERE data = ANY(ARRAY[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
 SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
 
--- Bigint, explicit cast is not squashed
+-- Bigint, explicit cast is squashed
 SELECT pg_stat_statements_reset() IS NOT NULL AS t;
 SELECT * FROM test_squash_bigint WHERE data IN
 	(1::bigint, 2::bigint, 3::bigint, 4::bigint, 5::bigint, 6::bigint,
 	 7::bigint, 8::bigint, 9::bigint, 10::bigint, 11::bigint);
+SELECT * FROM test_squash_bigint WHERE data = ANY(ARRAY[
+	 1::bigint, 2::bigint, 3::bigint, 4::bigint, 5::bigint, 6::bigint,
+	 7::bigint, 8::bigint, 9::bigint, 10::bigint, 11::bigint]);
 SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
 
--- Bigint, long tokens with parenthesis
+-- Bigint, long tokens with parenthesis, will not squash
 SELECT pg_stat_statements_reset() IS NOT NULL AS t;
 SELECT * FROM test_squash_bigint WHERE id IN
 	(abs(100), abs(200), abs(300), abs(400), abs(500), abs(600), abs(700),
 	 abs(800), abs(900), abs(1000), ((abs(1100))));
+SELECT * FROM test_squash_bigint WHERE id = ANY(ARRAY[
+	 abs(100), abs(200), abs(300), abs(400), abs(500), abs(600), abs(700),
+	 abs(800), abs(900), abs(1000), ((abs(1100)))]);
 SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
 
--- CoerceViaIO, SubLink instead of a Const
-CREATE TABLE test_squash_jsonb (id int, data jsonb);
+-- Multiple FuncExpr's. Will not squash
 SELECT pg_stat_statements_reset() IS NOT NULL AS t;
-SELECT * FROM test_squash_jsonb WHERE data IN
-	((SELECT '"1"')::jsonb, (SELECT '"2"')::jsonb, (SELECT '"3"')::jsonb,
-	 (SELECT '"4"')::jsonb, (SELECT '"5"')::jsonb, (SELECT '"6"')::jsonb,
-	 (SELECT '"7"')::jsonb, (SELECT '"8"')::jsonb, (SELECT '"9"')::jsonb,
-	 (SELECT '"10"')::jsonb);
+SELECT WHERE 1 IN (1::int::bigint::int, 2::int::bigint::int);
+SELECT WHERE 1 = ANY(ARRAY[1::int::bigint::int, 2::int::bigint::int]);
 SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
 
+--
 -- CoerceViaIO
+--
 
 -- Create some dummy type to force CoerceViaIO
 CREATE TYPE casttesttype;
@@ -141,19 +200,73 @@ SELECT * FROM test_squash_cast WHERE data IN
 	 4::int4::casttesttype, 5::int4::casttesttype, 6::int4::casttesttype,
 	 7::int4::casttesttype, 8::int4::casttesttype, 9::int4::casttesttype,
 	 10::int4::casttesttype, 11::int4::casttesttype);
+SELECT * FROM test_squash_cast WHERE data = ANY (ARRAY
+	[1::int4::casttesttype, 2::int4::casttesttype, 3::int4::casttesttype,
+	 4::int4::casttesttype, 5::int4::casttesttype, 6::int4::casttesttype,
+	 7::int4::casttesttype, 8::int4::casttesttype, 9::int4::casttesttype,
+	 10::int4::casttesttype, 11::int4::casttesttype]);
 SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
 
 -- Some casting expression are simplified to Const
+CREATE TABLE test_squash_jsonb (id int, data jsonb);
 SELECT pg_stat_statements_reset() IS NOT NULL AS t;
 SELECT * FROM test_squash_jsonb WHERE data IN
 	(('"1"')::jsonb, ('"2"')::jsonb, ('"3"')::jsonb, ('"4"')::jsonb,
-	 ( '"5"')::jsonb, ( '"6"')::jsonb, ( '"7"')::jsonb, ( '"8"')::jsonb,
-	 ( '"9"')::jsonb, ( '"10"')::jsonb);
+	 ('"5"')::jsonb, ('"6"')::jsonb, ('"7"')::jsonb, ('"8"')::jsonb,
+	 ('"9"')::jsonb, ('"10"')::jsonb);
+SELECT * FROM test_squash_jsonb WHERE data = ANY (ARRAY
+	[('"1"')::jsonb, ('"2"')::jsonb, ('"3"')::jsonb, ('"4"')::jsonb,
+	 ('"5"')::jsonb, ('"6"')::jsonb, ('"7"')::jsonb, ('"8"')::jsonb,
+	 ('"9"')::jsonb, ('"10"')::jsonb]);
 SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
 
--- RelabelType
+-- CoerceViaIO, SubLink instead of a Const. Will not squash
 SELECT pg_stat_statements_reset() IS NOT NULL AS t;
-SELECT * FROM test_squash WHERE id IN (1::oid, 2::oid, 3::oid, 4::oid, 5::oid, 6::oid, 7::oid, 8::oid, 9::oid);
+SELECT * FROM test_squash_jsonb WHERE data IN
+	((SELECT '"1"')::jsonb, (SELECT '"2"')::jsonb, (SELECT '"3"')::jsonb,
+	 (SELECT '"4"')::jsonb, (SELECT '"5"')::jsonb, (SELECT '"6"')::jsonb,
+	 (SELECT '"7"')::jsonb, (SELECT '"8"')::jsonb, (SELECT '"9"')::jsonb,
+	 (SELECT '"10"')::jsonb);
+SELECT * FROM test_squash_jsonb WHERE data = ANY(ARRAY
+	[(SELECT '"1"')::jsonb, (SELECT '"2"')::jsonb, (SELECT '"3"')::jsonb,
+	 (SELECT '"4"')::jsonb, (SELECT '"5"')::jsonb, (SELECT '"6"')::jsonb,
+	 (SELECT '"7"')::jsonb, (SELECT '"8"')::jsonb, (SELECT '"9"')::jsonb,
+	 (SELECT '"10"')::jsonb]);
+SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
+
+-- Multiple CoerceViaIO wrapping a constant. Will not squash
+SELECT pg_stat_statements_reset() IS NOT NULL AS t;
+SELECT WHERE 1 IN (1::text::int::text::int, 1::text::int::text::int);
+SELECT WHERE 1 = ANY(ARRAY[1::text::int::text::int, 1::text::int::text::int]);
+SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
+
+--
+-- RelabelType
+--
+
+SELECT pg_stat_statements_reset() IS NOT NULL AS t;
+-- if there is only one level of RelabelType, the list will be squashable
+SELECT * FROM test_squash WHERE id IN
+	(1::oid, 2::oid, 3::oid, 4::oid, 5::oid, 6::oid, 7::oid, 8::oid, 9::oid);
+SELECT ARRAY[1::oid, 2::oid, 3::oid, 4::oid, 5::oid, 6::oid, 7::oid, 8::oid, 9::oid];
+-- if there is at least one element with multiple levels of RelabelType,
+-- the list will not be squashable
+SELECT * FROM test_squash WHERE id IN (1::oid, 2::oid::int::oid);
+SELECT * FROM test_squash WHERE id = ANY(ARRAY[1::oid, 2::oid::int::oid]);
+SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
+
+--
+-- edge cases
+--
+
+SELECT pg_stat_statements_reset() IS NOT NULL AS t;
+-- for nested arrays, only constants are squashed
+SELECT ARRAY[
+    ARRAY[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
+    ARRAY[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
+    ARRAY[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
+    ARRAY[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+    ];
 SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
 
 -- Test constants evaluation in a CTE, which was causing issues in the past
@@ -163,7 +276,26 @@ WITH cte AS (
 SELECT ARRAY['a', 'b', 'c', const::varchar] AS result
 FROM cte;
 
--- Simple array would be squashed as well
 SELECT pg_stat_statements_reset() IS NOT NULL AS t;
-SELECT ARRAY[1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+-- Rewritten as an OpExpr, so it will not be squashed
+select where '1' IN ('1'::int, '2'::int::text);
+-- Rewritten as an ArrayExpr, so it will be squashed
+select where '1' IN ('1'::int, '2'::int);
 SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
+
+SELECT pg_stat_statements_reset() IS NOT NULL AS t;
+-- Both of these queries will be rewritten as an ArrayExpr, so they
+-- will be squashed, and have a similar queryId
+select where '1' IN ('1'::int::text, '2'::int::text);
+select where '1' = ANY (array['1'::int::text, '2'::int::text]);
+SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
+
+--
+-- cleanup
+--
+DROP TABLE test_squash;
+DROP TABLE test_float;
+DROP TABLE test_squash_numeric;
+DROP TABLE test_squash_bigint;
+DROP TABLE test_squash_cast CASCADE;
+DROP TABLE test_squash_jsonb;
\ No newline at end of file
-- 
2.39.5

