@@ -112,7 +112,10 @@ EXPLAIN (COSTS OFF) SELECT * FROM test.range_rel_1 UNION ALL SELECT * FROM test.
112
112
* Join
113
113
*/
114
114
SET enable_hashjoin = OFF;
115
+ set enable_nestloop = OFF;
115
116
SET enable_mergejoin = ON ;
117
+ SET pg_pathman .enable_runtimeappend = OFF;
118
+ SET pg_pathman .enable_runtimemergeappend = OFF;
116
119
EXPLAIN (COSTS OFF)
117
120
SELECT * FROM test .range_rel j1
118
121
JOIN test .range_rel j2 on j2 .id = j1 .id
@@ -137,6 +140,149 @@ EXPLAIN (COSTS OFF)
137
140
WITH ttt AS (SELECT * FROM test .hash_rel WHERE value = 2 )
138
141
SELECT * FROM ttt;
139
142
143
+
144
+ /*
145
+ * Test RuntimeAppend
146
+ */
147
+
148
+ create or replace function test .pathman_assert(smt bool, error_msg text ) returns text 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(a text , b text , error_msg text ) returns text 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(query text ) returns jsonb as $$
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() returns text as $$
179
+ declare
180
+ plan jsonb;
181
+ num int ;
182
+ begin
183
+ plan = test .pathman_test (' select * from test.runtime_test_1 where id = (select * from test.run_values limit 1)' );
184
+
185
+ perform test .pathman_equal ((plan- > 0 - > ' Plan' - > ' Node Type' )::text ,
186
+ ' "Custom Scan"' ,
187
+ ' wrong plan type' );
188
+
189
+ perform test .pathman_equal ((plan- > 0 - > ' Plan' - > ' Custom Plan Provider' )::text ,
190
+ ' "RuntimeAppend"' ,
191
+ ' wrong plan provider' );
192
+
193
+ perform test .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() returns text as $$
201
+ declare
202
+ plan jsonb;
203
+ num int ;
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
+ perform test .pathman_equal ((plan- > 0 - > ' Plan' - > ' Node Type' )::text ,
208
+ ' "Nested Loop"' ,
209
+ ' wrong plan type' );
210
+
211
+ perform test .pathman_equal ((plan- > 0 - > ' Plan' - > ' Plans' - > 1 - > ' Node Type' )::text ,
212
+ ' "Custom Scan"' ,
213
+ ' wrong plan type' );
214
+
215
+ perform test .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
+ perform test .pathman_equal (num::text , ' 6' , ' expected 6 child plans for custom scan' );
221
+
222
+ for i in 0 ..5 loop
223
+ perform test .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
+ perform test .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() returns text as $$
236
+ declare
237
+ plan jsonb;
238
+ num int ;
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
+ perform test .pathman_equal ((plan- > 0 - > ' Plan' - > ' Node Type' )::text ,
243
+ ' "Nested Loop"' ,
244
+ ' wrong plan type' );
245
+
246
+ perform test .pathman_equal ((plan- > 0 - > ' Plan' - > ' Plans' - > 1 - > ' Node Type' )::text ,
247
+ ' "Custom Scan"' ,
248
+ ' wrong plan type' );
249
+
250
+ perform test .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
+ perform test .pathman_equal (num::text , ' 128' , ' expected 128 child plans for custom scan' );
256
+
257
+ for i in 0 ..127 loop
258
+ num = plan- > 0 - > ' Plan' - > ' Plans' - > 1 - > ' Plans' - > i- > ' Actual Loops' ;
259
+ perform test .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_values as select generate_series(1 , 10000 ) val;
268
+ create table test .runtime_test_1(id serial primary key , val real );
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
+ analyze test .run_values ;
273
+ analyze test .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
+
140
286
/*
141
287
* Test split and merge
142
288
*/
0 commit comments