1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-28 23:42:10 +03:00

Suppress Append and MergeAppend plan nodes that have a single child.

If there's only one child relation, the Append or MergeAppend isn't
doing anything useful, and can be elided.  It does have a purpose
during planning though, which is to serve as a buffer between parent
and child Var numbering.  Therefore we keep it all the way through
to setrefs.c, and get rid of it only after fixing references in the
plan level(s) above it.  This works largely the same as setrefs.c's
ancient hack to get rid of no-op SubqueryScan nodes, and can even
share some code with that.

Note the change to make setrefs.c use apply_tlist_labeling rather than
ad-hoc code.  This has the effect of propagating the child's resjunk
and ressortgroupref labels, which formerly weren't propagated when
removing a SubqueryScan.  Doing that is demonstrably necessary for
the [Merge]Append cases, and seems harmless for SubqueryScan, if only
because trivial_subqueryscan is afraid to collapse cases where the
resjunk marking differs.  (I suspect that restriction could now be
removed, though it's unclear that it'd make any new matches possible,
since the outer query can't have references to a child resjunk column.)

David Rowley, reviewed by Alvaro Herrera and Tomas Vondra

Discussion: https://postgr.es/m/CAKJS1f_7u8ATyJ1JGTMHFoKDvZdeF-iEBhs+sM_SXowOr9cArg@mail.gmail.com
This commit is contained in:
Tom Lane
2019-03-25 15:42:35 -04:00
parent f21668f328
commit 8edd0e7946
12 changed files with 598 additions and 496 deletions

View File

@ -1770,12 +1770,11 @@ explain (costs off) select * from list_parted;
(4 rows)
explain (costs off) select * from list_parted where a is null;
QUERY PLAN
--------------------------------
Append
-> Seq Scan on part_null_xy
Filter: (a IS NULL)
(3 rows)
QUERY PLAN
--------------------------
Seq Scan on part_null_xy
Filter: (a IS NULL)
(2 rows)
explain (costs off) select * from list_parted where a is not null;
QUERY PLAN
@ -1800,20 +1799,18 @@ explain (costs off) select * from list_parted where a in ('ab', 'cd', 'ef');
(5 rows)
explain (costs off) select * from list_parted where a = 'ab' or a in (null, 'cd');
QUERY PLAN
---------------------------------------------------------------------------------------
Append
-> Seq Scan on part_ab_cd
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
(3 rows)
QUERY PLAN
---------------------------------------------------------------------------------
Seq Scan on part_ab_cd
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
(2 rows)
explain (costs off) select * from list_parted where a = 'ab';
QUERY PLAN
------------------------------------------
Append
-> Seq Scan on part_ab_cd
Filter: ((a)::text = 'ab'::text)
(3 rows)
QUERY PLAN
------------------------------------
Seq Scan on part_ab_cd
Filter: ((a)::text = 'ab'::text)
(2 rows)
create table range_list_parted (
a int,
@ -1893,12 +1890,11 @@ explain (costs off) select * from range_list_parted where a is null;
/* Should only select rows from the null-accepting partition */
explain (costs off) select * from range_list_parted where b is null;
QUERY PLAN
------------------------------------
Append
-> Seq Scan on part_40_inf_null
Filter: (b IS NULL)
(3 rows)
QUERY PLAN
------------------------------
Seq Scan on part_40_inf_null
Filter: (b IS NULL)
(2 rows)
explain (costs off) select * from range_list_parted where a is not null and a < 67;
QUERY PLAN
@ -2021,12 +2017,11 @@ explain (costs off) select * from mcrparted where a > -1; -- scans all partition
(15 rows)
explain (costs off) select * from mcrparted where a = 20 and abs(b) = 10 and c > 10; -- scans mcrparted4
QUERY PLAN
-----------------------------------------------------------
Append
-> Seq Scan on mcrparted4
Filter: ((c > 10) AND (a = 20) AND (abs(b) = 10))
(3 rows)
QUERY PLAN
-----------------------------------------------------
Seq Scan on mcrparted4
Filter: ((c > 10) AND (a = 20) AND (abs(b) = 10))
(2 rows)
explain (costs off) select * from mcrparted where a = 20 and c > 20; -- scans mcrparted3, mcrparte4, mcrparte5, mcrparted_def
QUERY PLAN
@ -2050,22 +2045,18 @@ create table parted_minmax1 partition of parted_minmax for values from (1) to (1
create index parted_minmax1i on parted_minmax1 (a, b);
insert into parted_minmax values (1,'12345');
explain (costs off) select min(a), max(a) from parted_minmax where b = '12345';
QUERY PLAN
-------------------------------------------------------------------------------------------------------
QUERY PLAN
-------------------------------------------------------------------------------------------------
Result
InitPlan 1 (returns $0)
-> Limit
-> Merge Append
Sort Key: parted_minmax1.a
-> Index Only Scan using parted_minmax1i on parted_minmax1
Index Cond: ((a IS NOT NULL) AND (b = '12345'::text))
-> Index Only Scan using parted_minmax1i on parted_minmax1
Index Cond: ((a IS NOT NULL) AND (b = '12345'::text))
InitPlan 2 (returns $1)
-> Limit
-> Merge Append
Sort Key: parted_minmax1_1.a DESC
-> Index Only Scan Backward using parted_minmax1i on parted_minmax1 parted_minmax1_1
Index Cond: ((a IS NOT NULL) AND (b = '12345'::text))
(13 rows)
-> Index Only Scan Backward using parted_minmax1i on parted_minmax1 parted_minmax1_1
Index Cond: ((a IS NOT NULL) AND (b = '12345'::text))
(9 rows)
select min(a), max(a) from parted_minmax where b = '12345';
min | max

View File

@ -186,19 +186,18 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT 50 phv, * FROM prt1 WHERE prt1.b = 0)
-- Join with pruned partitions from joining relations
EXPLAIN (COSTS OFF)
SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.a < 450 AND t2.b > 250 AND t1.b = 0 ORDER BY t1.a, t2.b;
QUERY PLAN
-----------------------------------------------------------
QUERY PLAN
-----------------------------------------------------
Sort
Sort Key: t1.a
-> Append
-> Hash Join
Hash Cond: (t2.b = t1.a)
-> Seq Scan on prt2_p2 t2
Filter: (b > 250)
-> Hash
-> Seq Scan on prt1_p2 t1
Filter: ((a < 450) AND (b = 0))
(10 rows)
-> Hash Join
Hash Cond: (t2.b = t1.a)
-> Seq Scan on prt2_p2 t2
Filter: (b > 250)
-> Hash
-> Seq Scan on prt1_p2 t1
Filter: ((a < 450) AND (b = 0))
(9 rows)
SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.a < 450 AND t2.b > 250 AND t1.b = 0 ORDER BY t1.a, t2.b;
a | c | b | c
@ -1480,10 +1479,9 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1, prt2_l t2 WHERE t1.a = t2.b AND t1
-> Seq Scan on prt2_l_p3_p1 t2_3
-> Seq Scan on prt2_l_p3_p2 t2_4
-> Hash
-> Append
-> Seq Scan on prt1_l_p3_p1 t1_3
Filter: (b = 0)
(29 rows)
-> Seq Scan on prt1_l_p3_p1 t1_3
Filter: (b = 0)
(28 rows)
SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1, prt2_l t2 WHERE t1.a = t2.b AND t1.b = 0 ORDER BY t1.a, t2.b;
a | c | b | c
@ -1526,10 +1524,9 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1 LEFT JOIN prt2_l t2 ON t1.a = t2.b
-> Seq Scan on prt2_l_p3_p1 t2_3
-> Seq Scan on prt2_l_p3_p2 t2_4
-> Hash
-> Append
-> Seq Scan on prt1_l_p3_p1 t1_3
Filter: (b = 0)
(30 rows)
-> Seq Scan on prt1_l_p3_p1 t1_3
Filter: (b = 0)
(29 rows)
SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1 LEFT JOIN prt2_l t2 ON t1.a = t2.b AND t1.c = t2.c WHERE t1.b = 0 ORDER BY t1.a, t2.b;
a | c | b | c
@ -1580,10 +1577,9 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1 RIGHT JOIN prt2_l t2 ON t1.a = t2.b
-> Seq Scan on prt1_l_p3_p1 t1_3
-> Seq Scan on prt1_l_p3_p2 t1_4
-> Hash
-> Append
-> Seq Scan on prt2_l_p3_p1 t2_3
Filter: (a = 0)
(30 rows)
-> Seq Scan on prt2_l_p3_p1 t2_3
Filter: (a = 0)
(29 rows)
SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_l t1 RIGHT JOIN prt2_l t2 ON t1.a = t2.b AND t1.c = t2.c WHERE t2.a = 0 ORDER BY t1.a, t2.b;
a | c | b | c
@ -1629,14 +1625,12 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1_l WHERE prt1_l.b = 0) t1
Filter: (a = 0)
-> Hash Full Join
Hash Cond: ((prt1_l_p3_p1.a = prt2_l_p3_p1.b) AND ((prt1_l_p3_p1.c)::text = (prt2_l_p3_p1.c)::text))
-> Append
-> Seq Scan on prt1_l_p3_p1
Filter: (b = 0)
-> Seq Scan on prt1_l_p3_p1
Filter: (b = 0)
-> Hash
-> Append
-> Seq Scan on prt2_l_p3_p1
Filter: (a = 0)
(33 rows)
-> Seq Scan on prt2_l_p3_p1
Filter: (a = 0)
(31 rows)
SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1_l WHERE prt1_l.b = 0) t1 FULL JOIN (SELECT * FROM prt2_l WHERE prt2_l.a = 0) t2 ON (t1.a = t2.b AND t1.c = t2.c) ORDER BY t1.a, t2.b;
a | c | b | c
@ -1697,9 +1691,8 @@ SELECT * FROM prt1_l t1 LEFT JOIN LATERAL
-> Seq Scan on prt1_l_p2_p2 t2_2
Filter: ((t1_2.a = a) AND ((t1_2.c)::text = (c)::text))
-> Nested Loop Left Join
-> Append
-> Seq Scan on prt1_l_p3_p1 t1_3
Filter: (b = 0)
-> Seq Scan on prt1_l_p3_p1 t1_3
Filter: (b = 0)
-> Hash Join
Hash Cond: ((t3_3.b = t2_3.a) AND ((t3_3.c)::text = (t2_3.c)::text))
-> Append
@ -1711,7 +1704,7 @@ SELECT * FROM prt1_l t1 LEFT JOIN LATERAL
Filter: ((t1_3.a = a) AND ((t1_3.c)::text = (c)::text))
-> Seq Scan on prt1_l_p3_p2 t2_4
Filter: ((t1_3.a = a) AND ((t1_3.c)::text = (c)::text))
(45 rows)
(44 rows)
SELECT * FROM prt1_l t1 LEFT JOIN LATERAL
(SELECT t2.a AS t2a, t2.c AS t2c, t2.b AS t2b, t3.b AS t3b, least(t1.a,t2.a,t3.b) FROM prt1_l t2 JOIN prt2_l t3 ON (t2.a = t3.b AND t2.c = t3.c)) ss

