diff options
-rw-r--r-- | contrib/pg_stat_statements/expected/squashing.out | 40 | ||||
-rw-r--r-- | contrib/pg_stat_statements/sql/squashing.sql | 9 | ||||
-rw-r--r-- | src/backend/nodes/queryjumblefuncs.c | 27 |
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; } /* |