Improve jumble squashing through CoerceViaIO and RelabelType

There's no principled reason for query jumbling to only remove the first
layer of RelabelType and CoerceViaIO.  Change it to see through as many
layers as there are.
master
Álvaro Herrera 5 days ago
parent 303ba0573c
commit debad29d22
No known key found for this signature in database
GPG Key ID: 1C20ACB9D5C564AE
  1. 40
      contrib/pg_stat_statements/expected/squashing.out
  2. 9
      contrib/pg_stat_statements/sql/squashing.sql
  3. 27
      src/backend/nodes/queryjumblefuncs.c

@ -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 SELECT pg_stat_statements_reset() IS NOT NULL AS t | 1
(2 rows) (2 rows)
-- Multiple CoerceViaIO wrapping a constant. Will not squash -- Multiple CoerceViaIO are squashed
SELECT pg_stat_statements_reset() IS NOT NULL AS t; SELECT pg_stat_statements_reset() IS NOT NULL AS t;
t t
--- ---
@ -661,10 +661,10 @@ SELECT WHERE 1 = ANY(ARRAY[1::text::int::text::int, 1::text::int::text::int]);
(1 row) (1 row)
SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C"; SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
query | calls query | calls
-------------------------------------------------------------------------+------- ----------------------------------------------------+-------
SELECT WHERE $1 IN ($2::text::int::text::int, $3::text::int::text::int) | 2 SELECT WHERE $1 IN ($2 /*, ... */) | 2
SELECT pg_stat_statements_reset() IS NOT NULL AS t | 1 SELECT pg_stat_statements_reset() IS NOT NULL AS t | 1
(2 rows) (2 rows)
-- --
@ -676,7 +676,7 @@ SELECT pg_stat_statements_reset() IS NOT NULL AS t;
t t
(1 row) (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 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); (1::oid, 2::oid, 3::oid, 4::oid, 5::oid, 6::oid, 7::oid, 8::oid, 9::oid);
id | data 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,2,3,4,5,6,7,8,9}
(1 row) (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); SELECT * FROM test_squash WHERE id IN (1::oid, 2::oid::int::oid);
id | data id | data
----+------ ----+------
@ -701,15 +699,25 @@ SELECT * FROM test_squash WHERE id = ANY(ARRAY[1::oid, 2::oid::int::oid]);
----+------ ----+------
(0 rows) (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"; SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
query | calls query | calls
--------------------------------------------------------------------+------- ----------------------------------------------------+-------
SELECT * FROM test_squash WHERE id IN +| 1 SELECT * FROM test_squash WHERE id IN +| 5
($1 /*, ... */) | ($1 /*, ... */) |
SELECT * FROM test_squash WHERE id IN ($1::oid, $2::oid::int::oid) | 2 SELECT ARRAY[$1 /*, ... */] | 1
SELECT ARRAY[$1 /*, ... */] | 1 SELECT pg_stat_statements_reset() IS NOT NULL AS t | 1
SELECT pg_stat_statements_reset() IS NOT NULL AS t | 1 (3 rows)
(4 rows)
-- --
-- edge cases -- edge cases

@ -234,7 +234,7 @@ SELECT * FROM test_squash_jsonb WHERE data = ANY(ARRAY
(SELECT '"10"')::jsonb]); (SELECT '"10"')::jsonb]);
SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C"; 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 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 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 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; 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 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); (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]; 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 IN (1::oid, 2::oid::int::oid);
SELECT * FROM test_squash WHERE id = ANY(ARRAY[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"; SELECT query, calls FROM pg_stat_statements ORDER BY query COLLATE "C";
-- --

@ -414,7 +414,7 @@ RecordConstLocation(JumbleState *jstate, int location, int len)
* Subroutine for _jumbleElements: Verify a few simple cases where we can * Subroutine for _jumbleElements: Verify a few simple cases where we can
* deduce that the expression is a constant: * 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 * - If it's a FuncExpr, check that the function is a builtin
* cast and its arguments are Const. * cast and its arguments are Const.
* - Otherwise test if the expression is a simple Const. * - Otherwise test if the expression is a simple Const.
@ -422,14 +422,22 @@ RecordConstLocation(JumbleState *jstate, int location, int len)
static bool static bool
IsSquashableConstant(Node *element) IsSquashableConstant(Node *element)
{ {
if (IsA(element, RelabelType)) restart:
element = (Node *) ((RelabelType *) element)->arg;
if (IsA(element, CoerceViaIO))
element = (Node *) ((CoerceViaIO *) element)->arg;
switch (nodeTag(element)) 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: case T_FuncExpr:
{ {
FuncExpr *func = (FuncExpr *) element; FuncExpr *func = (FuncExpr *) element;
@ -468,11 +476,8 @@ IsSquashableConstant(Node *element)
} }
default: default:
if (!IsA(element, Const)) return false;
return false;
} }
return true;
} }
/* /*

Loading…
Cancel
Save