View File

@ -43,20 +43,18 @@ explain (costs off) select * from lp where a > 'a' and a <= 'd';
(7 rows)
explain (costs off) select * from lp where a = 'a';
QUERY PLAN
-----------------------------------
Append
-> Seq Scan on lp_ad
Filter: (a = 'a'::bpchar)
(3 rows)
QUERY PLAN
-----------------------------
Seq Scan on lp_ad
Filter: (a = 'a'::bpchar)
(2 rows)
explain (costs off) select * from lp where 'a' = a; /* commuted */
QUERY PLAN
-----------------------------------
Append
-> Seq Scan on lp_ad
Filter: ('a'::bpchar = a)
(3 rows)
QUERY PLAN
-----------------------------
Seq Scan on lp_ad
Filter: ('a'::bpchar = a)
(2 rows)
explain (costs off) select * from lp where a is not null;
QUERY PLAN
@ -75,12 +73,11 @@ explain (costs off) select * from lp where a is not null;
(11 rows)
explain (costs off) select * from lp where a is null;
QUERY PLAN
-----------------------------
Append
-> Seq Scan on lp_null
Filter: (a IS NULL)
(3 rows)
QUERY PLAN
-----------------------
Seq Scan on lp_null
Filter: (a IS NULL)
(2 rows)
explain (costs off) select * from lp where a = 'a' or a = 'c';
QUERY PLAN
@ -150,12 +147,11 @@ create table coll_pruning_a partition of coll_pruning for values in ('a');
create table coll_pruning_b partition of coll_pruning for values in ('b');
create table coll_pruning_def partition of coll_pruning default;
explain (costs off) select * from coll_pruning where a collate "C" = 'a' collate "C";
QUERY PLAN
---------------------------------------------
Append
-> Seq Scan on coll_pruning_a
Filter: (a = 'a'::text COLLATE "C")
(3 rows)
QUERY PLAN
---------------------------------------
Seq Scan on coll_pruning_a
Filter: (a = 'a'::text COLLATE "C")
(2 rows)
-- collation doesn't match the partitioning collation, no pruning occurs
explain (costs off) select * from coll_pruning where a collate "POSIX" = 'a' collate "POSIX";
@ -192,20 +188,18 @@ create table rlp5 partition of rlp for values from (31) to (maxvalue) partition
create table rlp5_default partition of rlp5 default;
create table rlp5_1 partition of rlp5 for values from (31) to (40);
explain (costs off) select * from rlp where a < 1;
QUERY PLAN
-------------------------
Append
-> Seq Scan on rlp1
Filter: (a < 1)
(3 rows)
QUERY PLAN
-------------------
Seq Scan on rlp1
Filter: (a < 1)
(2 rows)
explain (costs off) select * from rlp where 1 > a; /* commuted */
QUERY PLAN
-------------------------
Append
-> Seq Scan on rlp1
Filter: (1 > a)
(3 rows)
QUERY PLAN
-------------------
Seq Scan on rlp1
Filter: (1 > a)
(2 rows)
explain (costs off) select * from rlp where a <= 1;
QUERY PLAN
@ -218,20 +212,18 @@ explain (costs off) select * from rlp where a <= 1;
(5 rows)
explain (costs off) select * from rlp where a = 1;
QUERY PLAN
-------------------------
Append
-> Seq Scan on rlp2
Filter: (a = 1)
(3 rows)
QUERY PLAN
-------------------
Seq Scan on rlp2
Filter: (a = 1)
(2 rows)
explain (costs off) select * from rlp where a = 1::bigint; /* same as above */
QUERY PLAN
-----------------------------------
Append
-> Seq Scan on rlp2
Filter: (a = '1'::bigint)
(3 rows)
QUERY PLAN
-----------------------------
Seq Scan on rlp2
Filter: (a = '1'::bigint)
(2 rows)
explain (costs off) select * from rlp where a = 1::numeric; /* no pruning */
QUERY PLAN
@ -384,20 +376,18 @@ explain (costs off) select * from rlp where a = 16;
(9 rows)
explain (costs off) select * from rlp where a = 16 and b in ('not', 'in', 'here');
QUERY PLAN
----------------------------------------------------------------------------
Append
-> Seq Scan on rlp3_default
Filter: ((a = 16) AND ((b)::text = ANY ('{not,in,here}'::text[])))
(3 rows)
QUERY PLAN
----------------------------------------------------------------------
Seq Scan on rlp3_default
Filter: ((a = 16) AND ((b)::text = ANY ('{not,in,here}'::text[])))
(2 rows)
explain (costs off) select * from rlp where a = 16 and b < 'ab';
QUERY PLAN
---------------------------------------------------------
Append
-> Seq Scan on rlp3_default
Filter: (((b)::text < 'ab'::text) AND (a = 16))
(3 rows)
QUERY PLAN
---------------------------------------------------
Seq Scan on rlp3_default
Filter: (((b)::text < 'ab'::text) AND (a = 16))
(2 rows)
explain (costs off) select * from rlp where a = 16 and b <= 'ab';
QUERY PLAN
@ -410,12 +400,11 @@ explain (costs off) select * from rlp where a = 16 and b <= 'ab';
(5 rows)
explain (costs off) select * from rlp where a = 16 and b is null;
QUERY PLAN
--------------------------------------------
Append
-> Seq Scan on rlp3nullxy
Filter: ((b IS NULL) AND (a = 16))
(3 rows)
QUERY PLAN
--------------------------------------
Seq Scan on rlp3nullxy
Filter: ((b IS NULL) AND (a = 16))
(2 rows)
explain (costs off) select * from rlp where a = 16 and b is not null;
QUERY PLAN
@ -432,12 +421,11 @@ explain (costs off) select * from rlp where a = 16 and b is not null;
(9 rows)
explain (costs off) select * from rlp where a is null;
QUERY PLAN
------------------------------------
Append
-> Seq Scan on rlp_default_null
Filter: (a IS NULL)
(3 rows)
QUERY PLAN
------------------------------
Seq Scan on rlp_default_null
Filter: (a IS NULL)
(2 rows)
explain (costs off) select * from rlp where a is not null;
QUERY PLAN
@ -486,12 +474,11 @@ explain (costs off) select * from rlp where a > 30;
(7 rows)
explain (costs off) select * from rlp where a = 30; /* only default is scanned */
QUERY PLAN
----------------------------------
Append
-> Seq Scan on rlp_default_30
Filter: (a = 30)
(3 rows)
QUERY PLAN
----------------------------
Seq Scan on rlp_default_30
Filter: (a = 30)
(2 rows)
explain (costs off) select * from rlp where a <= 31;
QUERY PLAN
@ -528,12 +515,11 @@ explain (costs off) select * from rlp where a <= 31;
(29 rows)
explain (costs off) select * from rlp where a = 1 or a = 7;
QUERY PLAN
--------------------------------------
Append
-> Seq Scan on rlp2
Filter: ((a = 1) OR (a = 7))
(3 rows)
QUERY PLAN
--------------------------------
Seq Scan on rlp2
Filter: ((a = 1) OR (a = 7))
(2 rows)
explain (costs off) select * from rlp where a = 1 or b = 'ab';
QUERY PLAN
@ -580,12 +566,11 @@ explain (costs off) select * from rlp where a > 20 and a < 27;
(9 rows)
explain (costs off) select * from rlp where a = 29;
QUERY PLAN
--------------------------------
Append
-> Seq Scan on rlp4_default
Filter: (a = 29)
(3 rows)
QUERY PLAN
--------------------------
Seq Scan on rlp4_default
Filter: (a = 29)
(2 rows)
explain (costs off) select * from rlp where a >= 29;
QUERY PLAN
@ -605,12 +590,11 @@ explain (costs off) select * from rlp where a >= 29;
-- redundant clauses are eliminated
explain (costs off) select * from rlp where a > 1 and a = 10; /* only default */
QUERY PLAN
----------------------------------------
Append
-> Seq Scan on rlp_default_10
Filter: ((a > 1) AND (a = 10))
(3 rows)
QUERY PLAN
----------------------------------
Seq Scan on rlp_default_10
Filter: ((a > 1) AND (a = 10))
(2 rows)
explain (costs off) select * from rlp where a > 1 and a >=15; /* rlp3 onwards, including default */
QUERY PLAN
@ -797,20 +781,18 @@ explain (costs off) select * from mc3p where a <= 10 and abs(b) < 10;
(9 rows)
explain (costs off) select * from mc3p where a = 11 and abs(b) = 0;
QUERY PLAN
---------------------------------------------
Append
-> Seq Scan on mc3p_default
Filter: ((a = 11) AND (abs(b) = 0))
(3 rows)
QUERY PLAN
---------------------------------------
Seq Scan on mc3p_default
Filter: ((a = 11) AND (abs(b) = 0))
(2 rows)
explain (costs off) select * from mc3p where a = 20 and abs(b) = 10 and c = 100;
QUERY PLAN
------------------------------------------------------------
Append
-> Seq Scan on mc3p6
Filter: ((a = 20) AND (c = 100) AND (abs(b) = 10))
(3 rows)
QUERY PLAN
------------------------------------------------------
Seq Scan on mc3p6
Filter: ((a = 20) AND (c = 100) AND (abs(b) = 10))
(2 rows)
explain (costs off) select * from mc3p where a > 20;
QUERY PLAN
@ -962,12 +944,11 @@ explain (costs off) select * from mc2p where a < 2;
(9 rows)
explain (costs off) select * from mc2p where a = 2 and b < 1;
QUERY PLAN
---------------------------------------
Append
-> Seq Scan on mc2p3
Filter: ((b < 1) AND (a = 2))
(3 rows)
QUERY PLAN
---------------------------------
Seq Scan on mc2p3
Filter: ((b < 1) AND (a = 2))
(2 rows)
explain (costs off) select * from mc2p where a > 1;
QUERY PLAN
@ -986,53 +967,47 @@ explain (costs off) select * from mc2p where a > 1;
(11 rows)
explain (costs off) select * from mc2p where a = 1 and b > 1;
QUERY PLAN
---------------------------------------
Append
-> Seq Scan on mc2p2
Filter: ((b > 1) AND (a = 1))
(3 rows)
QUERY PLAN
---------------------------------
Seq Scan on mc2p2
Filter: ((b > 1) AND (a = 1))
(2 rows)
-- all partitions but the default one should be pruned
explain (costs off) select * from mc2p where a = 1 and b is null;
QUERY PLAN
-------------------------------------------
Append
-> Seq Scan on mc2p_default
Filter: ((b IS NULL) AND (a = 1))
(3 rows)
QUERY PLAN
-------------------------------------
Seq Scan on mc2p_default
Filter: ((b IS NULL) AND (a = 1))
(2 rows)
explain (costs off) select * from mc2p where a is null and b is null;
QUERY PLAN
-----------------------------------------------
Append
-> Seq Scan on mc2p_default
Filter: ((a IS NULL) AND (b IS NULL))
(3 rows)
QUERY PLAN
-----------------------------------------
Seq Scan on mc2p_default
Filter: ((a IS NULL) AND (b IS NULL))
(2 rows)
explain (costs off) select * from mc2p where a is null and b = 1;
QUERY PLAN
-------------------------------------------
Append
-> Seq Scan on mc2p_default
Filter: ((a IS NULL) AND (b = 1))
(3 rows)
QUERY PLAN
-------------------------------------
Seq Scan on mc2p_default
Filter: ((a IS NULL) AND (b = 1))
(2 rows)
explain (costs off) select * from mc2p where a is null;
QUERY PLAN
--------------------------------
Append
-> Seq Scan on mc2p_default
Filter: (a IS NULL)
(3 rows)
QUERY PLAN
--------------------------
Seq Scan on mc2p_default
Filter: (a IS NULL)
(2 rows)
explain (costs off) select * from mc2p where b is null;
QUERY PLAN
--------------------------------
Append
-> Seq Scan on mc2p_default
Filter: (b IS NULL)
(3 rows)
QUERY PLAN
--------------------------
Seq Scan on mc2p_default
Filter: (b IS NULL)
(2 rows)
-- boolean partitioning
create table boolpart (a bool) partition by list (a);
@ -1050,20 +1025,18 @@ explain (costs off) select * from boolpart where a in (true, false);
(5 rows)
explain (costs off) select * from boolpart where a = false;
QUERY PLAN
------------------------------
Append
-> Seq Scan on boolpart_f
Filter: (NOT a)
(3 rows)
QUERY PLAN
------------------------
Seq Scan on boolpart_f
Filter: (NOT a)
(2 rows)
explain (costs off) select * from boolpart where not a = false;
QUERY PLAN
------------------------------
Append
-> Seq Scan on boolpart_t
Filter: a
(3 rows)
QUERY PLAN
------------------------
Seq Scan on boolpart_t
Filter: a
(2 rows)
explain (costs off) select * from boolpart where a is true or a is not true;
QUERY PLAN
@ -1076,12 +1049,11 @@ explain (costs off) select * from boolpart where a is true or a is not true;
(5 rows)
explain (costs off) select * from boolpart where a is not true;
QUERY PLAN
---------------------------------
Append
-> Seq Scan on boolpart_f
Filter: (a IS NOT TRUE)
(3 rows)
QUERY PLAN
---------------------------
Seq Scan on boolpart_f
Filter: (a IS NOT TRUE)
(2 rows)
explain (costs off) select * from boolpart where a is not true and a is not false;
QUERY PLAN
@ -1190,10 +1162,9 @@ EXPLAIN (COSTS OFF) SELECT tableoid::regclass as part, a, b FROM part WHERE a IS
---------------------------------------------------------------------------
Sort
Sort Key: ((part_p2_p1.tableoid)::regclass), part_p2_p1.a, part_p2_p1.b
-> Append
-> Seq Scan on part_p2_p1
Filter: (a IS NULL)
(5 rows)
-> Seq Scan on part_p2_p1
Filter: (a IS NULL)
(4 rows)
--
-- some more cases
@ -1260,13 +1231,12 @@ explain (costs off) select * from mc2p t1, lateral (select count(*) from mc3p t2
-- also here, because values for all keys are provided
explain (costs off) select * from mc2p t1, lateral (select count(*) from mc3p t2 where t2.a = 1 and abs(t2.b) = 1 and t2.c = 1) s where t1.a = 1;
QUERY PLAN
--------------------------------------------------------------------
QUERY PLAN
--------------------------------------------------------------
Nested Loop
-> Aggregate
-> Append
-> Seq Scan on mc3p1 t2
Filter: ((a = 1) AND (c = 1) AND (abs(b) = 1))
-> Seq Scan on mc3p1 t2
Filter: ((a = 1) AND (c = 1) AND (abs(b) = 1))
-> Append
-> Seq Scan on mc2p1 t1
Filter: (a = 1)
@ -1274,7 +1244,7 @@ explain (costs off) select * from mc2p t1, lateral (select count(*) from mc3p t2
Filter: (a = 1)
-> Seq Scan on mc2p_default t1_2
Filter: (a = 1)
(12 rows)
(11 rows)
--
-- pruning with clauses containing <> operator
@ -1395,12 +1365,11 @@ explain (costs off) select * from coll_pruning_multi where substr(a, 1) = 'a' co
-- pruning, with values provided for both keys
explain (costs off) select * from coll_pruning_multi where substr(a, 1) = 'e' collate "C" and substr(a, 1) = 'a' collate "POSIX";
QUERY PLAN
---------------------------------------------------------------------------------------------------------
Append
-> Seq Scan on coll_pruning_multi2
Filter: ((substr(a, 1) = 'e'::text COLLATE "C") AND (substr(a, 1) = 'a'::text COLLATE "POSIX"))
(3 rows)
QUERY PLAN
---------------------------------------------------------------------------------------------------
Seq Scan on coll_pruning_multi2
Filter: ((substr(a, 1) = 'e'::text COLLATE "C") AND (substr(a, 1) = 'a'::text COLLATE "POSIX"))
(2 rows)
--
-- LIKE operators don't prune
@ -1445,12 +1414,11 @@ explain (costs off) select * from rparted_by_int2 where a > 100000000000000;
create table rparted_by_int2_maxvalue partition of rparted_by_int2 for values from (16384) to (maxvalue);
-- all partitions but rparted_by_int2_maxvalue pruned
explain (costs off) select * from rparted_by_int2 where a > 100000000000000;
QUERY PLAN
-------------------------------------------------
Append
-> Seq Scan on rparted_by_int2_maxvalue
Filter: (a > '100000000000000'::bigint)
(3 rows)
QUERY PLAN
-------------------------------------------
Seq Scan on rparted_by_int2_maxvalue
Filter: (a > '100000000000000'::bigint)
(2 rows)
drop table lp, coll_pruning, rlp, mc3p, mc2p, boolpart, rp, coll_pruning_multi, like_op_noprune, lparted_by_int2, rparted_by_int2;
--
@ -1584,52 +1552,46 @@ explain (costs off) select * from hp where a <> 1 and b <> 'xxx';
-- pruning should work if either a value or a IS NULL clause is provided for
-- each of the keys
explain (costs off) select * from hp where a is null and b is null;
QUERY PLAN
-----------------------------------------------
Append
-> Seq Scan on hp0
Filter: ((a IS NULL) AND (b IS NULL))
(3 rows)
QUERY PLAN
-----------------------------------------
Seq Scan on hp0
Filter: ((a IS NULL) AND (b IS NULL))
(2 rows)
explain (costs off) select * from hp where a = 1 and b is null;
QUERY PLAN
-------------------------------------------
Append
-> Seq Scan on hp1
Filter: ((b IS NULL) AND (a = 1))
(3 rows)
QUERY PLAN
-------------------------------------
Seq Scan on hp1
Filter: ((b IS NULL) AND (a = 1))
(2 rows)
explain (costs off) select * from hp where a = 1 and b = 'xxx';
QUERY PLAN
-------------------------------------------------
Append
-> Seq Scan on hp0
Filter: ((a = 1) AND (b = 'xxx'::text))
(3 rows)
QUERY PLAN
-------------------------------------------
Seq Scan on hp0
Filter: ((a = 1) AND (b = 'xxx'::text))
(2 rows)
explain (costs off) select * from hp where a is null and b = 'xxx';
QUERY PLAN
-----------------------------------------------------
Append
-> Seq Scan on hp2
Filter: ((a IS NULL) AND (b = 'xxx'::text))
(3 rows)
QUERY PLAN
-----------------------------------------------
Seq Scan on hp2
Filter: ((a IS NULL) AND (b = 'xxx'::text))
(2 rows)
explain (costs off) select * from hp where a = 2 and b = 'xxx';
QUERY PLAN
-------------------------------------------------
Append
-> Seq Scan on hp3
Filter: ((a = 2) AND (b = 'xxx'::text))
(3 rows)
QUERY PLAN
-------------------------------------------
Seq Scan on hp3
Filter: ((a = 2) AND (b = 'xxx'::text))
(2 rows)
explain (costs off) select * from hp where a = 1 and b = 'abcde';
QUERY PLAN
---------------------------------------------------
Append
-> Seq Scan on hp2
Filter: ((a = 1) AND (b = 'abcde'::text))
(3 rows)
QUERY PLAN
---------------------------------------------
Seq Scan on hp2
Filter: ((a = 1) AND (b = 'abcde'::text))
(2 rows)
explain (costs off) select * from hp where (a = 1 and b = 'abcde') or (a = 2 and b = 'xxx') or (a is null and b is null);
QUERY PLAN
@ -2878,12 +2840,11 @@ execute part_abc_q1 (1, 2, 3);
-- Single partition should be scanned.
explain (analyze, costs off, summary off, timing off) execute part_abc_q1 (1, 2, 3);
QUERY PLAN
-------------------------------------------------------
Append (actual rows=0 loops=1)
-> Seq Scan on part_abc_p1 (actual rows=0 loops=1)
Filter: ((a = $1) AND (b = $2) AND (c = $3))
(3 rows)
QUERY PLAN
-------------------------------------------------
Seq Scan on part_abc_p1 (actual rows=0 loops=1)
Filter: ((a = $1) AND (b = $2) AND (c = $3))
(2 rows)
deallocate part_abc_q1;
drop table part_abc;
@ -3205,12 +3166,11 @@ create table pp_arrpart (a int[]) partition by list (a);
create table pp_arrpart1 partition of pp_arrpart for values in ('{1}');
create table pp_arrpart2 partition of pp_arrpart for values in ('{2, 3}', '{4, 5}');
explain (costs off) select * from pp_arrpart where a = '{1}';
QUERY PLAN
----------------------------------------
Append
-> Seq Scan on pp_arrpart1
Filter: (a = '{1}'::integer[])
(3 rows)
QUERY PLAN
----------------------------------
Seq Scan on pp_arrpart1
Filter: (a = '{1}'::integer[])
(2 rows)
explain (costs off) select * from pp_arrpart where a = '{1, 2}';
QUERY PLAN
@ -3262,20 +3222,18 @@ select tableoid::regclass, * from pph_arrpart order by 1;
(3 rows)
explain (costs off) select * from pph_arrpart where a = '{1}';
QUERY PLAN
----------------------------------------
Append
-> Seq Scan on pph_arrpart2
Filter: (a = '{1}'::integer[])
(3 rows)
QUERY PLAN
----------------------------------
Seq Scan on pph_arrpart2
Filter: (a = '{1}'::integer[])
(2 rows)
explain (costs off) select * from pph_arrpart where a = '{1, 2}';
QUERY PLAN
------------------------------------------
Append
-> Seq Scan on pph_arrpart1
Filter: (a = '{1,2}'::integer[])
(3 rows)
QUERY PLAN
------------------------------------
Seq Scan on pph_arrpart1
Filter: (a = '{1,2}'::integer[])
(2 rows)
explain (costs off) select * from pph_arrpart where a in ('{4, 5}', '{1}');
QUERY PLAN
@ -3294,12 +3252,11 @@ create table pp_enumpart (a pp_colors) partition by list (a);
create table pp_enumpart_green partition of pp_enumpart for values in ('green');
create table pp_enumpart_blue partition of pp_enumpart for values in ('blue');
explain (costs off) select * from pp_enumpart where a = 'blue';
QUERY PLAN
-----------------------------------------
Append
-> Seq Scan on pp_enumpart_blue
Filter: (a = 'blue'::pp_colors)
(3 rows)
QUERY PLAN
-----------------------------------
Seq Scan on pp_enumpart_blue
Filter: (a = 'blue'::pp_colors)
(2 rows)
explain (costs off) select * from pp_enumpart where a = 'black';
QUERY PLAN
@ -3316,12 +3273,11 @@ create table pp_recpart (a pp_rectype) partition by list (a);
create table pp_recpart_11 partition of pp_recpart for values in ('(1,1)');
create table pp_recpart_23 partition of pp_recpart for values in ('(2,3)');
explain (costs off) select * from pp_recpart where a = '(1,1)'::pp_rectype;
QUERY PLAN
-------------------------------------------
Append
-> Seq Scan on pp_recpart_11
Filter: (a = '(1,1)'::pp_rectype)
(3 rows)
QUERY PLAN
-------------------------------------
Seq Scan on pp_recpart_11
Filter: (a = '(1,1)'::pp_rectype)
(2 rows)
explain (costs off) select * from pp_recpart where a = '(1,2)'::pp_rectype;
QUERY PLAN
@ -3337,12 +3293,11 @@ create table pp_intrangepart (a int4range) partition by list (a);
create table pp_intrangepart12 partition of pp_intrangepart for values in ('[1,2]');
create table pp_intrangepart2inf partition of pp_intrangepart for values in ('[2,)');
explain (costs off) select * from pp_intrangepart where a = '[1,2]'::int4range;
QUERY PLAN
------------------------------------------
Append
-> Seq Scan on pp_intrangepart12
Filter: (a = '[1,3)'::int4range)
(3 rows)
QUERY PLAN
------------------------------------
Seq Scan on pp_intrangepart12
Filter: (a = '[1,3)'::int4range)
(2 rows)
explain (costs off) select * from pp_intrangepart where a = '(1,2)'::int4range;
QUERY PLAN
@ -3359,12 +3314,11 @@ create table pp_lp (a int, value int) partition by list (a);
create table pp_lp1 partition of pp_lp for values in(1);
create table pp_lp2 partition of pp_lp for values in(2);
explain (costs off) select * from pp_lp where a = 1;
QUERY PLAN
--------------------------
Append
-> Seq Scan on pp_lp1
Filter: (a = 1)
(3 rows)
QUERY PLAN
--------------------
Seq Scan on pp_lp1
Filter: (a = 1)
(2 rows)
explain (costs off) update pp_lp set value = 10 where a = 1;
QUERY PLAN
@ -3529,12 +3483,11 @@ explain (costs off) select * from pp_temp_parent where true;
(3 rows)
explain (costs off) select * from pp_temp_parent where a = 2;
QUERY PLAN
------------------------------------
Append
-> Seq Scan on pp_temp_part_def
Filter: (a = 2)
(3 rows)
QUERY PLAN
------------------------------
Seq Scan on pp_temp_part_def
Filter: (a = 2)
(2 rows)
drop table pp_temp_parent;
-- Stress run-time partition pruning a bit more, per bug reports
@ -3628,13 +3581,12 @@ create table listp2 partition of listp for values in(2) partition by list(b);
create table listp2_10 partition of listp2 for values in (10);
explain (analyze, costs off, summary off, timing off)
select * from listp where a = (select 2) and b <> 10;
QUERY PLAN
-------------------------------------------
Append (actual rows=0 loops=1)
QUERY PLAN
--------------------------------------------
Seq Scan on listp1 (actual rows=0 loops=1)
Filter: ((b <> 10) AND (a = $0))
InitPlan 1 (returns $0)
-> Result (actual rows=1 loops=1)
-> Seq Scan on listp1 (never executed)
Filter: ((b <> 10) AND (a = $0))
(5 rows)
-> Result (never executed)
(4 rows)
drop table listp;

View File

@ -1057,15 +1057,14 @@ NOTICE: f_leak => awesome science fiction
(4 rows)
EXPLAIN (COSTS OFF) SELECT * FROM part_document WHERE f_leak(dtitle);
QUERY PLAN
--------------------------------------------------------------------
Append
QUERY PLAN
--------------------------------------------------------------
Seq Scan on part_document_fiction
Filter: ((cid < 55) AND (dlevel <= $0) AND f_leak(dtitle))
InitPlan 1 (returns $0)
-> Index Scan using uaccount_pkey on uaccount
Index Cond: (pguser = CURRENT_USER)
-> Seq Scan on part_document_fiction
Filter: ((cid < 55) AND (dlevel <= $0) AND f_leak(dtitle))
(6 rows)
(5 rows)
-- pp1 ERROR
INSERT INTO part_document VALUES (100, 11, 5, 'regress_rls_dave', 'testing pp1'); -- fail
@ -1136,15 +1135,14 @@ NOTICE: f_leak => awesome science fiction
(4 rows)
EXPLAIN (COSTS OFF) SELECT * FROM part_document WHERE f_leak(dtitle);
QUERY PLAN
--------------------------------------------------------------------
Append
QUERY PLAN
--------------------------------------------------------------
Seq Scan on part_document_fiction
Filter: ((cid < 55) AND (dlevel <= $0) AND f_leak(dtitle))
InitPlan 1 (returns $0)
-> Index Scan using uaccount_pkey on uaccount
Index Cond: (pguser = CURRENT_USER)
-> Seq Scan on part_document_fiction
Filter: ((cid < 55) AND (dlevel <= $0) AND f_leak(dtitle))
(6 rows)
(5 rows)
-- viewpoint from regress_rls_carol
SET SESSION AUTHORIZATION regress_rls_carol;

View File

@ -812,11 +812,10 @@ explain (costs off)
UNION ALL
SELECT 2 AS t, * FROM tenk1 b) c
WHERE t = 2;
QUERY PLAN
---------------------------
Append
-> Seq Scan on tenk1 b
(2 rows)
QUERY PLAN
---------------------
Seq Scan on tenk1 b
(1 row)
-- Test that we push quals into UNION sub-selects only when it's safe
explain (costs off)