mirror of
https://github.com/postgres/postgres.git
synced 2026-01-05 23:38:41 +03:00
Transform OR-clauses to SAOP's during index matching
This commit makes match_clause_to_indexcol() match "(indexkey op C1) OR (indexkey op C2) ... (indexkey op CN)" expression to the index while transforming it into "indexkey op ANY(ARRAY[C1, C2, ...])" (ScalarArrayOpExpr node). This transformation allows handling long OR-clauses with single IndexScan avoiding diving them into a slower BitmapOr. We currently restrict Ci to be either Const or Param to apply this transformation only when it's clearly beneficial. However, in the future, we might switch to a liberal understanding of constants, as it is in other cases. Discussion: https://postgr.es/m/567ED6CA.2040504%40sigaev.ru Author: Alena Rybakina, Andrey Lepikhov, Alexander Korotkov Reviewed-by: Peter Geoghegan, Ranier Vilela, Alexander Korotkov, Robert Haas Reviewed-by: Jian He, Tom Lane, Nikolay Shaplov
This commit is contained in:
@@ -732,12 +732,81 @@ SELECT * FROM tenk1
|
||||
SELECT * FROM tenk1
|
||||
WHERE thousand = 42 AND (tenthous = 1 OR tenthous = 3 OR tenthous = 42);
|
||||
|
||||
EXPLAIN (COSTS OFF)
|
||||
SELECT * FROM tenk1
|
||||
WHERE thousand = 42 AND (tenthous = 1 OR tenthous = (SELECT 1 + 2) OR tenthous = 42);
|
||||
SELECT * FROM tenk1
|
||||
WHERE thousand = 42 AND (tenthous = 1 OR tenthous = (SELECT 1 + 2) OR tenthous = 42);
|
||||
|
||||
EXPLAIN (COSTS OFF)
|
||||
SELECT count(*) FROM tenk1
|
||||
WHERE hundred = 42 AND (thousand = 42 OR thousand = 99);
|
||||
SELECT count(*) FROM tenk1
|
||||
WHERE hundred = 42 AND (thousand = 42 OR thousand = 99);
|
||||
|
||||
EXPLAIN (COSTS OFF)
|
||||
SELECT * FROM tenk1
|
||||
WHERE thousand = 42 AND (tenthous = 1 OR tenthous = 3 OR tenthous = 42);
|
||||
SELECT * FROM tenk1
|
||||
WHERE thousand = 42 AND (tenthous = 1 OR tenthous = 3 OR tenthous = 42);
|
||||
|
||||
EXPLAIN (COSTS OFF)
|
||||
SELECT * FROM tenk1
|
||||
WHERE thousand = 42 AND (tenthous = 1::numeric OR tenthous = 3::int4 OR tenthous = 42::numeric);
|
||||
|
||||
EXPLAIN (COSTS OFF)
|
||||
SELECT * FROM tenk1
|
||||
WHERE tenthous = 1::numeric OR tenthous = 3::int4 OR tenthous = 42::numeric;
|
||||
|
||||
EXPLAIN (COSTS OFF)
|
||||
SELECT count(*) FROM tenk1
|
||||
WHERE hundred = 42 AND (thousand = 42 OR thousand = 99);
|
||||
SELECT count(*) FROM tenk1
|
||||
WHERE hundred = 42 AND (thousand = 42 OR thousand = 99);
|
||||
|
||||
EXPLAIN (COSTS OFF)
|
||||
SELECT count(*) FROM tenk1
|
||||
WHERE hundred = 42 AND (thousand < 42 OR thousand < 99 OR 43 > thousand OR 42 > thousand);
|
||||
SELECT count(*) FROM tenk1
|
||||
WHERE hundred = 42 AND (thousand < 42 OR thousand < 99 OR 43 > thousand OR 42 > thousand);
|
||||
|
||||
EXPLAIN (COSTS OFF)
|
||||
SELECT count(*) FROM tenk1
|
||||
WHERE thousand = 42 AND (tenthous = 1 OR tenthous = 3) OR thousand = 41;
|
||||
SELECT count(*) FROM tenk1
|
||||
WHERE thousand = 42 AND (tenthous = 1 OR tenthous = 3) OR thousand = 41;
|
||||
|
||||
EXPLAIN (COSTS OFF)
|
||||
SELECT count(*) FROM tenk1
|
||||
WHERE hundred = 42 AND (thousand = 42 OR thousand = 99 OR tenthous < 2) OR thousand = 41;
|
||||
SELECT count(*) FROM tenk1
|
||||
WHERE hundred = 42 AND (thousand = 42 OR thousand = 99 OR tenthous < 2) OR thousand = 41;
|
||||
|
||||
EXPLAIN (COSTS OFF)
|
||||
SELECT count(*) FROM tenk1
|
||||
WHERE hundred = 42 AND (thousand = 42 OR thousand = 41 OR thousand = 99 AND tenthous = 2);
|
||||
SELECT count(*) FROM tenk1
|
||||
WHERE hundred = 42 AND (thousand = 42 OR thousand = 41 OR thousand = 99 AND tenthous = 2);
|
||||
|
||||
EXPLAIN (COSTS OFF)
|
||||
SELECT count(*) FROM tenk1, tenk2
|
||||
WHERE tenk1.hundred = 42 AND (tenk2.thousand = 42 OR tenk1.thousand = 41 OR tenk2.tenthous = 2) AND
|
||||
tenk2.hundred = tenk1.hundred;
|
||||
|
||||
EXPLAIN (COSTS OFF)
|
||||
SELECT count(*) FROM tenk1, tenk2
|
||||
WHERE tenk1.hundred = 42 AND (tenk2.thousand = 42 OR tenk2.thousand = 41 OR tenk2.tenthous = 2) AND
|
||||
tenk2.hundred = tenk1.hundred;
|
||||
|
||||
EXPLAIN (COSTS OFF)
|
||||
SELECT count(*) FROM tenk1 JOIN tenk2 ON
|
||||
tenk1.hundred = 42 AND (tenk2.thousand = 42 OR tenk2.thousand = 41 OR tenk2.tenthous = 2) AND
|
||||
tenk2.hundred = tenk1.hundred;
|
||||
|
||||
EXPLAIN (COSTS OFF)
|
||||
SELECT count(*) FROM tenk1 LEFT JOIN tenk2 ON
|
||||
tenk1.hundred = 42 AND (tenk2.thousand = 42 OR tenk2.thousand = 41 OR tenk2.tenthous = 2) AND
|
||||
tenk2.hundred = tenk1.hundred;
|
||||
--
|
||||
-- Check behavior with duplicate index column contents
|
||||
--
|
||||
|
||||
@@ -1462,6 +1462,15 @@ select * from tenk1 a join tenk1 b on
|
||||
(a.unique1 = 1 and b.unique1 = 2) or
|
||||
((a.unique2 = 3 or a.unique2 = 7) and b.hundred = 4);
|
||||
|
||||
explain (costs off)
|
||||
select * from tenk1 a join tenk1 b on
|
||||
(a.unique1 = 1 and b.unique1 = 2) or
|
||||
((a.unique2 = 3 or a.unique2 = 7) and b.hundred = 4);
|
||||
explain (costs off)
|
||||
select * from tenk1 a join tenk1 b on
|
||||
(a.unique1 < 20 or a.unique1 = 3 or a.unique1 = 1 and b.unique1 = 2) or
|
||||
((a.unique2 = 3 or a.unique2 = 7) and b.hundred = 4);
|
||||
|
||||
--
|
||||
-- test placement of movable quals in a parameterized join tree
|
||||
--
|
||||
|
||||
@@ -2177,6 +2177,7 @@ CREATE FUNCTION op_leak(int, int) RETURNS bool
|
||||
CREATE OPERATOR <<< (procedure = op_leak, leftarg = int, rightarg = int,
|
||||
restrict = scalarltsel);
|
||||
SELECT * FROM rls_tbl WHERE a <<< 1000;
|
||||
EXPLAIN (COSTS OFF) SELECT * FROM rls_tbl WHERE a <<< 1000 or a <<< 900;
|
||||
DROP OPERATOR <<< (int, int);
|
||||
DROP FUNCTION op_leak(int, int);
|
||||
RESET SESSION AUTHORIZATION;
|
||||
|
||||
@@ -1634,6 +1634,7 @@ CREATE FUNCTION op_leak(int, int) RETURNS bool
|
||||
CREATE OPERATOR <<< (procedure = op_leak, leftarg = int, rightarg = int,
|
||||
restrict = scalarltsel);
|
||||
SELECT * FROM tststats.priv_test_tbl WHERE a <<< 0 AND b <<< 0; -- Permission denied
|
||||
SELECT * FROM tststats.priv_test_tbl WHERE a <<< 0 OR b <<< 0;
|
||||
DELETE FROM tststats.priv_test_tbl WHERE a <<< 0 AND b <<< 0; -- Permission denied
|
||||
|
||||
-- Grant access via a security barrier view, but hide all data
|
||||
@@ -1645,6 +1646,7 @@ GRANT SELECT, DELETE ON tststats.priv_test_view TO regress_stats_user1;
|
||||
-- Should now have access via the view, but see nothing and leak nothing
|
||||
SET SESSION AUTHORIZATION regress_stats_user1;
|
||||
SELECT * FROM tststats.priv_test_view WHERE a <<< 0 AND b <<< 0; -- Should not leak
|
||||
SELECT * FROM tststats.priv_test_view WHERE a <<< 0 OR b <<< 0; -- Should not leak
|
||||
DELETE FROM tststats.priv_test_view WHERE a <<< 0 AND b <<< 0; -- Should not leak
|
||||
|
||||
-- Grant table access, but hide all data with RLS
|
||||
@@ -1655,6 +1657,7 @@ GRANT SELECT, DELETE ON tststats.priv_test_tbl TO regress_stats_user1;
|
||||
-- Should now have direct table access, but see nothing and leak nothing
|
||||
SET SESSION AUTHORIZATION regress_stats_user1;
|
||||
SELECT * FROM tststats.priv_test_tbl WHERE a <<< 0 AND b <<< 0; -- Should not leak
|
||||
SELECT * FROM tststats.priv_test_tbl WHERE a <<< 0 OR b <<< 0;
|
||||
DELETE FROM tststats.priv_test_tbl WHERE a <<< 0 AND b <<< 0; -- Should not leak
|
||||
|
||||
-- privilege checks for pg_stats_ext and pg_stats_ext_exprs
|
||||
|
||||
@@ -63,6 +63,18 @@ CREATE INDEX guid1_hash ON guid1 USING HASH (guid_field);
|
||||
|
||||
-- unique index test
|
||||
CREATE UNIQUE INDEX guid1_unique_BTREE ON guid1 USING BTREE (guid_field);
|
||||
|
||||
EXPLAIN (COSTS OFF)
|
||||
SELECT COUNT(*) FROM guid1 WHERE guid_field <> '11111111111111111111111111111111' OR
|
||||
guid_field <> '3f3e3c3b-3a30-3938-3736-353433a2313e';
|
||||
EXPLAIN (COSTS OFF)
|
||||
SELECT COUNT(*) FROM guid1 WHERE guid_field <= '22222222-2222-2222-2222-222222222222' OR
|
||||
guid_field <= '11111111111111111111111111111111' OR
|
||||
guid_field <= '3f3e3c3b-3a30-3938-3736-353433a2313e';
|
||||
EXPLAIN (COSTS OFF)
|
||||
SELECT COUNT(*) FROM guid1 WHERE guid_field = '3f3e3c3b-3a30-3938-3736-353433a2313e' OR
|
||||
guid_field = '11111111111111111111111111111111';
|
||||
|
||||
-- should fail
|
||||
INSERT INTO guid1(guid_field) VALUES('11111111-1111-1111-1111-111111111111');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user