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