Skip to content

Commit 9e615f0

Browse files
committed
improve tlist handling in Runtime[Merge]Append
1 parent 5180382 commit 9e615f0

File tree

3 files changed

+131
-31
lines changed

3 files changed

+131
-31
lines changed

expected/pathman_runtime_nodes.out

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -180,9 +180,21 @@ begin
180180
into res; /* test empty tlist */
181181

182182

183+
select id * 2, id, 17
184+
from test.runtime_test_3
185+
where id = (select * from test.vals order by val limit 1)
186+
limit 1
187+
into res; /* test computations */
188+
189+
190+
select test.vals.* from test.vals, lateral (select from test.runtime_test_3
191+
where id = test.vals.val) as q
192+
into res; /* test lateral */
193+
194+
183195
select id, generate_series(1, 2) gen, val
184196
from test.runtime_test_3
185-
where id = any (select * from test.vals order by val limit 5)
197+
where id = (select * from test.vals order by val limit 1)
186198
order by id, gen, val
187199
offset 1 limit 1
188200
into res; /* without IndexOnlyScan */
@@ -248,11 +260,7 @@ select pathman.create_hash_partitions('test.runtime_test_3', 'id', 4);
248260

249261
create index on test.runtime_test_3 (id);
250262
create index on test.runtime_test_3_0 (id);
251-
analyze test.run_values;
252-
analyze test.runtime_test_1;
253-
analyze test.runtime_test_2;
254-
analyze test.runtime_test_3;
255-
analyze test.runtime_test_3_0;
263+
VACUUM ANALYZE;
256264
set pg_pathman.enable_runtimeappend = on;
257265
set pg_pathman.enable_runtimemergeappend = on;
258266
select test.pathman_test_1(); /* RuntimeAppend (select ... where id = (subquery)) */
@@ -285,6 +293,19 @@ select test.pathman_test_5(); /* projection tests for RuntimeXXX nodes */
285293
ok
286294
(1 row)
287295

296+
/* RuntimeAppend (select ... where id = ANY (subquery), missing partitions) */
297+
select count(*) = 0 from pathman.pathman_partition_list
298+
where parent = 'test.runtime_test_1'::regclass and range_max::int < 0;
299+
?column?
300+
----------
301+
t
302+
(1 row)
303+
304+
select from test.runtime_test_1
305+
where id = any (select generate_series(-10, -1)); /* should be empty */
306+
--
307+
(0 rows)
308+
288309
/* RuntimeAppend (join, enabled parent) */
289310
select pathman.set_enable_parent('test.runtime_test_1', true);
290311
set_enable_parent
@@ -301,7 +322,7 @@ join (select * from test.run_values limit 4) as t2 on t1.id = t2.val;
301322
-> Limit
302323
-> Seq Scan on run_values
303324
-> Custom Scan (RuntimeAppend)
304-
-> Index Only Scan using runtime_test_1_pkey on runtime_test_1 t1
325+
-> Seq Scan on runtime_test_1 t1
305326
Filter: (run_values.val = id)
306327
-> Index Only Scan using runtime_test_1_0_pkey on runtime_test_1_0 t1
307328
Index Cond: (id = run_values.val)

sql/pathman_runtime_nodes.sql

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -190,9 +190,21 @@ begin
190190
into res; /* test empty tlist */
191191

192192

193+
select id * 2, id, 17
194+
from test.runtime_test_3
195+
where id = (select * from test.vals order by val limit 1)
196+
limit 1
197+
into res; /* test computations */
198+
199+
200+
select test.vals.* from test.vals, lateral (select from test.runtime_test_3
201+
where id = test.vals.val) as q
202+
into res; /* test lateral */
203+
204+
193205
select id, generate_series(1, 2) gen, val
194206
from test.runtime_test_3
195-
where id = any (select * from test.vals order by val limit 5)
207+
where id = (select * from test.vals order by val limit 1)
196208
order by id, gen, val
197209
offset 1 limit 1
198210
into res; /* without IndexOnlyScan */
@@ -250,11 +262,8 @@ create index on test.runtime_test_3 (id);
250262
create index on test.runtime_test_3_0 (id);
251263

