From 2f729d83226705d1149419a2aef7c1678fe641ec Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Fri, 9 Aug 2019 13:20:28 -0400 Subject: [PATCH] Fix SIGSEGV in pruning for ScalarArrayOp with constant-null array. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not much to be said here: commit 9fdb675fc should have checked constisnull, didn't. Per report from Piotr Włodarczyk. Back-patch to v11 where bug was introduced. Discussion: https://postgr.es/m/CAP-dhMr+vRpwizEYjUjsiZ1vwqpohTm+3Pbdt6Pr7FEgPq9R0Q@mail.gmail.com --- src/backend/partitioning/partprune.c | 7 +- src/test/regress/expected/partition_prune.out | 68 +++++++++++++++++++ src/test/regress/sql/partition_prune.sql | 10 +++ 3 files changed, 84 insertions(+), 1 deletion(-) diff --git a/src/backend/partitioning/partprune.c b/src/backend/partitioning/partprune.c index bfc16409dd9..e15e11e3ab3 100644 --- a/src/backend/partitioning/partprune.c +++ b/src/backend/partitioning/partprune.c @@ -2034,7 +2034,7 @@ match_clause_to_partition_key(GeneratePruningStepsContext *context, * nodes, one for each array element (excepting nulls). */ Const *arr = (Const *) rightop; - ArrayType *arrval = DatumGetArrayTypeP(arr->constvalue); + ArrayType *arrval; int16 elemlen; bool elembyval; char elemalign; @@ -2043,6 +2043,11 @@ match_clause_to_partition_key(GeneratePruningStepsContext *context, int num_elems, i; + /* If the array itself is null, the saop returns null */ + if (arr->constisnull) + return PARTCLAUSE_MATCH_CONTRADICT; + + arrval = DatumGetArrayTypeP(arr->constvalue); get_typlenbyvalalign(ARR_ELEMTYPE(arrval), &elemlen, &elembyval, &elemalign); deconstruct_array(arrval, diff --git a/src/test/regress/expected/partition_prune.out b/src/test/regress/expected/partition_prune.out index 63872285161..c564c056b9c 100644 --- a/src/test/regress/expected/partition_prune.out +++ b/src/test/regress/expected/partition_prune.out @@ -1197,6 +1197,60 @@ explain (costs off) select * from coercepart where a !~ all ('{ab,bc}'); Filter: ((a)::text !~ ALL ('{ab,bc}'::text[])) (7 rows) +explain (costs off) select * from coercepart where a = any ('{ab,bc}'); + QUERY PLAN +------------------------------------------------------- + Append + -> Seq Scan on coercepart_ab + Filter: ((a)::text = ANY ('{ab,bc}'::text[])) + -> Seq Scan on coercepart_bc + Filter: ((a)::text = ANY ('{ab,bc}'::text[])) +(5 rows) + +explain (costs off) select * from coercepart where a = any ('{ab,null}'); + QUERY PLAN +--------------------------------------------------------- + Append + -> Seq Scan on coercepart_ab + Filter: ((a)::text = ANY ('{ab,NULL}'::text[])) +(3 rows) + +explain (costs off) select * from coercepart where a = any (null::text[]); + QUERY PLAN +-------------------------- + Result + One-Time Filter: false +(2 rows) + +explain (costs off) select * from coercepart where a = all ('{ab}'); + QUERY PLAN +---------------------------------------------------- + Append + -> Seq Scan on coercepart_ab + Filter: ((a)::text = ALL ('{ab}'::text[])) +(3 rows) + +explain (costs off) select * from coercepart where a = all ('{ab,bc}'); + QUERY PLAN +-------------------------- + Result + One-Time Filter: false +(2 rows) + +explain (costs off) select * from coercepart where a = all ('{ab,null}'); + QUERY PLAN +-------------------------- + Result + One-Time Filter: false +(2 rows) + +explain (costs off) select * from coercepart where a = all (null::text[]); + QUERY PLAN +-------------------------- + Result + One-Time Filter: false +(2 rows) + drop table coercepart; CREATE TABLE part (a INT, b INT) PARTITION BY LIST (a); CREATE TABLE part_p1 PARTITION OF part FOR VALUES IN (-2,-1,0,1,2); @@ -3076,6 +3130,20 @@ select * from stable_qual_pruning Filter: (a = ANY ('{"Tue Feb 01 00:00:00 2000 PST","Fri Jan 01 00:00:00 2010 PST"}'::timestamp with time zone[])) (4 rows) +explain (analyze, costs off, summary off, timing off) +select * from stable_qual_pruning + where a = any(null::timestamptz[]); + QUERY PLAN +---------------------------------------------------------------- + Append (actual rows=0 loops=1) + -> Seq Scan on stable_qual_pruning1 (actual rows=0 loops=1) + Filter: (a = ANY (NULL::timestamp with time zone[])) + -> Seq Scan on stable_qual_pruning2 (actual rows=0 loops=1) + Filter: (a = ANY (NULL::timestamp with time zone[])) + -> Seq Scan on stable_qual_pruning3 (actual rows=0 loops=1) + Filter: (a = ANY (NULL::timestamp with time zone[])) +(7 rows) + drop table stable_qual_pruning; -- -- Check that pruning with composite range partitioning works correctly when diff --git a/src/test/regress/sql/partition_prune.sql b/src/test/regress/sql/partition_prune.sql index 4d60556d38c..48956c4ee3a 100644 --- a/src/test/regress/sql/partition_prune.sql +++ b/src/test/regress/sql/partition_prune.sql @@ -180,6 +180,13 @@ explain (costs off) select * from coercepart where a ~ any ('{ab}'); explain (costs off) select * from coercepart where a !~ all ('{ab}'); explain (costs off) select * from coercepart where a ~ any ('{ab,bc}'); explain (costs off) select * from coercepart where a !~ all ('{ab,bc}'); +explain (costs off) select * from coercepart where a = any ('{ab,bc}'); +explain (costs off) select * from coercepart where a = any ('{ab,null}'); +explain (costs off) select * from coercepart where a = any (null::text[]); +explain (costs off) select * from coercepart where a = all ('{ab}'); +explain (costs off) select * from coercepart where a = all ('{ab,bc}'); +explain (costs off) select * from coercepart where a = all ('{ab,null}'); +explain (costs off) select * from coercepart where a = all (null::text[]); drop table coercepart; @@ -764,6 +771,9 @@ select * from stable_qual_pruning explain (analyze, costs off, summary off, timing off) select * from stable_qual_pruning where a = any(array['2000-02-01', '2010-01-01']::timestamptz[]); +explain (analyze, costs off, summary off, timing off) +select * from stable_qual_pruning + where a = any(null::timestamptz[]); drop table stable_qual_pruning;