Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 7b88d63

Browse files
committed
Add null test to partition constraint for default range partitions.
Non-default range partitions have a constraint which include null tests, and both default and non-default list partitions also have a constraint which includes null tests, but for some reason this was missed for default range partitions. This could cause the partition constraint to evaluate to false for rows that were (correctly) routed to that partition by insert tuple routing, which could in turn cause constraint exclusion to prune the default partition in cases where it should not. Amit Langote, reviewed by Kyotaro Horiguchi Discussion: http://postgr.es/m/ba7aaeb1-4399-220e-70b4-62eade1522d0@lab.ntt.co.jp
1 parent 487a0c1 commit 7b88d63

File tree

4 files changed

+56
-25
lines changed

4 files changed

+56
-25
lines changed

src/backend/catalog/partition.c

+23-6
Original file line numberDiff line numberDiff line change
@@ -2134,12 +2134,29 @@ get_qual_for_range(Relation parent, PartitionBoundSpec *spec,
21342134

21352135
if (or_expr_args != NIL)
21362136
{
2137-
/* OR all the non-default partition constraints; then negate it */
2138-
result = lappend(result,
2139-
list_length(or_expr_args) > 1
2140-
? makeBoolExpr(OR_EXPR, or_expr_args, -1)
2141-
: linitial(or_expr_args));
2142-
result = list_make1(makeBoolExpr(NOT_EXPR, result, -1));
2137+
Expr *other_parts_constr;
2138+
2139+
/*
2140+
* Combine the constraints obtained for non-default partitions
2141+
* using OR. As requested, each of the OR's args doesn't include
2142+
* the NOT NULL test for partition keys (which is to avoid its
2143+
* useless repetition). Add the same now.
2144+
*/
2145+
other_parts_constr =
2146+
makeBoolExpr(AND_EXPR,
2147+
lappend(get_range_nulltest(key),
2148+
list_length(or_expr_args) > 1
2149+
? makeBoolExpr(OR_EXPR, or_expr_args,
2150+
-1)
2151+
: linitial(or_expr_args)),
2152+
-1);
2153+
2154+
/*
2155+
* Finally, the default partition contains everything *NOT*
2156+
* contained in the non-default partitions.
2157+
*/
2158+
result = list_make1(makeBoolExpr(NOT_EXPR,
2159+
list_make1(other_parts_constr), -1));
21432160
}
21442161

21452162
return result;

src/test/regress/expected/inherit.out

+27-14
Original file line numberDiff line numberDiff line change
@@ -1853,41 +1853,48 @@ drop table range_list_parted;
18531853
-- check that constraint exclusion is able to cope with the partition
18541854
-- constraint emitted for multi-column range partitioned tables
18551855
create table mcrparted (a int, b int, c int) partition by range (a, abs(b), c);
1856+
create table mcrparted_def partition of mcrparted default;
18561857
create table mcrparted0 partition of mcrparted for values from (minvalue, minvalue, minvalue) to (1, 1, 1);
18571858
create table mcrparted1 partition of mcrparted for values from (1, 1, 1) to (10, 5, 10);
18581859
create table mcrparted2 partition of mcrparted for values from (10, 5, 10) to (10, 10, 10);
18591860
create table mcrparted3 partition of mcrparted for values from (11, 1, 1) to (20, 10, 10);
18601861
create table mcrparted4 partition of mcrparted for values from (20, 10, 10) to (20, 20, 20);
18611862
create table mcrparted5 partition of mcrparted for values from (20, 20, 20) to (maxvalue, maxvalue, maxvalue);
1862-
explain (costs off) select * from mcrparted where a = 0; -- scans mcrparted0
1863-
QUERY PLAN
1864-
------------------------------
1863+
explain (costs off) select * from mcrparted where a = 0; -- scans mcrparted0, mcrparted_def
1864+
QUERY PLAN
1865+
---------------------------------
18651866
Append
18661867
-> Seq Scan on mcrparted0
18671868
Filter: (a = 0)
1868-
(3 rows)
1869+
-> Seq Scan on mcrparted_def
1870+
Filter: (a = 0)
1871+
(5 rows)
18691872

1870-
explain (costs off) select * from mcrparted where a = 10 and abs(b) < 5; -- scans mcrparted1
1873+
explain (costs off) select * from mcrparted where a = 10 and abs(b) < 5; -- scans mcrparted1, mcrparted_def
18711874
QUERY PLAN
18721875
---------------------------------------------
18731876
Append
18741877
-> Seq Scan on mcrparted1
18751878
Filter: ((a = 10) AND (abs(b) < 5))
1876-
(3 rows)
1879+
-> Seq Scan on mcrparted_def
1880+
Filter: ((a = 10) AND (abs(b) < 5))
1881+
(5 rows)
18771882

1878-
explain (costs off) select * from mcrparted where a = 10 and abs(b) = 5; -- scans mcrparted1, mcrparted2
1883+
explain (costs off) select * from mcrparted where a = 10 and abs(b) = 5; -- scans mcrparted1, mcrparted2, mcrparted_def
18791884
QUERY PLAN
18801885
---------------------------------------------
18811886
Append
18821887
-> Seq Scan on mcrparted1
18831888
Filter: ((a = 10) AND (abs(b) = 5))
18841889
-> Seq Scan on mcrparted2
18851890
Filter: ((a = 10) AND (abs(b) = 5))
1886-
(5 rows)
1891+
-> Seq Scan on mcrparted_def
1892+
Filter: ((a = 10) AND (abs(b) = 5))
1893+
(7 rows)
18871894

18881895
explain (costs off) select * from mcrparted where abs(b) = 5; -- scans all partitions
1889-
QUERY PLAN
1890-
------------------------------
1896+
QUERY PLAN
1897+
---------------------------------
18911898
Append
18921899
-> Seq Scan on mcrparted0
18931900
Filter: (abs(b) = 5)
@@ -1899,7 +1906,9 @@ explain (costs off) select * from mcrparted where abs(b) = 5; -- scans all parti
18991906
Filter: (abs(b) = 5)
19001907
-> Seq Scan on mcrparted5
19011908
Filter: (abs(b) = 5)
1902-
(11 rows)
1909+
-> Seq Scan on mcrparted_def
1910+
Filter: (abs(b) = 5)
1911+
(13 rows)
19031912

19041913
explain (costs off) select * from mcrparted where a > -1; -- scans all partitions
19051914
QUERY PLAN
@@ -1917,7 +1926,9 @@ explain (costs off) select * from mcrparted where a > -1; -- scans all partition
19171926
Filter: (a > '-1'::integer)
19181927
-> Seq Scan on mcrparted5
19191928
Filter: (a > '-1'::integer)
1920-
(13 rows)
1929+
-> Seq Scan on mcrparted_def
1930+
Filter: (a > '-1'::integer)
1931+
(15 rows)
19211932

19221933
explain (costs off) select * from mcrparted where a = 20 and abs(b) = 10 and c > 10; -- scans mcrparted4
19231934
QUERY PLAN
@@ -1927,7 +1938,7 @@ explain (costs off) select * from mcrparted where a = 20 and abs(b) = 10 and c >
19271938
Filter: ((c > 10) AND (a = 20) AND (abs(b) = 10))
19281939
(3 rows)
19291940

1930-
explain (costs off) select * from mcrparted where a = 20 and c > 20; -- scans mcrparted3, mcrparte4, mcrparte5
1941+
explain (costs off) select * from mcrparted where a = 20 and c > 20; -- scans mcrparted3, mcrparte4, mcrparte5, mcrparted_def
19311942
QUERY PLAN
19321943
-----------------------------------------
19331944
Append
@@ -1937,7 +1948,9 @@ explain (costs off) select * from mcrparted where a = 20 and c > 20; -- scans mc
19371948
Filter: ((c > 20) AND (a = 20))
19381949
-> Seq Scan on mcrparted5
19391950
Filter: ((c > 20) AND (a = 20))
1940-
(7 rows)
1951+
-> Seq Scan on mcrparted_def
1952+
Filter: ((c > 20) AND (a = 20))
1953+
(9 rows)
19411954

19421955
drop table mcrparted;
19431956
-- check that partitioned table Appends cope with being referenced in

src/test/regress/expected/update.out

+1-1
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ create table part_def partition of range_parted default;
227227
a | text | | | | extended | |
228228
b | integer | | | | plain | |
229229
Partition of: range_parted DEFAULT
230-
Partition constraint: (NOT (((a = 'a'::text) AND (b >= 1) AND (b < 10)) OR ((a = 'a'::text) AND (b >= 10) AND (b < 20)) OR ((a = 'b'::text) AND (b >= 1) AND (b < 10)) OR ((a = 'b'::text) AND (b >= 10) AND (b < 20))))
230+
Partition constraint: (NOT ((a IS NOT NULL) AND (b IS NOT NULL) AND (((a = 'a'::text) AND (b >= 1) AND (b < 10)) OR ((a = 'a'::text) AND (b >= 10) AND (b < 20)) OR ((a = 'b'::text) AND (b >= 1) AND (b < 10)) OR ((a = 'b'::text) AND (b >= 10) AND (b < 20)))))
231231

232232
insert into range_parted values ('c', 9);
233233
-- ok

src/test/regress/sql/inherit.sql

+5-4
Original file line numberDiff line numberDiff line change
@@ -664,19 +664,20 @@ drop table range_list_parted;
664664
-- check that constraint exclusion is able to cope with the partition
665665
-- constraint emitted for multi-column range partitioned tables
666666
create table mcrparted (a int, b int, c int) partition by range (a, abs(b), c);
667+
create table mcrparted_def partition of mcrparted default;
667668
create table mcrparted0 partition of mcrparted for values from (minvalue, minvalue, minvalue) to (1, 1, 1);
668669
create table mcrparted1 partition of mcrparted for values from (1, 1, 1) to (10, 5, 10);
669670
create table mcrparted2 partition of mcrparted for values from (10, 5, 10) to (10, 10, 10);
670671
create table mcrparted3 partition of mcrparted for values from (11, 1, 1) to (20, 10, 10);
671672
create table mcrparted4 partition of mcrparted for values from (20, 10, 10) to (20, 20, 20);
672673
create table mcrparted5 partition of mcrparted for values from (20, 20, 20) to (maxvalue, maxvalue, maxvalue);
673-
explain (costs off) select * from mcrparted where a = 0; -- scans mcrparted0
674-
explain (costs off) select * from mcrparted where a = 10 and abs(b) < 5; -- scans mcrparted1
675-
explain (costs off) select * from mcrparted where a = 10 and abs(b) = 5; -- scans mcrparted1, mcrparted2
674+
explain (costs off) select * from mcrparted where a = 0; -- scans mcrparted0, mcrparted_def
675+
explain (costs off) select * from mcrparted where a = 10 and abs(b) < 5; -- scans mcrparted1, mcrparted_def
676+
explain (costs off) select * from mcrparted where a = 10 and abs(b) = 5; -- scans mcrparted1, mcrparted2, mcrparted_def
676677
explain (costs off) select * from mcrparted where abs(b) = 5; -- scans all partitions
677678
explain (costs off) select * from mcrparted where a > -1; -- scans all partitions
678679
explain (costs off) select * from mcrparted where a = 20 and abs(b) = 10 and c > 10; -- scans mcrparted4
679-
explain (costs off) select * from mcrparted where a = 20 and c > 20; -- scans mcrparted3, mcrparte4, mcrparte5
680+
explain (costs off) select * from mcrparted where a = 20 and c > 20; -- scans mcrparted3, mcrparte4, mcrparte5, mcrparted_def
680681
drop table mcrparted;
681682

682683
-- check that partitioned table Appends cope with being referenced in

0 commit comments

Comments
 (0)