252264

253-
analyze test.run_values;
254-
analyze test.runtime_test_1;
255-
analyze test.runtime_test_2;
256-
analyze test.runtime_test_3;
257-
analyze test.runtime_test_3_0;
265+
VACUUM ANALYZE;
266+
258267

259268
set pg_pathman.enable_runtimeappend = on;
260269
set pg_pathman.enable_runtimemergeappend = on;
@@ -265,6 +274,12 @@ select test.pathman_test_3(); /* RuntimeAppend (a join b on a.id = b.val) */
265274
select test.pathman_test_4(); /* RuntimeMergeAppend (lateral) */
266275
select test.pathman_test_5(); /* projection tests for RuntimeXXX nodes */
267276

277+
/* RuntimeAppend (select ... where id = ANY (subquery), missing partitions) */
278+
select count(*) = 0 from pathman.pathman_partition_list
279+
where parent = 'test.runtime_test_1'::regclass and range_max::int < 0;
280+
281+
select from test.runtime_test_1
282+
where id = any (select generate_series(-10, -1)); /* should be empty */
268283

269284
/* RuntimeAppend (join, enabled parent) */
270285
select pathman.set_enable_parent('test.runtime_test_1', true);

src/nodes_common.c

Lines changed: 82 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
#include "access/sysattr.h"
1616
#include "optimizer/restrictinfo.h"
17+
#include "optimizer/tlist.h"
1718
#include "optimizer/var.h"
1819
#include "rewrite/rewriteManip.h"
1920
#include "utils/memutils.h"
@@ -123,40 +124,91 @@ select_required_plans(HTAB *children_table, Oid *parts, int nparts, int *nres)
123124
return result;
124125
}
125126

126-
/* Replace 'varno' of child's Vars with the 'append_rel_rti' */
127+
/* Adapt child's tlist for parent relation (change varnos and varattnos) */
127128
static List *
128-
replace_tlist_varnos(List *tlist, Index old_varno, Index new_varno)
129+
build_parent_tlist(List *tlist, AppendRelInfo *appinfo)
129130
{
130-
List *temp_tlist;
131-
132-
AssertArg(old_varno != 0);
133-
AssertArg(new_varno != 0);
131+
List *temp_tlist,
132+
*pulled_vars;
133+
ListCell *lc1,
134+
*lc2;
134135

135136
temp_tlist = copyObject(tlist);
136-
ChangeVarNodes((Node *) temp_tlist, old_varno, new_varno, 0);
137+
pulled_vars = pull_vars_of_level((Node *) temp_tlist, 0);
138+
139+
foreach (lc1, pulled_vars)
140+
{
141+
Var *tlist_var = (Var *) lfirst(lc1);
142+
143+
AttrNumber attnum = 0;
144+
foreach (lc2, appinfo->translated_vars)
145+
{
146+
Var *translated_var = (Var *) lfirst(lc2);
147+
148+
attnum++;
149+
150+
if (translated_var->varattno == tlist_var->varattno)
151+
tlist_var->varattno = attnum;
152+
}
153+
}
154+
155+
ChangeVarNodes((Node *) temp_tlist,
156+
appinfo->child_relid,
157+
appinfo->parent_relid,
158+
0);
137159

138160
return temp_tlist;
139161
}
140162

