@@ -3823,3 +3823,183 @@ select * from tuplesest_tab join
38233823
38243824drop table tuplesest_parted;
38253825drop table tuplesest_tab;
3826+ --
3827+ -- Test the cases for partition pruning by an expression like:
3828+ -- partkey = ANY($1)
3829+ --
3830+ CREATE TABLE array_prune (id int)
3831+ PARTITION BY HASH(id);
3832+ CREATE TABLE array_prune_t0
3833+ PARTITION OF array_prune FOR VALUES WITH (modulus 2, remainder 0);
3834+ CREATE TABLE array_prune_t1
3835+ PARTITION OF array_prune FOR VALUES WITH (modulus 2, remainder 1);
3836+ CREATE FUNCTION array_prune_fn(oper text, arr text) RETURNS setof text
3837+ LANGUAGE plpgsql AS $$
3838+ DECLARE
3839+ line text;
3840+ query text;
3841+ BEGIN
3842+ query := format('EXPLAIN (COSTS OFF) SELECT * FROM array_prune WHERE id %s (%s)', $1, $2);
3843+ FOR line IN EXECUTE query
3844+ LOOP
3845+ RETURN NEXT line;
3846+ END LOOP;
3847+ END; $$;
3848+ SELECT array_prune_fn('= ANY', 'ARRAY[1]'); -- prune one partition
3849+ array_prune_fn
3850+ -----------------------------------------
3851+ Seq Scan on array_prune_t0 array_prune
3852+ Filter: (id = ANY ('{1}'::integer[]))
3853+ (2 rows)
3854+
3855+ SELECT array_prune_fn('= ANY', 'ARRAY[1,2]'); -- prune one partition
3856+ array_prune_fn
3857+ -------------------------------------------
3858+ Seq Scan on array_prune_t0 array_prune
3859+ Filter: (id = ANY ('{1,2}'::integer[]))
3860+ (2 rows)
3861+
3862+ SELECT array_prune_fn('= ANY', 'ARRAY[1,2,3]'); -- no pruning
3863+ array_prune_fn
3864+ ---------------------------------------------------
3865+ Append
3866+ -> Seq Scan on array_prune_t0 array_prune_1
3867+ Filter: (id = ANY ('{1,2,3}'::integer[]))
3868+ -> Seq Scan on array_prune_t1 array_prune_2
3869+ Filter: (id = ANY ('{1,2,3}'::integer[]))
3870+ (5 rows)
3871+
3872+ SELECT array_prune_fn('= ANY', 'ARRAY[1, NULL]'); -- prune
3873+ array_prune_fn
3874+ ----------------------------------------------
3875+ Seq Scan on array_prune_t0 array_prune
3876+ Filter: (id = ANY ('{1,NULL}'::integer[]))
3877+ (2 rows)
3878+
3879+ SELECT array_prune_fn('= ANY', 'ARRAY[3, NULL]'); -- prune
3880+ array_prune_fn
3881+ ----------------------------------------------
3882+ Seq Scan on array_prune_t1 array_prune
3883+ Filter: (id = ANY ('{3,NULL}'::integer[]))
3884+ (2 rows)
3885+
3886+ SELECT array_prune_fn('= ANY', 'ARRAY[NULL, NULL]'); -- error
3887+ ERROR: operator does not exist: integer = text
3888+ LINE 1: ...IN (COSTS OFF) SELECT * FROM array_prune WHERE id = ANY (ARR...
3889+ ^
3890+ HINT: No operator matches the given name and argument types. You might need to add explicit type casts.
3891+ QUERY: EXPLAIN (COSTS OFF) SELECT * FROM array_prune WHERE id = ANY (ARRAY[NULL, NULL])
3892+ CONTEXT: PL/pgSQL function array_prune_fn(text,text) line 7 at FOR over EXECUTE statement
3893+ -- Check case of explicit cast
3894+ SELECT array_prune_fn('= ANY', 'ARRAY[1,2]::numeric[]');
3895+ array_prune_fn
3896+ ------------------------------------------------------------
3897+ Append
3898+ -> Seq Scan on array_prune_t0 array_prune_1
3899+ Filter: ((id)::numeric = ANY ('{1,2}'::numeric[]))
3900+ -> Seq Scan on array_prune_t1 array_prune_2
3901+ Filter: ((id)::numeric = ANY ('{1,2}'::numeric[]))
3902+ (5 rows)
3903+
3904+ SELECT array_prune_fn('= ANY', 'ARRAY[1::bigint,2::int]'); -- conversion to bigint
3905+ array_prune_fn
3906+ ------------------------------------------
3907+ Seq Scan on array_prune_t0 array_prune
3908+ Filter: (id = ANY ('{1,2}'::bigint[]))
3909+ (2 rows)
3910+
3911+ SELECT array_prune_fn('= ANY', 'ARRAY[1::bigint,2::numeric]'); -- conversion to numeric
3912+ array_prune_fn
3913+ ------------------------------------------------------------
3914+ Append
3915+ -> Seq Scan on array_prune_t0 array_prune_1
3916+ Filter: ((id)::numeric = ANY ('{1,2}'::numeric[]))
3917+ -> Seq Scan on array_prune_t1 array_prune_2
3918+ Filter: ((id)::numeric = ANY ('{1,2}'::numeric[]))
3919+ (5 rows)
3920+
3921+ SELECT array_prune_fn('= ANY', 'ARRAY[1::bigint,2::text]'); -- Error. XXX: slightly different error in comparison with the static case
3922+ ERROR: ARRAY types bigint and text cannot be matched
3923+ LINE 1: ...* FROM array_prune WHERE id = ANY (ARRAY[1::bigint,2::text])
3924+ ^
3925+ QUERY: EXPLAIN (COSTS OFF) SELECT * FROM array_prune WHERE id = ANY (ARRAY[1::bigint,2::text])
3926+ CONTEXT: PL/pgSQL function array_prune_fn(text,text) line 7 at FOR over EXECUTE statement
3927+ SELECT array_prune_fn('<> ANY', 'ARRAY[1]'); -- no pruning
3928+ array_prune_fn
3929+ ------------------------------------------------
3930+ Append
3931+ -> Seq Scan on array_prune_t0 array_prune_1
3932+ Filter: (id <> ANY ('{1}'::integer[]))
3933+ -> Seq Scan on array_prune_t1 array_prune_2
3934+ Filter: (id <> ANY ('{1}'::integer[]))
3935+ (5 rows)
3936+
3937+ DROP TABLE IF EXISTS array_prune CASCADE;
3938+ CREATE TABLE array_prune (id int)
3939+ PARTITION BY RANGE(id);
3940+ CREATE TABLE array_prune_t0
3941+ PARTITION OF array_prune FOR VALUES FROM (1) TO (10);
3942+ CREATE TABLE array_prune_t1
3943+ PARTITION OF array_prune FOR VALUES FROM (10) TO (20);
3944+ SELECT array_prune_fn('= ANY', 'ARRAY[10]'); -- prune
3945+ array_prune_fn
3946+ ------------------------------------------
3947+ Seq Scan on array_prune_t1 array_prune
3948+ Filter: (id = ANY ('{10}'::integer[]))
3949+ (2 rows)
3950+
3951+ SELECT array_prune_fn('>= ANY', 'ARRAY[10]'); -- prune
3952+ array_prune_fn
3953+ -------------------------------------------
3954+ Seq Scan on array_prune_t1 array_prune
3955+ Filter: (id >= ANY ('{10}'::integer[]))
3956+ (2 rows)
3957+
3958+ SELECT array_prune_fn('>= ANY', 'ARRAY[9, 10]'); -- do not prune
3959+ array_prune_fn
3960+ ---------------------------------------------------
3961+ Append
3962+ -> Seq Scan on array_prune_t0 array_prune_1
3963+ Filter: (id >= ANY ('{9,10}'::integer[]))
3964+ -> Seq Scan on array_prune_t1 array_prune_2
3965+ Filter: (id >= ANY ('{9,10}'::integer[]))
3966+ (5 rows)
3967+
3968+ DROP TABLE IF EXISTS array_prune CASCADE;
3969+ CREATE TABLE array_prune (id int)
3970+ PARTITION BY LIST(id);
3971+ CREATE TABLE array_prune_t0
3972+ PARTITION OF array_prune FOR VALUES IN ('1');
3973+ CREATE TABLE array_prune_t1
3974+ PARTITION OF array_prune FOR VALUES IN ('2');
3975+ SELECT array_prune_fn('= ANY', 'ARRAY[1,1]'); -- prune second
3976+ array_prune_fn
3977+ -------------------------------------------
3978+ Seq Scan on array_prune_t0 array_prune
3979+ Filter: (id = ANY ('{1,1}'::integer[]))
3980+ (2 rows)
3981+
3982+ SELECT array_prune_fn('>= ANY', 'ARRAY[1,2]'); -- do not prune
3983+ array_prune_fn
3984+ --------------------------------------------------
3985+ Append
3986+ -> Seq Scan on array_prune_t0 array_prune_1
3987+ Filter: (id >= ANY ('{1,2}'::integer[]))
3988+ -> Seq Scan on array_prune_t1 array_prune_2
3989+ Filter: (id >= ANY ('{1,2}'::integer[]))
3990+ (5 rows)
3991+
3992+ SELECT array_prune_fn('<> ANY', 'ARRAY[1]'); -- prune second
3993+ array_prune_fn
3994+ ------------------------------------------
3995+ Seq Scan on array_prune_t1 array_prune
3996+ Filter: (id <> ANY ('{1}'::integer[]))
3997+ (2 rows)
3998+
3999+ SELECT array_prune_fn('<> ALL', 'ARRAY[1,2]'); -- prune both
4000+ array_prune_fn
4001+ --------------------------
4002+ Result
4003+ One-Time Filter: false
4004+ (2 rows)
4005+
0 commit comments