@@ -112,7 +112,10 @@ EXPLAIN (COSTS OFF) SELECT * FROM test.range_rel_1 UNION ALL SELECT * FROM test.
112112 * Join
113113*/
114114SET enable_hashjoin= OFF;
115+ set enable_nestloop= OFF;
115116SET enable_mergejoin= ON ;
117+ SET pg_pathman .enable_runtimeappend = OFF;
118+ SET pg_pathman .enable_runtimemergeappend = OFF;
116119EXPLAIN (COSTS OFF)
117120SELECT * FROM test .range_rel j1
118121JOIN test .range_rel j2on j2 .id = j1 .id
@@ -137,6 +140,149 @@ EXPLAIN (COSTS OFF)
137140 WITH tttAS (SELECT * FROM test .hash_rel WHERE value= 2 )
138141SELECT * FROM ttt;
139142
143+
144+ /*
145+ * Test RuntimeAppend
146+ */
147+
148+ create or replace function test .pathman_assert(smt bool, error_msgtext ) returnstext as $$
149+ begin
150+ if not smt then
151+ raise exception' %' , error_msg;
152+ end if;
153+
154+ return' ok' ;
155+ end;
156+ $$ language plpgsql;
157+
158+ create or replace function test .pathman_equal(atext , btext , error_msgtext ) returnstext as $$
159+ begin
160+ if a!= b then
161+ raise exception' ' ' %' ' is not equal to' ' %' ' , %' , a, b, error_msg;
162+ end if;
163+
164+ return' equal' ;
165+ end;
166+ $$ language plpgsql;
167+
168+ create or replace function test .pathman_test(querytext ) returns jsonbas $$
169+ declare
170+ plan jsonb;
171+ begin
172+ execute' explain (analyze, format json)' || query into plan;
173+
174+ return plan;
175+ end;
176+ $$ language plpgsql;
177+
178+ create or replace function test .pathman_test_1() returnstext as $$
179+ declare
180+ plan jsonb;
181+ numint ;
182+ begin
183+ plan= test .pathman_test (' select * from test.runtime_test_1 where id = (select * from test.run_values limit 1)' );
184+
185+ performtest .pathman_equal ((plan- > 0 - > ' Plan' - > ' Node Type' )::text ,
186+ ' "Custom Scan"' ,
187+ ' wrong plan type' );
188+
189+ performtest .pathman_equal ((plan- > 0 - > ' Plan' - > ' Custom Plan Provider' )::text ,
190+ ' "RuntimeAppend"' ,
191+ ' wrong plan provider' );
192+
193+ performtest .pathman_equal ((plan- > 0 - > ' Plan' - > ' Plans' - > 1 - > ' Relation Name' )::text ,
194+ ' "runtime_test_1_1"' ,
195+ ' wrong partition' );
196+ return' ok' ;
197+ end;
198+ $$ language plpgsql;
199+
200+ create or replace function test .pathman_test_2() returnstext as $$
201+ declare
202+ plan jsonb;
203+ numint ;
204+ begin
205+ plan= test .pathman_test (' select * from test.runtime_test_1 where id = any (select * from test.run_values limit 6)' );
206+
207+ performtest .pathman_equal ((plan- > 0 - > ' Plan' - > ' Node Type' )::text ,
208+ ' "Nested Loop"' ,
209+ ' wrong plan type' );
210+
211+ performtest .pathman_equal ((plan- > 0 - > ' Plan' - > ' Plans' - > 1 - > ' Node Type' )::text ,
212+ ' "Custom Scan"' ,
213+ ' wrong plan type' );
214+
215+ performtest .pathman_equal ((plan- > 0 - > ' Plan' - > ' Plans' - > 1 - > ' Custom Plan Provider' )::text ,
216+ ' "RuntimeAppend"' ,
217+ ' wrong plan provider' );
218+
219+ select count (* )from jsonb_array_elements_text(plan- > 0 - > ' Plan' - > ' Plans' - > 1 - > ' Plans' ) into num;
220+ performtest .pathman_equal (num::text ,' 6' ,' expected 6 child plans for custom scan' );
221+
222+ for iin 0 ..5 loop
223+ performtest .pathman_equal ((plan- > 0 - > ' Plan' - > ' Plans' - > 1 - > ' Plans' - > i- > ' Relation Name' )::text ,
224+ format(' "runtime_test_1_%s"' , i+ 1 ),
225+ ' wrong partition' );
226+
227+ num= plan- > 0 - > ' Plan' - > ' Plans' - > 1 - > ' Plans' - > i- > ' Actual Loops' ;
228+ performtest .pathman_equal (num::text ,' 1' ,' expected 1 loop' );
229+ end loop;
230+
231+ return' ok' ;
232+ end;
233+ $$ language plpgsql;
234+
235+ create or replace function test .pathman_test_3() returnstext as $$
236+ declare
237+ plan jsonb;
238+ numint ;
239+ begin
240+ plan= test .pathman_test (' select * from test.runtime_test_1 a join test.run_values b on a.id = b.val' );
241+
242+ performtest .pathman_equal ((plan- > 0 - > ' Plan' - > ' Node Type' )::text ,
243+ ' "Nested Loop"' ,
244+ ' wrong plan type' );
245+
246+ performtest .pathman_equal ((plan- > 0 - > ' Plan' - > ' Plans' - > 1 - > ' Node Type' )::text ,
247+ ' "Custom Scan"' ,
248+ ' wrong plan type' );
249+
250+ performtest .pathman_equal ((plan- > 0 - > ' Plan' - > ' Plans' - > 1 - > ' Custom Plan Provider' )::text ,
251+ ' "RuntimeAppend"' ,
252+ ' wrong plan provider' );
253+
254+ select count (* )from jsonb_array_elements_text(plan- > 0 - > ' Plan' - > ' Plans' - > 1 - > ' Plans' ) into num;
255+ performtest .pathman_equal (num::text ,' 128' ,' expected 128 child plans for custom scan' );
256+
257+ for iin 0 ..127 loop
258+ num= plan- > 0 - > ' Plan' - > ' Plans' - > 1 - > ' Plans' - > i- > ' Actual Loops' ;
259+ performtest .pathman_assert (num<= 79 ,' expected no more than 79 loops' );
260+ end loop;
261+
262+ return' ok' ;
263+ end;
264+ $$ language plpgsql;
265+
266+
267+ create table test .run_valuesas select generate_series(1 ,10000 ) val;
268+ create table test .runtime_test_1(idserial primary key , valreal );
269+ insert into test .runtime_test_1 select generate_series(1 ,10000 ), random();
270+ select pathman .create_hash_partitions (' test.runtime_test_1' ,' id' ,128 );
271+
272+ analyzetest .run_values ;
273+ analyzetest .runtime_test_1 ;
274+
275+ set enable_mergejoin= off;
276+ set enable_hashjoin= off;
277+ set pg_pathman .enable_runtimeappend = on ;
278+ select test .pathman_test_1 ();/* RuntimeAppend (select ... where id = (subquery))*/
279+ select test .pathman_test_2 ();/* RuntimeAppend (select ... where id = any(subquery))*/
280+ select test .pathman_test_3 ();/* RuntimeAppend (a join b on a.id = b.val)*/
281+ set enable_mergejoin= on ;
282+ set enable_hashjoin= on ;
283+
284+ drop table test .run_values ,test .runtime_test_1 cascade;
285+
140286/*
141287 * Test split and merge
142288*/