@@ -3823,3 +3823,183 @@ select * from tuplesest_tab join
3823
3823
3824
3824
drop table tuplesest_parted;
3825
3825
drop 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
+