|
14 | 14 |
|
15 | 15 | #include "access/sysattr.h"
|
16 | 16 | #include "optimizer/restrictinfo.h"
|
| 17 | +#include "optimizer/tlist.h" |
17 | 18 | #include "optimizer/var.h"
|
18 | 19 | #include "rewrite/rewriteManip.h"
|
19 | 20 | #include "utils/memutils.h"
|
@@ -123,40 +124,91 @@ select_required_plans(HTAB *children_table, Oid *parts, int nparts, int *nres)
|
123 | 124 | return result;
|
124 | 125 | }
|
125 | 126 |
|
126 |
| -/* Replace 'varno' of child's Vars with the 'append_rel_rti' */ |
| 127 | +/* Adapt child's tlist for parent relation (change varnos and varattnos) */ |
127 | 128 | static List *
|
128 |
| -replace_tlist_varnos(List *tlist, Index old_varno, Index new_varno) |
| 129 | +build_parent_tlist(List *tlist, AppendRelInfo *appinfo) |
129 | 130 | {
|
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; |
134 | 135 |
|
135 | 136 | 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); |
137 | 159 |
|
138 | 160 | return temp_tlist;
|
139 | 161 | }
|
140 | 162 |
|
| 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 | + |
141 | 183 | /* Append partition attribute in case it's not present in target list */
|
142 | 184 | 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) |
144 | 188 | {
|
145 | 189 | ListCell *lc;
|
| 190 | + AttrNumber part_attr; |
| 191 | + Var *part_attr_tvar; |
146 | 192 | bool part_attr_found = false;
|
147 | 193 |
|
| 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 | + |
148 | 200 | foreach (lc, tlist)
|
149 | 201 | {
|
150 | 202 | TargetEntry *te = (TargetEntry *) lfirst(lc);
|
151 | 203 | Var *var = (Var *) te->expr;
|
152 | 204 |
|
153 |
| - if (IsA(var, Var) && var->varoattno == prel->attnum) |
| 205 | + if (IsA(var, Var) && var->varoattno == part_attr) |
154 | 206 | part_attr_found = true;
|
155 | 207 | }
|
156 | 208 |
|
157 | 209 | if (!part_attr_found)
|
158 | 210 | {
|
159 |
| - Var *newvar = makeVar(relno, |
| 211 | + Var *newvar = makeVar(appinfo->child_relid, |
160 | 212 | prel->attnum,
|
161 | 213 | prel->atttype,
|
162 | 214 | prel->atttypmod,
|
@@ -450,28 +502,40 @@ create_append_plan_common(PlannerInfo *root, RelOptInfo *rel,
|
450 | 502 | {
|
451 | 503 | Plan *child_plan = (Plan *) lfirst(lc2);
|
452 | 504 | RelOptInfo *child_rel = ((Path *) lfirst(lc1))->parent;
|
| 505 | + AppendRelInfo *appinfo = find_childrel_appendrelinfo(root, child_rel); |
453 | 506 |
|
454 | 507 | /* Replace rel's tlist with a matching one (for ExecQual()) */
|
455 | 508 | if (!processed_rel_tlist)
|
456 | 509 | {
|
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; |
460 | 526 |
|
461 | 527 | /* Done, new target list has been built */
|
462 | 528 | processed_rel_tlist = true;
|
463 | 529 | }
|
464 | 530 |
|
465 | 531 | /* Add partition attribute if necessary (for ExecQual()) */
|
466 | 532 | child_plan->targetlist = append_part_attr_to_tlist(child_plan->targetlist,
|
467 |
| - child_rel->relid, |
468 |
| - prel); |
| 533 | + appinfo, prel); |
469 | 534 |
|
470 | 535 | /* Now make custom_scan_tlist match child plans' targetlists */
|
471 | 536 | 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); |
475 | 539 | }
|
476 | 540 | }
|
477 | 541 |
|
|
0 commit comments