summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--contrib/pg_stat_statements/expected/squashing.out40
-rw-r--r--contrib/pg_stat_statements/sql/squashing.sql9
-rw-r--r--src/backend/nodes/queryjumblefuncs.c27
3 files changed, 45 insertions, 31 deletions
diff --git a/contrib/pg_stat_statements/expected/squashing.out b/contrib/pg_stat_statements/expected/squashing.out
index 7b935d464ec..e978564ad72 100644
--- a/contrib/pg_stat_statements/expected/squashing.out
+++ b/contrib/pg_stat_statements/expected/squashing.out
@@ -645,7 +645,7 @@ SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
SELECT pg_stat_statements_reset() IS NOT NULL AS t | 1
(2 rows)
--- Multiple CoerceViaIO wrapping a constant. Will not squash
+-- Multiple CoerceViaIO are squashed
SELECT pg_stat_statements_reset() IS NOT NULL AS t;
t
---
@@ -661,10 +661,10 @@ 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
+ query | calls
+----------------------------------------------------+-------
+ SELECT WHERE $1 IN ($2 /*, ... */) | 2
+ SELECT pg_stat_statements_reset() IS NOT NULL AS t | 1
(2 rows)
--
@@ -676,7 +676,7 @@ SELECT pg_stat_statements_reset() IS NOT NULL AS t;
t
(1 row)
--- if there is only one level of RelabelType, the list will be squashable
+-- However many layers of RelabelType there are, 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
@@ -689,8 +689,6 @@ SELECT ARRAY[1::oid, 2::oid, 3::oid, 4::oid, 5::oid, 6::oid, 7::oid, 8::oid, 9::
{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
----+------
@@ -701,15 +699,25 @@ SELECT * FROM test_squash WHERE id = ANY(ARRAY[1::oid, 2::oid::int::oid]);
----+------
(0 rows)
+-- RelabelType together with CoerceViaIO is also squashable
+SELECT * FROM test_squash WHERE id = ANY(ARRAY[1::oid::text::int::oid, 2::oid::int::oid]);
+ id | data
+----+------
+(0 rows)
+
+SELECT * FROM test_squash WHERE id = ANY(ARRAY[1::text::int::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 /*, ... */) |
- SELECT * FROM test_squash WHERE id IN ($1::oid, $2::oid::int::oid) | 2
- SELECT ARRAY[$1 /*, ... */] | 1
- SELECT pg_stat_statements_reset() IS NOT NULL AS t | 1
-(4 rows)
+ query | calls
+----------------------------------------------------+-------
+ SELECT * FROM test_squash WHERE id IN +| 5
+ ($1 /*, ... */) |
+ SELECT ARRAY[$1 /*, ... */] | 1
+ SELECT pg_stat_statements_reset() IS NOT NULL AS t | 1
+(3 rows)
--
-- edge cases
diff --git a/contrib/pg_stat_statements/sql/squashing.sql b/contrib/pg_stat_statements/sql/squashing.sql
index bd3243ec9cd..946e149831c 100644
--- a/contrib/pg_stat_statements/sql/squashing.sql
+++ b/contrib/pg_stat_statements/sql/squashing.sql
@@ -234,7 +234,7 @@ SELECT * FROM test_squash_jsonb WHERE data = ANY(ARRAY
(SELECT '"10"')::jsonb]);
SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
--- Multiple CoerceViaIO wrapping a constant. Will not squash
+-- Multiple CoerceViaIO are squashed
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]);
@@ -245,14 +245,15 @@ SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
--
SELECT pg_stat_statements_reset() IS NOT NULL AS t;
--- if there is only one level of RelabelType, the list will be squashable
+-- However many layers of RelabelType there are, 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]);
+-- RelabelType together with CoerceViaIO is also squashable
+SELECT * FROM test_squash WHERE id = ANY(ARRAY[1::oid::text::int::oid, 2::oid::int::oid]);
+SELECT * FROM test_squash WHERE id = ANY(ARRAY[1::text::int::oid, 2::oid::int::oid]);
SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
--
diff --git a/src/backend/nodes/queryjumblefuncs.c b/src/backend/nodes/queryjumblefuncs.c
index fb33e6931ad..62e3a677cd1 100644
--- a/src/backend/nodes/queryjumblefuncs.c
+++ b/src/backend/nodes/queryjumblefuncs.c
@@ -414,7 +414,7 @@ RecordConstLocation(JumbleState *jstate, int location, int len)
* Subroutine for _jumbleElements: Verify a few simple cases where we can
* deduce that the expression is a constant:
*
- * - Ignore a possible wrapping RelabelType and CoerceViaIO.
+ * - See through any wrapping RelabelType and CoerceViaIO layers.
* - If it's a FuncExpr, check that the function is a builtin
* cast and its arguments are Const.
* - Otherwise test if the expression is a simple Const.
@@ -422,14 +422,22 @@ RecordConstLocation(JumbleState *jstate, int location, int len)
static bool
IsSquashableConstant(Node *element)
{
- if (IsA(element, RelabelType))
- element = (Node *) ((RelabelType *) element)->arg;
-
- if (IsA(element, CoerceViaIO))
- element = (Node *) ((CoerceViaIO *) element)->arg;
-
+restart:
switch (nodeTag(element))
{
+ case T_RelabelType:
+ /* Unwrap RelabelType */
+ element = (Node *) ((RelabelType *) element)->arg;
+ goto restart;
+
+ case T_CoerceViaIO:
+ /* Unwrap CoerceViaIO */
+ element = (Node *) ((CoerceViaIO *) element)->arg;
+ goto restart;
+
+ case T_Const:
+ return true;
+
case T_FuncExpr:
{
FuncExpr *func = (FuncExpr *) element;
@@ -468,11 +476,8 @@ IsSquashableConstant(Node *element)
}
default:
- if (!IsA(element, Const))
- return false;
+ return false;
}
-
- return true;
}
/*