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