163+
/* Is tlist 'a' subset of tlist 'b'? (in terms of Vars) */
164+
static bool
165+
tlist_is_var_subset(List *a, List *b)
166+
{
167+
ListCell *lc;
168+
169+
foreach (lc, b)
170+
{
171+
TargetEntry *te = (TargetEntry *) lfirst(lc);
172+
173+
if (!IsA(te->expr, Var) && !IsA(te->expr, RelabelType))
174+
continue;
175+
176+
if (!tlist_member_ignore_relabel((Node *) te->expr, a))
177+
return true;
178+
}
179+
180+
return false;
181+
}
182+
141183
/* Append partition attribute in case it's not present in target list */
142184
static List *
143-
append_part_attr_to_tlist(List *tlist, Index relno, const PartRelationInfo *prel)
185+
append_part_attr_to_tlist(List *tlist,
186+
AppendRelInfo *appinfo,
187+
const PartRelationInfo *prel)
144188
{
145189
ListCell *lc;
190+
AttrNumber part_attr;
191+
Var *part_attr_tvar;
146192
bool part_attr_found = false;
147193

194+
/* Get attribute number of partitioned column (may differ) */
195+
part_attr_tvar = (Var *) list_nth(appinfo->translated_vars,
196+
AttrNumberGetAttrOffset(prel->attnum));
197+
Assert(part_attr_tvar);
198+
part_attr = (part_attr_tvar)->varoattno;
199+
148200
foreach (lc, tlist)
149201
{
150202
TargetEntry *te = (TargetEntry *) lfirst(lc);
151203
Var *var = (Var *) te->expr;
152204

153-
if (IsA(var, Var) && var->varoattno == prel->attnum)
205+
if (IsA(var, Var) && var->varoattno == part_attr)
154206
part_attr_found = true;
155207
}
156208

157209
if (!part_attr_found)
158210
{
159-
Var *newvar = makeVar(relno,
211+
Var *newvar = makeVar(appinfo->child_relid,
160212
prel->attnum,
161213
prel->atttype,
162214
prel->atttypmod,
@@ -450,28 +502,40 @@ create_append_plan_common(PlannerInfo *root, RelOptInfo *rel,
450502
{
451503
Plan *child_plan = (Plan *) lfirst(lc2);
452504
RelOptInfo *child_rel = ((Path *) lfirst(lc1))->parent;
505+
AppendRelInfo *appinfo = find_childrel_appendrelinfo(root, child_rel);
453506

454507
/* Replace rel's tlist with a matching one (for ExecQual()) */
455508
if (!processed_rel_tlist)
456509
{
457-
tlist = replace_tlist_varnos(child_plan->targetlist,
458-
child_rel->relid,
459-
rel->relid);
510+
List *temp_tlist = build_parent_tlist(child_plan->targetlist,
511+
appinfo);
512+
513+
/*
514+
* HACK: PostgreSQL may return a physical tlist,
515+
* which is bad (we may have child IndexOnlyScans).
516+
* If we find out that CustomScan's tlist is a
517+
* Var-superset of child's tlist, we replace it
518+
* with the latter, else we'll have a broken tlist
519+
* labeling (Assert).
520+
*
521+
* NOTE: physical tlist may only be used if we're not
522+
* asked to produce tuples of exact format (CP_EXACT_TLIST).
523+
*/
524+
if (tlist_is_var_subset(temp_tlist, tlist))
525+
tlist = temp_tlist;
460526

461527
/* Done, new target list has been built */
462528
processed_rel_tlist = true;
463529
}
464530

465531
/* Add partition attribute if necessary (for ExecQual()) */
466532
child_plan->targetlist = append_part_attr_to_tlist(child_plan->targetlist,
467-
child_rel->relid,
468-
prel);
533+
appinfo, prel);
469534

470535
/* Now make custom_scan_tlist match child plans' targetlists */
471536
if (!cscan->custom_scan_tlist)
472-
cscan->custom_scan_tlist = replace_tlist_varnos(child_plan->targetlist,
473-
child_rel->relid,
474-
rel->relid);
537+
cscan->custom_scan_tlist = build_parent_tlist(child_plan->targetlist,
538+
appinfo);
475539
}
476540
}
477541

0 commit comments

Comments
 (0)