@@ -160,6 +160,89 @@ WHERE a.aid = b.aid AND b.bval like 'val%';
160160 JOINS: 0
161161(6 rows)
162162
163+ -- Partitioned join over foreign tables
164+ set enable_partitionwise_join = on;
165+ ALTER SERVER loopback OPTIONS (ADD fdw_tuple_cost '1.0');
166+ CREATE TABLE local_main_p0(aid int, aval text);
167+ CREATE TABLE local_main_p1(aid int, aval text);
168+ CREATE TABLE main (aid int, aval text) PARTITION BY HASH(aid);
169+ CREATE FOREIGN TABLE main_p0 PARTITION OF main FOR VALUES WITH (MODULUS 3, REMAINDER 0)
170+ SERVER loopback OPTIONS (table_name 'local_main_p0');
171+ CREATE FOREIGN TABLE main_p1 PARTITION OF main FOR VALUES WITH (MODULUS 3, REMAINDER 1)
172+ SERVER loopback OPTIONS (table_name 'local_main_p1');
173+ CREATE TABLE main_p2 PARTITION OF main FOR VALUES WITH (MODULUS 3, REMAINDER 2);
174+ CREATE TABLE local_ref_p0(bid int, aid int, bval text);
175+ CREATE TABLE local_ref_p1(bid int, aid int, bval text);
176+ CREATE TABLE ref (bid int, aid int, bval text) PARTITION BY HASH(aid);
177+ CREATE FOREIGN TABLE ref_p0 PARTITION OF ref FOR VALUES WITH (MODULUS 3, REMAINDER 0)
178+ SERVER loopback OPTIONS (table_name 'local_ref_p0');
179+ CREATE FOREIGN TABLE ref_p1 PARTITION OF ref FOR VALUES WITH (MODULUS 3, REMAINDER 1)
180+ SERVER loopback OPTIONS (table_name 'local_ref_p1');
181+ CREATE TABLE ref_p2 PARTITION OF ref FOR VALUES WITH (MODULUS 3, REMAINDER 2);
182+ INSERT INTO main SELECT i, 'val_' || i FROM generate_series(1,100) i;
183+ INSERT INTO ref SELECT i, mod(i, 10) + 1, 'val_' || i FROM generate_series(1,1000) i;
184+ ANALYZE local_main_p0, local_main_p1, main_p2;
185+ ANALYZE local_ref_p0, local_ref_p1, ref_p2;
186+ EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF)
187+ SELECT * from main AS a, ref AS b
188+ WHERE a.aid = b.aid AND b.bval like 'val%';
189+ QUERY PLAN
190+ --------------------------------------------------------------------
191+ Append (actual rows=1000 loops=1)
192+ AQO not used
193+ -> Foreign Scan (actual rows=400 loops=1)
194+ AQO not used
195+ Relations: (main_p0 a_1) INNER JOIN (ref_p0 b_1)
196+ -> Foreign Scan (actual rows=300 loops=1)
197+ AQO not used
198+ Relations: (main_p1 a_2) INNER JOIN (ref_p1 b_2)
199+ -> Hash Join (actual rows=300 loops=1)
200+ AQO not used
201+ Hash Cond: (b_3.aid = a_3.aid)
202+ -> Seq Scan on ref_p2 b_3 (actual rows=300 loops=1)
203+ AQO not used
204+ Filter: (bval ~~ 'val%'::text)
205+ -> Hash (actual rows=38 loops=1)
206+ Buckets: 1024 Batches: 1 Memory Usage: 10kB
207+ -> Seq Scan on main_p2 a_3 (actual rows=38 loops=1)
208+ AQO not used
209+ Using aqo: true
210+ AQO mode: LEARN
211+ JOINS: 1
212+ (21 rows)
213+
214+ EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF)
215+ SELECT * from main AS a, ref AS b
216+ WHERE a.aid = b.aid AND b.bval like 'val%';
217+ QUERY PLAN
218+ --------------------------------------------------------------------
219+ Append (actual rows=1000 loops=1)
220+ AQO not used
221+ -> Foreign Scan (actual rows=400 loops=1)
222+ AQO: rows=400, error=0%
223+ Relations: (main_p0 a_1) INNER JOIN (ref_p0 b_1)
224+ -> Foreign Scan (actual rows=300 loops=1)
225+ AQO: rows=300, error=0%
226+ Relations: (main_p1 a_2) INNER JOIN (ref_p1 b_2)
227+ -> Hash Join (actual rows=300 loops=1)
228+ AQO: rows=300, error=0%
229+ Hash Cond: (b_3.aid = a_3.aid)
230+ -> Seq Scan on ref_p2 b_3 (actual rows=300 loops=1)
231+ AQO: rows=300, error=0%
232+ Filter: (bval ~~ 'val%'::text)
233+ -> Hash (actual rows=38 loops=1)
234+ Buckets: 1024 Batches: 1 Memory Usage: 10kB
235+ -> Seq Scan on main_p2 a_3 (actual rows=38 loops=1)
236+ AQO: rows=38, error=0%
237+ Using aqo: true
238+ AQO mode: LEARN
239+ JOINS: 1
240+ (21 rows)
241+
242+ DROP TABLE main, local_main_p0, local_main_p1;
243+ DROP TABLE ref, local_ref_p0, local_ref_p1;
244+ ALTER SERVER loopback OPTIONS (DROP fdw_tuple_cost);
245+ reset enable_partitionwise_join;
163246-- TODO: Non-mergejoinable join condition.
164247EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF)
165248SELECT * FROM frgn AS a, frgn AS b WHERE a.x<b.x;