00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include "postgres.h"
00030
00031 #include <limits.h>
00032
00033 #include "access/heapam.h"
00034 #include "access/htup_details.h"
00035 #include "access/sysattr.h"
00036 #include "catalog/pg_inherits_fn.h"
00037 #include "catalog/pg_type.h"
00038 #include "miscadmin.h"
00039 #include "nodes/makefuncs.h"
00040 #include "nodes/nodeFuncs.h"
00041 #include "optimizer/cost.h"
00042 #include "optimizer/pathnode.h"
00043 #include "optimizer/planmain.h"
00044 #include "optimizer/planner.h"
00045 #include "optimizer/prep.h"
00046 #include "optimizer/tlist.h"
00047 #include "parser/parse_coerce.h"
00048 #include "parser/parsetree.h"
00049 #include "utils/lsyscache.h"
00050 #include "utils/rel.h"
00051 #include "utils/selfuncs.h"
00052
00053
00054 typedef struct
00055 {
00056 PlannerInfo *root;
00057 AppendRelInfo *appinfo;
00058 } adjust_appendrel_attrs_context;
00059
00060 static Plan *recurse_set_operations(Node *setOp, PlannerInfo *root,
00061 double tuple_fraction,
00062 List *colTypes, List *colCollations,
00063 bool junkOK,
00064 int flag, List *refnames_tlist,
00065 List **sortClauses, double *pNumGroups);
00066 static Plan *generate_recursion_plan(SetOperationStmt *setOp,
00067 PlannerInfo *root, double tuple_fraction,
00068 List *refnames_tlist,
00069 List **sortClauses);
00070 static Plan *generate_union_plan(SetOperationStmt *op, PlannerInfo *root,
00071 double tuple_fraction,
00072 List *refnames_tlist,
00073 List **sortClauses, double *pNumGroups);
00074 static Plan *generate_nonunion_plan(SetOperationStmt *op, PlannerInfo *root,
00075 double tuple_fraction,
00076 List *refnames_tlist,
00077 List **sortClauses, double *pNumGroups);
00078 static List *recurse_union_children(Node *setOp, PlannerInfo *root,
00079 double tuple_fraction,
00080 SetOperationStmt *top_union,
00081 List *refnames_tlist);
00082 static Plan *make_union_unique(SetOperationStmt *op, Plan *plan,
00083 PlannerInfo *root, double tuple_fraction,
00084 List **sortClauses);
00085 static bool choose_hashed_setop(PlannerInfo *root, List *groupClauses,
00086 Plan *input_plan,
00087 double dNumGroups, double dNumOutputRows,
00088 double tuple_fraction,
00089 const char *construct);
00090 static List *generate_setop_tlist(List *colTypes, List *colCollations,
00091 int flag,
00092 Index varno,
00093 bool hack_constants,
00094 List *input_tlist,
00095 List *refnames_tlist);
00096 static List *generate_append_tlist(List *colTypes, List *colCollations,
00097 bool flag,
00098 List *input_plans,
00099 List *refnames_tlist);
00100 static List *generate_setop_grouplist(SetOperationStmt *op, List *targetlist);
00101 static void expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte,
00102 Index rti);
00103 static void make_inh_translation_list(Relation oldrelation,
00104 Relation newrelation,
00105 Index newvarno,
00106 List **translated_vars);
00107 static Bitmapset *translate_col_privs(const Bitmapset *parent_privs,
00108 List *translated_vars);
00109 static Node *adjust_appendrel_attrs_mutator(Node *node,
00110 adjust_appendrel_attrs_context *context);
00111 static Relids adjust_relid_set(Relids relids, Index oldrelid, Index newrelid);
00112 static List *adjust_inherited_tlist(List *tlist,
00113 AppendRelInfo *context);
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134 Plan *
00135 plan_set_operations(PlannerInfo *root, double tuple_fraction,
00136 List **sortClauses)
00137 {
00138 Query *parse = root->parse;
00139 SetOperationStmt *topop = (SetOperationStmt *) parse->setOperations;
00140 Node *node;
00141 RangeTblEntry *leftmostRTE;
00142 Query *leftmostQuery;
00143
00144 Assert(topop && IsA(topop, SetOperationStmt));
00145
00146
00147 Assert(parse->jointree->fromlist == NIL);
00148 Assert(parse->jointree->quals == NULL);
00149 Assert(parse->groupClause == NIL);
00150 Assert(parse->havingQual == NULL);
00151 Assert(parse->windowClause == NIL);
00152 Assert(parse->distinctClause == NIL);
00153
00154
00155
00156
00157
00158
00159 setup_simple_rel_arrays(root);
00160
00161
00162
00163
00164
00165 node = topop->larg;
00166 while (node && IsA(node, SetOperationStmt))
00167 node = ((SetOperationStmt *) node)->larg;
00168 Assert(node && IsA(node, RangeTblRef));
00169 leftmostRTE = root->simple_rte_array[((RangeTblRef *) node)->rtindex];
00170 leftmostQuery = leftmostRTE->subquery;
00171 Assert(leftmostQuery != NULL);
00172
00173
00174
00175
00176 if (root->hasRecursion)
00177 return generate_recursion_plan(topop, root, tuple_fraction,
00178 leftmostQuery->targetList,
00179 sortClauses);
00180
00181
00182
00183
00184
00185
00186
00187 return recurse_set_operations((Node *) topop, root, tuple_fraction,
00188 topop->colTypes, topop->colCollations,
00189 true, -1,
00190 leftmostQuery->targetList,
00191 sortClauses, NULL);
00192 }
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214 static Plan *
00215 recurse_set_operations(Node *setOp, PlannerInfo *root,
00216 double tuple_fraction,
00217 List *colTypes, List *colCollations,
00218 bool junkOK,
00219 int flag, List *refnames_tlist,
00220 List **sortClauses, double *pNumGroups)
00221 {
00222 if (IsA(setOp, RangeTblRef))
00223 {
00224 RangeTblRef *rtr = (RangeTblRef *) setOp;
00225 RangeTblEntry *rte = root->simple_rte_array[rtr->rtindex];
00226 Query *subquery = rte->subquery;
00227 RelOptInfo *rel;
00228 PlannerInfo *subroot;
00229 Plan *subplan,
00230 *plan;
00231
00232 Assert(subquery != NULL);
00233
00234
00235
00236
00237
00238
00239 rel = build_simple_rel(root, rtr->rtindex, RELOPT_BASEREL);
00240
00241
00242 Assert(root->plan_params == NIL);
00243
00244
00245
00246
00247 subplan = subquery_planner(root->glob, subquery,
00248 root,
00249 false, tuple_fraction,
00250 &subroot);
00251
00252
00253 rel->subplan = subplan;
00254 rel->subroot = subroot;
00255
00256
00257
00258
00259
00260 if (root->plan_params)
00261 elog(ERROR, "unexpected outer reference in set operation subquery");
00262
00263
00264
00265
00266
00267
00268 if (pNumGroups)
00269 {
00270 if (subquery->groupClause || subquery->distinctClause ||
00271 subroot->hasHavingQual || subquery->hasAggs)
00272 *pNumGroups = subplan->plan_rows;
00273 else
00274 *pNumGroups = estimate_num_groups(subroot,
00275 get_tlist_exprs(subquery->targetList, false),
00276 subplan->plan_rows);
00277 }
00278
00279
00280
00281
00282 plan = (Plan *)
00283 make_subqueryscan(generate_setop_tlist(colTypes, colCollations,
00284 flag,
00285 rtr->rtindex,
00286 true,
00287 subplan->targetlist,
00288 refnames_tlist),
00289 NIL,
00290 rtr->rtindex,
00291 subplan);
00292
00293
00294
00295
00296
00297 *sortClauses = NIL;
00298
00299 return plan;
00300 }
00301 else if (IsA(setOp, SetOperationStmt))
00302 {
00303 SetOperationStmt *op = (SetOperationStmt *) setOp;
00304 Plan *plan;
00305
00306
00307 if (op->op == SETOP_UNION)
00308 plan = generate_union_plan(op, root, tuple_fraction,
00309 refnames_tlist,
00310 sortClauses, pNumGroups);
00311 else
00312 plan = generate_nonunion_plan(op, root, tuple_fraction,
00313 refnames_tlist,
00314 sortClauses, pNumGroups);
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329 if (flag >= 0 ||
00330 !tlist_same_datatypes(plan->targetlist, colTypes, junkOK) ||
00331 !tlist_same_collations(plan->targetlist, colCollations, junkOK))
00332 {
00333 plan = (Plan *)
00334 make_result(root,
00335 generate_setop_tlist(colTypes, colCollations,
00336 flag,
00337 0,
00338 false,
00339 plan->targetlist,
00340 refnames_tlist),
00341 NULL,
00342 plan);
00343 }
00344 return plan;
00345 }
00346 else
00347 {
00348 elog(ERROR, "unrecognized node type: %d",
00349 (int) nodeTag(setOp));
00350 return NULL;
00351 }
00352 }
00353
00354
00355
00356
00357 static Plan *
00358 generate_recursion_plan(SetOperationStmt *setOp, PlannerInfo *root,
00359 double tuple_fraction,
00360 List *refnames_tlist,
00361 List **sortClauses)
00362 {
00363 Plan *plan;
00364 Plan *lplan;
00365 Plan *rplan;
00366 List *tlist;
00367 List *groupList;
00368 long numGroups;
00369
00370
00371 if (setOp->op != SETOP_UNION)
00372 elog(ERROR, "only UNION queries can be recursive");
00373
00374 Assert(root->wt_param_id >= 0);
00375
00376
00377
00378
00379
00380 lplan = recurse_set_operations(setOp->larg, root, tuple_fraction,
00381 setOp->colTypes, setOp->colCollations,
00382 false, -1,
00383 refnames_tlist, sortClauses, NULL);
00384
00385 root->non_recursive_plan = lplan;
00386 rplan = recurse_set_operations(setOp->rarg, root, tuple_fraction,
00387 setOp->colTypes, setOp->colCollations,
00388 false, -1,
00389 refnames_tlist, sortClauses, NULL);
00390 root->non_recursive_plan = NULL;
00391
00392
00393
00394
00395 tlist = generate_append_tlist(setOp->colTypes, setOp->colCollations, false,
00396 list_make2(lplan, rplan),
00397 refnames_tlist);
00398
00399
00400
00401
00402 if (setOp->all)
00403 {
00404 groupList = NIL;
00405 numGroups = 0;
00406 }
00407 else
00408 {
00409 double dNumGroups;
00410
00411
00412 groupList = generate_setop_grouplist(setOp, tlist);
00413
00414
00415 if (!grouping_is_hashable(groupList))
00416 ereport(ERROR,
00417 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00418 errmsg("could not implement recursive UNION"),
00419 errdetail("All column datatypes must be hashable.")));
00420
00421
00422
00423
00424
00425 dNumGroups = lplan->plan_rows + rplan->plan_rows * 10;
00426
00427
00428 numGroups = (long) Min(dNumGroups, (double) LONG_MAX);
00429 }
00430
00431
00432
00433
00434 plan = (Plan *) make_recursive_union(tlist, lplan, rplan,
00435 root->wt_param_id,
00436 groupList, numGroups);
00437
00438 *sortClauses = NIL;
00439
00440 return plan;
00441 }
00442
00443
00444
00445
00446 static Plan *
00447 generate_union_plan(SetOperationStmt *op, PlannerInfo *root,
00448 double tuple_fraction,
00449 List *refnames_tlist,
00450 List **sortClauses, double *pNumGroups)
00451 {
00452 List *planlist;
00453 List *tlist;
00454 Plan *plan;
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467 if (!op->all)
00468 tuple_fraction = 0.0;
00469
00470
00471
00472
00473
00474
00475
00476 planlist = list_concat(recurse_union_children(op->larg, root,
00477 tuple_fraction,
00478 op, refnames_tlist),
00479 recurse_union_children(op->rarg, root,
00480 tuple_fraction,
00481 op, refnames_tlist));
00482
00483
00484
00485
00486
00487
00488
00489
00490 tlist = generate_append_tlist(op->colTypes, op->colCollations, false,
00491 planlist, refnames_tlist);
00492
00493
00494
00495
00496 plan = (Plan *) make_append(planlist, tlist);
00497
00498
00499
00500
00501
00502 if (op->all)
00503 *sortClauses = NIL;
00504 else
00505 plan = make_union_unique(op, plan, root, tuple_fraction, sortClauses);
00506
00507
00508
00509
00510
00511
00512 if (pNumGroups)
00513 *pNumGroups = plan->plan_rows;
00514
00515 return plan;
00516 }
00517
00518
00519
00520
00521 static Plan *
00522 generate_nonunion_plan(SetOperationStmt *op, PlannerInfo *root,
00523 double tuple_fraction,
00524 List *refnames_tlist,
00525 List **sortClauses, double *pNumGroups)
00526 {
00527 Plan *lplan,
00528 *rplan,
00529 *plan;
00530 List *tlist,
00531 *groupList,
00532 *planlist,
00533 *child_sortclauses;
00534 double dLeftGroups,
00535 dRightGroups,
00536 dNumGroups,
00537 dNumOutputRows;
00538 long numGroups;
00539 bool use_hash;
00540 SetOpCmd cmd;
00541 int firstFlag;
00542
00543
00544 lplan = recurse_set_operations(op->larg, root,
00545 0.0 ,
00546 op->colTypes, op->colCollations,
00547 false, 0,
00548 refnames_tlist,
00549 &child_sortclauses, &dLeftGroups);
00550 rplan = recurse_set_operations(op->rarg, root,
00551 0.0 ,
00552 op->colTypes, op->colCollations,
00553 false, 1,
00554 refnames_tlist,
00555 &child_sortclauses, &dRightGroups);
00556
00557
00558
00559
00560
00561
00562
00563 if (op->op == SETOP_EXCEPT || dLeftGroups <= dRightGroups)
00564 {
00565 planlist = list_make2(lplan, rplan);
00566 firstFlag = 0;
00567 }
00568 else
00569 {
00570 planlist = list_make2(rplan, lplan);
00571 firstFlag = 1;
00572 }
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583 tlist = generate_append_tlist(op->colTypes, op->colCollations, true,
00584 planlist, refnames_tlist);
00585
00586
00587
00588
00589 plan = (Plan *) make_append(planlist, tlist);
00590
00591
00592 groupList = generate_setop_grouplist(op, tlist);
00593
00594
00595 if (groupList == NIL)
00596 {
00597 *sortClauses = NIL;
00598 return plan;
00599 }
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609 if (op->op == SETOP_EXCEPT)
00610 {
00611 dNumGroups = dLeftGroups;
00612 dNumOutputRows = op->all ? lplan->plan_rows : dNumGroups;
00613 }
00614 else
00615 {
00616 dNumGroups = Min(dLeftGroups, dRightGroups);
00617 dNumOutputRows = op->all ? Min(lplan->plan_rows, rplan->plan_rows) : dNumGroups;
00618 }
00619
00620
00621 numGroups = (long) Min(dNumGroups, (double) LONG_MAX);
00622
00623
00624
00625
00626 use_hash = choose_hashed_setop(root, groupList, plan,
00627 dNumGroups, dNumOutputRows, tuple_fraction,
00628 (op->op == SETOP_INTERSECT) ? "INTERSECT" : "EXCEPT");
00629
00630 if (!use_hash)
00631 plan = (Plan *) make_sort_from_sortclauses(root, groupList, plan);
00632
00633
00634
00635
00636 switch (op->op)
00637 {
00638 case SETOP_INTERSECT:
00639 cmd = op->all ? SETOPCMD_INTERSECT_ALL : SETOPCMD_INTERSECT;
00640 break;
00641 case SETOP_EXCEPT:
00642 cmd = op->all ? SETOPCMD_EXCEPT_ALL : SETOPCMD_EXCEPT;
00643 break;
00644 default:
00645 elog(ERROR, "unrecognized set op: %d", (int) op->op);
00646 cmd = SETOPCMD_INTERSECT;
00647 break;
00648 }
00649 plan = (Plan *) make_setop(cmd, use_hash ? SETOP_HASHED : SETOP_SORTED,
00650 plan, groupList,
00651 list_length(op->colTypes) + 1,
00652 use_hash ? firstFlag : -1,
00653 numGroups, dNumOutputRows);
00654
00655
00656 *sortClauses = use_hash ? NIL : groupList;
00657
00658 if (pNumGroups)
00659 *pNumGroups = dNumGroups;
00660
00661 return plan;
00662 }
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677 static List *
00678 recurse_union_children(Node *setOp, PlannerInfo *root,
00679 double tuple_fraction,
00680 SetOperationStmt *top_union,
00681 List *refnames_tlist)
00682 {
00683 List *child_sortclauses;
00684
00685 if (IsA(setOp, SetOperationStmt))
00686 {
00687 SetOperationStmt *op = (SetOperationStmt *) setOp;
00688
00689 if (op->op == top_union->op &&
00690 (op->all == top_union->all || op->all) &&
00691 equal(op->colTypes, top_union->colTypes))
00692 {
00693
00694 return list_concat(recurse_union_children(op->larg, root,
00695 tuple_fraction,
00696 top_union,
00697 refnames_tlist),
00698 recurse_union_children(op->rarg, root,
00699 tuple_fraction,
00700 top_union,
00701 refnames_tlist));
00702 }
00703 }
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714 return list_make1(recurse_set_operations(setOp, root,
00715 tuple_fraction,
00716 top_union->colTypes,
00717 top_union->colCollations,
00718 false, -1,
00719 refnames_tlist,
00720 &child_sortclauses, NULL));
00721 }
00722
00723
00724
00725
00726 static Plan *
00727 make_union_unique(SetOperationStmt *op, Plan *plan,
00728 PlannerInfo *root, double tuple_fraction,
00729 List **sortClauses)
00730 {
00731 List *groupList;
00732 double dNumGroups;
00733 long numGroups;
00734
00735
00736 groupList = generate_setop_grouplist(op, plan->targetlist);
00737
00738
00739 if (groupList == NIL)
00740 {
00741 *sortClauses = NIL;
00742 return plan;
00743 }
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753 dNumGroups = plan->plan_rows;
00754
00755
00756 numGroups = (long) Min(dNumGroups, (double) LONG_MAX);
00757
00758
00759 if (choose_hashed_setop(root, groupList, plan,
00760 dNumGroups, dNumGroups, tuple_fraction,
00761 "UNION"))
00762 {
00763
00764 plan = (Plan *) make_agg(root,
00765 plan->targetlist,
00766 NIL,
00767 AGG_HASHED,
00768 NULL,
00769 list_length(groupList),
00770 extract_grouping_cols(groupList,
00771 plan->targetlist),
00772 extract_grouping_ops(groupList),
00773 numGroups,
00774 plan);
00775
00776 *sortClauses = NIL;
00777 }
00778 else
00779 {
00780
00781 plan = (Plan *) make_sort_from_sortclauses(root, groupList, plan);
00782 plan = (Plan *) make_unique(plan, groupList);
00783 plan->plan_rows = dNumGroups;
00784
00785 *sortClauses = groupList;
00786 }
00787
00788 return plan;
00789 }
00790
00791
00792
00793
00794 static bool
00795 choose_hashed_setop(PlannerInfo *root, List *groupClauses,
00796 Plan *input_plan,
00797 double dNumGroups, double dNumOutputRows,
00798 double tuple_fraction,
00799 const char *construct)
00800 {
00801 int numGroupCols = list_length(groupClauses);
00802 bool can_sort;
00803 bool can_hash;
00804 Size hashentrysize;
00805 Path hashed_p;
00806 Path sorted_p;
00807
00808
00809 can_sort = grouping_is_sortable(groupClauses);
00810 can_hash = grouping_is_hashable(groupClauses);
00811 if (can_hash && can_sort)
00812 {
00813
00814 }
00815 else if (can_hash)
00816 return true;
00817 else if (can_sort)
00818 return false;
00819 else
00820 ereport(ERROR,
00821 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00822
00823 errmsg("could not implement %s", construct),
00824 errdetail("Some of the datatypes only support hashing, while others only support sorting.")));
00825
00826
00827 if (!enable_hashagg)
00828 return false;
00829
00830
00831
00832
00833
00834 hashentrysize = MAXALIGN(input_plan->plan_width) + MAXALIGN(sizeof(MinimalTupleData));
00835
00836 if (hashentrysize * dNumGroups > work_mem * 1024L)
00837 return false;
00838
00839
00840
00841
00842
00843
00844
00845
00846
00847
00848
00849
00850 cost_agg(&hashed_p, root, AGG_HASHED, NULL,
00851 numGroupCols, dNumGroups,
00852 input_plan->startup_cost, input_plan->total_cost,
00853 input_plan->plan_rows);
00854
00855
00856
00857
00858
00859 sorted_p.startup_cost = input_plan->startup_cost;
00860 sorted_p.total_cost = input_plan->total_cost;
00861
00862 cost_sort(&sorted_p, root, NIL, sorted_p.total_cost,
00863 input_plan->plan_rows, input_plan->plan_width,
00864 0.0, work_mem, -1.0);
00865 cost_group(&sorted_p, root, numGroupCols, dNumGroups,
00866 sorted_p.startup_cost, sorted_p.total_cost,
00867 input_plan->plan_rows);
00868
00869
00870
00871
00872
00873 if (tuple_fraction >= 1.0)
00874 tuple_fraction /= dNumOutputRows;
00875
00876 if (compare_fractional_path_costs(&hashed_p, &sorted_p,
00877 tuple_fraction) < 0)
00878 {
00879
00880 return true;
00881 }
00882 return false;
00883 }
00884
00885
00886
00887
00888
00889
00890
00891
00892
00893
00894
00895
00896 static List *
00897 generate_setop_tlist(List *colTypes, List *colCollations,
00898 int flag,
00899 Index varno,
00900 bool hack_constants,
00901 List *input_tlist,
00902 List *refnames_tlist)
00903 {
00904 List *tlist = NIL;
00905 int resno = 1;
00906 ListCell *ctlc,
00907 *cclc,
00908 *itlc,
00909 *rtlc;
00910 TargetEntry *tle;
00911 Node *expr;
00912
00913
00914 rtlc = list_head(refnames_tlist);
00915 forthree(ctlc, colTypes, cclc, colCollations, itlc, input_tlist)
00916 {
00917 Oid colType = lfirst_oid(ctlc);
00918 Oid colColl = lfirst_oid(cclc);
00919 TargetEntry *inputtle = (TargetEntry *) lfirst(itlc);
00920 TargetEntry *reftle = (TargetEntry *) lfirst(rtlc);
00921
00922 rtlc = lnext(rtlc);
00923
00924 Assert(inputtle->resno == resno);
00925 Assert(reftle->resno == resno);
00926 Assert(!inputtle->resjunk);
00927 Assert(!reftle->resjunk);
00928
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942 if (hack_constants && inputtle->expr && IsA(inputtle->expr, Const))
00943 expr = (Node *) inputtle->expr;
00944 else
00945 expr = (Node *) makeVar(varno,
00946 inputtle->resno,
00947 exprType((Node *) inputtle->expr),
00948 exprTypmod((Node *) inputtle->expr),
00949 exprCollation((Node *) inputtle->expr),
00950 0);
00951
00952 if (exprType(expr) != colType)
00953 {
00954
00955
00956
00957
00958
00959
00960
00961
00962 expr = coerce_to_common_type(NULL,
00963 expr,
00964 colType,
00965 "UNION/INTERSECT/EXCEPT");
00966 }
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979 if (exprCollation(expr) != colColl)
00980 {
00981 expr = (Node *) makeRelabelType((Expr *) expr,
00982 exprType(expr),
00983 exprTypmod(expr),
00984 colColl,
00985 COERCE_IMPLICIT_CAST);
00986 }
00987
00988 tle = makeTargetEntry((Expr *) expr,
00989 (AttrNumber) resno++,
00990 pstrdup(reftle->resname),
00991 false);
00992 tlist = lappend(tlist, tle);
00993 }
00994
00995 if (flag >= 0)
00996 {
00997
00998
00999 expr = (Node *) makeConst(INT4OID,
01000 -1,
01001 InvalidOid,
01002 sizeof(int32),
01003 Int32GetDatum(flag),
01004 false,
01005 true);
01006 tle = makeTargetEntry((Expr *) expr,
01007 (AttrNumber) resno++,
01008 pstrdup("flag"),
01009 true);
01010 tlist = lappend(tlist, tle);
01011 }
01012
01013 return tlist;
01014 }
01015
01016
01017
01018
01019
01020
01021
01022
01023
01024
01025
01026
01027
01028
01029 static List *
01030 generate_append_tlist(List *colTypes, List *colCollations,
01031 bool flag,
01032 List *input_plans,
01033 List *refnames_tlist)
01034 {
01035 List *tlist = NIL;
01036 int resno = 1;
01037 ListCell *curColType;
01038 ListCell *curColCollation;
01039 ListCell *ref_tl_item;
01040 int colindex;
01041 TargetEntry *tle;
01042 Node *expr;
01043 ListCell *planl;
01044 int32 *colTypmods;
01045
01046
01047
01048
01049
01050
01051
01052 colTypmods = (int32 *) palloc(list_length(colTypes) * sizeof(int32));
01053
01054 foreach(planl, input_plans)
01055 {
01056 Plan *subplan = (Plan *) lfirst(planl);
01057 ListCell *subtlist;
01058
01059 curColType = list_head(colTypes);
01060 colindex = 0;
01061 foreach(subtlist, subplan->targetlist)
01062 {
01063 TargetEntry *subtle = (TargetEntry *) lfirst(subtlist);
01064
01065 if (subtle->resjunk)
01066 continue;
01067 Assert(curColType != NULL);
01068 if (exprType((Node *) subtle->expr) == lfirst_oid(curColType))
01069 {
01070
01071 int32 subtypmod = exprTypmod((Node *) subtle->expr);
01072
01073 if (planl == list_head(input_plans))
01074 colTypmods[colindex] = subtypmod;
01075 else if (subtypmod != colTypmods[colindex])
01076 colTypmods[colindex] = -1;
01077 }
01078 else
01079 {
01080
01081 colTypmods[colindex] = -1;
01082 }
01083 curColType = lnext(curColType);
01084 colindex++;
01085 }
01086 Assert(curColType == NULL);
01087 }
01088
01089
01090
01091
01092 colindex = 0;
01093 forthree(curColType, colTypes, curColCollation, colCollations,
01094 ref_tl_item, refnames_tlist)
01095 {
01096 Oid colType = lfirst_oid(curColType);
01097 int32 colTypmod = colTypmods[colindex++];
01098 Oid colColl = lfirst_oid(curColCollation);
01099 TargetEntry *reftle = (TargetEntry *) lfirst(ref_tl_item);
01100
01101 Assert(reftle->resno == resno);
01102 Assert(!reftle->resjunk);
01103 expr = (Node *) makeVar(0,
01104 resno,
01105 colType,
01106 colTypmod,
01107 colColl,
01108 0);
01109 tle = makeTargetEntry((Expr *) expr,
01110 (AttrNumber) resno++,
01111 pstrdup(reftle->resname),
01112 false);
01113 tlist = lappend(tlist, tle);
01114 }
01115
01116 if (flag)
01117 {
01118
01119
01120 expr = (Node *) makeVar(0,
01121 resno,
01122 INT4OID,
01123 -1,
01124 InvalidOid,
01125 0);
01126 tle = makeTargetEntry((Expr *) expr,
01127 (AttrNumber) resno++,
01128 pstrdup("flag"),
01129 true);
01130 tlist = lappend(tlist, tle);
01131 }
01132
01133 pfree(colTypmods);
01134
01135 return tlist;
01136 }
01137
01138
01139
01140
01141
01142
01143
01144
01145
01146
01147
01148
01149 static List *
01150 generate_setop_grouplist(SetOperationStmt *op, List *targetlist)
01151 {
01152 List *grouplist = (List *) copyObject(op->groupClauses);
01153 ListCell *lg;
01154 ListCell *lt;
01155 Index refno = 1;
01156
01157 lg = list_head(grouplist);
01158 foreach(lt, targetlist)
01159 {
01160 TargetEntry *tle = (TargetEntry *) lfirst(lt);
01161 SortGroupClause *sgc;
01162
01163
01164 Assert(tle->ressortgroupref == 0);
01165
01166 if (tle->resjunk)
01167 continue;
01168
01169
01170 Assert(lg != NULL);
01171 sgc = (SortGroupClause *) lfirst(lg);
01172 lg = lnext(lg);
01173 Assert(sgc->tleSortGroupRef == 0);
01174
01175
01176 sgc->tleSortGroupRef = tle->ressortgroupref = refno++;
01177 }
01178 Assert(lg == NULL);
01179 return grouplist;
01180 }
01181
01182
01183
01184
01185
01186
01187
01188
01189
01190 void
01191 expand_inherited_tables(PlannerInfo *root)
01192 {
01193 Index nrtes;
01194 Index rti;
01195 ListCell *rl;
01196
01197
01198
01199
01200
01201
01202 nrtes = list_length(root->parse->rtable);
01203 rl = list_head(root->parse->rtable);
01204 for (rti = 1; rti <= nrtes; rti++)
01205 {
01206 RangeTblEntry *rte = (RangeTblEntry *) lfirst(rl);
01207
01208 expand_inherited_rtentry(root, rte, rti);
01209 rl = lnext(rl);
01210 }
01211 }
01212
01213
01214
01215
01216
01217
01218
01219
01220
01221
01222
01223
01224
01225
01226
01227
01228
01229 static void
01230 expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
01231 {
01232 Query *parse = root->parse;
01233 Oid parentOID;
01234 PlanRowMark *oldrc;
01235 Relation oldrelation;
01236 LOCKMODE lockmode;
01237 List *inhOIDs;
01238 List *appinfos;
01239 ListCell *l;
01240
01241
01242 if (!rte->inh)
01243 return;
01244
01245 if (rte->rtekind != RTE_RELATION)
01246 {
01247 Assert(rte->rtekind == RTE_SUBQUERY);
01248 return;
01249 }
01250
01251 parentOID = rte->relid;
01252 if (!has_subclass(parentOID))
01253 {
01254
01255 rte->inh = false;
01256 return;
01257 }
01258
01259
01260
01261
01262
01263
01264
01265
01266
01267
01268
01269
01270
01271
01272 oldrc = get_plan_rowmark(root->rowMarks, rti);
01273 if (rti == parse->resultRelation)
01274 lockmode = RowExclusiveLock;
01275 else if (oldrc && RowMarkRequiresRowShareLock(oldrc->markType))
01276 lockmode = RowShareLock;
01277 else
01278 lockmode = AccessShareLock;
01279
01280
01281 inhOIDs = find_all_inheritors(parentOID, lockmode, NULL);
01282
01283
01284
01285
01286
01287
01288 if (list_length(inhOIDs) < 2)
01289 {
01290
01291 rte->inh = false;
01292 return;
01293 }
01294
01295
01296
01297
01298
01299
01300 if (oldrc)
01301 oldrc->isParent = true;
01302
01303
01304
01305
01306
01307 oldrelation = heap_open(parentOID, NoLock);
01308
01309
01310 appinfos = NIL;
01311 foreach(l, inhOIDs)
01312 {
01313 Oid childOID = lfirst_oid(l);
01314 Relation newrelation;
01315 RangeTblEntry *childrte;
01316 Index childRTindex;
01317 AppendRelInfo *appinfo;
01318
01319
01320 if (childOID != parentOID)
01321 newrelation = heap_open(childOID, NoLock);
01322 else
01323 newrelation = oldrelation;
01324
01325
01326
01327
01328
01329
01330
01331 if (childOID != parentOID && RELATION_IS_OTHER_TEMP(newrelation))
01332 {
01333 heap_close(newrelation, lockmode);
01334 continue;
01335 }
01336
01337
01338
01339
01340
01341
01342
01343 childrte = copyObject(rte);
01344 childrte->relid = childOID;
01345 childrte->inh = false;
01346 childrte->requiredPerms = 0;
01347 parse->rtable = lappend(parse->rtable, childrte);
01348 childRTindex = list_length(parse->rtable);
01349
01350
01351
01352
01353 appinfo = makeNode(AppendRelInfo);
01354 appinfo->parent_relid = rti;
01355 appinfo->child_relid = childRTindex;
01356 appinfo->parent_reltype = oldrelation->rd_rel->reltype;
01357 appinfo->child_reltype = newrelation->rd_rel->reltype;
01358 make_inh_translation_list(oldrelation, newrelation, childRTindex,
01359 &appinfo->translated_vars);
01360 appinfo->parent_reloid = parentOID;
01361 appinfos = lappend(appinfos, appinfo);
01362
01363
01364
01365
01366
01367
01368
01369
01370
01371
01372 if (childOID != parentOID)
01373 {
01374 childrte->selectedCols = translate_col_privs(rte->selectedCols,
01375 appinfo->translated_vars);
01376 childrte->modifiedCols = translate_col_privs(rte->modifiedCols,
01377 appinfo->translated_vars);
01378 }
01379
01380
01381
01382
01383 if (oldrc)
01384 {
01385 PlanRowMark *newrc = makeNode(PlanRowMark);
01386
01387 newrc->rti = childRTindex;
01388 newrc->prti = rti;
01389 newrc->rowmarkId = oldrc->rowmarkId;
01390 newrc->markType = oldrc->markType;
01391 newrc->noWait = oldrc->noWait;
01392 newrc->isParent = false;
01393
01394 root->rowMarks = lappend(root->rowMarks, newrc);
01395 }
01396
01397
01398 if (childOID != parentOID)
01399 heap_close(newrelation, NoLock);
01400 }
01401
01402 heap_close(oldrelation, NoLock);
01403
01404
01405
01406
01407
01408
01409 if (list_length(appinfos) < 2)
01410 {
01411
01412 rte->inh = false;
01413 return;
01414 }
01415
01416
01417 root->append_rel_list = list_concat(root->append_rel_list, appinfos);
01418 }
01419
01420
01421
01422
01423
01424
01425
01426
01427 static void
01428 make_inh_translation_list(Relation oldrelation, Relation newrelation,
01429 Index newvarno,
01430 List **translated_vars)
01431 {
01432 List *vars = NIL;
01433 TupleDesc old_tupdesc = RelationGetDescr(oldrelation);
01434 TupleDesc new_tupdesc = RelationGetDescr(newrelation);
01435 int oldnatts = old_tupdesc->natts;
01436 int newnatts = new_tupdesc->natts;
01437 int old_attno;
01438
01439 for (old_attno = 0; old_attno < oldnatts; old_attno++)
01440 {
01441 Form_pg_attribute att;
01442 char *attname;
01443 Oid atttypid;
01444 int32 atttypmod;
01445 Oid attcollation;
01446 int new_attno;
01447
01448 att = old_tupdesc->attrs[old_attno];
01449 if (att->attisdropped)
01450 {
01451
01452 vars = lappend(vars, NULL);
01453 continue;
01454 }
01455 attname = NameStr(att->attname);
01456 atttypid = att->atttypid;
01457 atttypmod = att->atttypmod;
01458 attcollation = att->attcollation;
01459
01460
01461
01462
01463
01464 if (oldrelation == newrelation)
01465 {
01466 vars = lappend(vars, makeVar(newvarno,
01467 (AttrNumber) (old_attno + 1),
01468 atttypid,
01469 atttypmod,
01470 attcollation,
01471 0));
01472 continue;
01473 }
01474
01475
01476
01477
01478
01479
01480
01481
01482
01483
01484
01485 if (old_attno < newnatts &&
01486 (att = new_tupdesc->attrs[old_attno]) != NULL &&
01487 !att->attisdropped && att->attinhcount != 0 &&
01488 strcmp(attname, NameStr(att->attname)) == 0)
01489 new_attno = old_attno;
01490 else
01491 {
01492 for (new_attno = 0; new_attno < newnatts; new_attno++)
01493 {
01494 att = new_tupdesc->attrs[new_attno];
01495 if (!att->attisdropped && att->attinhcount != 0 &&
01496 strcmp(attname, NameStr(att->attname)) == 0)
01497 break;
01498 }
01499 if (new_attno >= newnatts)
01500 elog(ERROR, "could not find inherited attribute \"%s\" of relation \"%s\"",
01501 attname, RelationGetRelationName(newrelation));
01502 }
01503
01504
01505 if (atttypid != att->atttypid || atttypmod != att->atttypmod)
01506 elog(ERROR, "attribute \"%s\" of relation \"%s\" does not match parent's type",
01507 attname, RelationGetRelationName(newrelation));
01508 if (attcollation != att->attcollation)
01509 elog(ERROR, "attribute \"%s\" of relation \"%s\" does not match parent's collation",
01510 attname, RelationGetRelationName(newrelation));
01511
01512 vars = lappend(vars, makeVar(newvarno,
01513 (AttrNumber) (new_attno + 1),
01514 atttypid,
01515 atttypmod,
01516 attcollation,
01517 0));
01518 }
01519
01520 *translated_vars = vars;
01521 }
01522
01523
01524
01525
01526
01527
01528
01529
01530
01531
01532
01533
01534 static Bitmapset *
01535 translate_col_privs(const Bitmapset *parent_privs,
01536 List *translated_vars)
01537 {
01538 Bitmapset *child_privs = NULL;
01539 bool whole_row;
01540 int attno;
01541 ListCell *lc;
01542
01543
01544 for (attno = FirstLowInvalidHeapAttributeNumber + 1; attno < 0; attno++)
01545 {
01546 if (bms_is_member(attno - FirstLowInvalidHeapAttributeNumber,
01547 parent_privs))
01548 child_privs = bms_add_member(child_privs,
01549 attno - FirstLowInvalidHeapAttributeNumber);
01550 }
01551
01552
01553 whole_row = bms_is_member(InvalidAttrNumber - FirstLowInvalidHeapAttributeNumber,
01554 parent_privs);
01555
01556
01557 attno = InvalidAttrNumber;
01558 foreach(lc, translated_vars)
01559 {
01560 Var *var = (Var *) lfirst(lc);
01561
01562 attno++;
01563 if (var == NULL)
01564 continue;
01565 Assert(IsA(var, Var));
01566 if (whole_row ||
01567 bms_is_member(attno - FirstLowInvalidHeapAttributeNumber,
01568 parent_privs))
01569 child_privs = bms_add_member(child_privs,
01570 var->varattno - FirstLowInvalidHeapAttributeNumber);
01571 }
01572
01573 return child_privs;
01574 }
01575
01576
01577
01578
01579
01580
01581
01582
01583
01584
01585
01586
01587
01588
01589 Node *
01590 adjust_appendrel_attrs(PlannerInfo *root, Node *node, AppendRelInfo *appinfo)
01591 {
01592 Node *result;
01593 adjust_appendrel_attrs_context context;
01594
01595 context.root = root;
01596 context.appinfo = appinfo;
01597
01598
01599
01600
01601 if (node && IsA(node, Query))
01602 {
01603 Query *newnode;
01604
01605 newnode = query_tree_mutator((Query *) node,
01606 adjust_appendrel_attrs_mutator,
01607 (void *) &context,
01608 QTW_IGNORE_RC_SUBQUERIES);
01609 if (newnode->resultRelation == appinfo->parent_relid)
01610 {
01611 newnode->resultRelation = appinfo->child_relid;
01612
01613 if (newnode->commandType == CMD_UPDATE)
01614 newnode->targetList =
01615 adjust_inherited_tlist(newnode->targetList,
01616 appinfo);
01617 }
01618 result = (Node *) newnode;
01619 }
01620 else
01621 result = adjust_appendrel_attrs_mutator(node, &context);
01622
01623 return result;
01624 }
01625
01626 static Node *
01627 adjust_appendrel_attrs_mutator(Node *node,
01628 adjust_appendrel_attrs_context *context)
01629 {
01630 AppendRelInfo *appinfo = context->appinfo;
01631
01632 if (node == NULL)
01633 return NULL;
01634 if (IsA(node, Var))
01635 {
01636 Var *var = (Var *) copyObject(node);
01637
01638 if (var->varlevelsup == 0 &&
01639 var->varno == appinfo->parent_relid)
01640 {
01641 var->varno = appinfo->child_relid;
01642 var->varnoold = appinfo->child_relid;
01643 if (var->varattno > 0)
01644 {
01645 Node *newnode;
01646
01647 if (var->varattno > list_length(appinfo->translated_vars))
01648 elog(ERROR, "attribute %d of relation \"%s\" does not exist",
01649 var->varattno, get_rel_name(appinfo->parent_reloid));
01650 newnode = copyObject(list_nth(appinfo->translated_vars,
01651 var->varattno - 1));
01652 if (newnode == NULL)
01653 elog(ERROR, "attribute %d of relation \"%s\" does not exist",
01654 var->varattno, get_rel_name(appinfo->parent_reloid));
01655 return newnode;
01656 }
01657 else if (var->varattno == 0)
01658 {
01659
01660
01661
01662
01663
01664
01665 if (OidIsValid(appinfo->child_reltype))
01666 {
01667 Assert(var->vartype == appinfo->parent_reltype);
01668 if (appinfo->parent_reltype != appinfo->child_reltype)
01669 {
01670 ConvertRowtypeExpr *r = makeNode(ConvertRowtypeExpr);
01671
01672 r->arg = (Expr *) var;
01673 r->resulttype = appinfo->parent_reltype;
01674 r->convertformat = COERCE_IMPLICIT_CAST;
01675 r->location = -1;
01676
01677 var->vartype = appinfo->child_reltype;
01678 return (Node *) r;
01679 }
01680 }
01681 else
01682 {
01683
01684
01685
01686
01687
01688
01689
01690
01691
01692
01693
01694 RowExpr *rowexpr;
01695 List *fields;
01696 RangeTblEntry *rte;
01697
01698 rte = rt_fetch(appinfo->parent_relid,
01699 context->root->parse->rtable);
01700 fields = (List *) copyObject(appinfo->translated_vars);
01701 rowexpr = makeNode(RowExpr);
01702 rowexpr->args = fields;
01703 rowexpr->row_typeid = var->vartype;
01704 rowexpr->row_format = COERCE_IMPLICIT_CAST;
01705 rowexpr->colnames = copyObject(rte->eref->colnames);
01706 rowexpr->location = -1;
01707
01708 return (Node *) rowexpr;
01709 }
01710 }
01711
01712 }
01713 return (Node *) var;
01714 }
01715 if (IsA(node, CurrentOfExpr))
01716 {
01717 CurrentOfExpr *cexpr = (CurrentOfExpr *) copyObject(node);
01718
01719 if (cexpr->cvarno == appinfo->parent_relid)
01720 cexpr->cvarno = appinfo->child_relid;
01721 return (Node *) cexpr;
01722 }
01723 if (IsA(node, RangeTblRef))
01724 {
01725 RangeTblRef *rtr = (RangeTblRef *) copyObject(node);
01726
01727 if (rtr->rtindex == appinfo->parent_relid)
01728 rtr->rtindex = appinfo->child_relid;
01729 return (Node *) rtr;
01730 }
01731 if (IsA(node, JoinExpr))
01732 {
01733
01734 JoinExpr *j;
01735
01736 j = (JoinExpr *) expression_tree_mutator(node,
01737 adjust_appendrel_attrs_mutator,
01738 (void *) context);
01739
01740 if (j->rtindex == appinfo->parent_relid)
01741 j->rtindex = appinfo->child_relid;
01742 return (Node *) j;
01743 }
01744 if (IsA(node, PlaceHolderVar))
01745 {
01746
01747 PlaceHolderVar *phv;
01748
01749 phv = (PlaceHolderVar *) expression_tree_mutator(node,
01750 adjust_appendrel_attrs_mutator,
01751 (void *) context);
01752
01753 if (phv->phlevelsup == 0)
01754 phv->phrels = adjust_relid_set(phv->phrels,
01755 appinfo->parent_relid,
01756 appinfo->child_relid);
01757 return (Node *) phv;
01758 }
01759
01760 Assert(!IsA(node, SpecialJoinInfo));
01761 Assert(!IsA(node, LateralJoinInfo));
01762 Assert(!IsA(node, AppendRelInfo));
01763 Assert(!IsA(node, PlaceHolderInfo));
01764 Assert(!IsA(node, MinMaxAggInfo));
01765
01766
01767
01768
01769
01770
01771 if (IsA(node, RestrictInfo))
01772 {
01773 RestrictInfo *oldinfo = (RestrictInfo *) node;
01774 RestrictInfo *newinfo = makeNode(RestrictInfo);
01775
01776
01777 memcpy(newinfo, oldinfo, sizeof(RestrictInfo));
01778
01779
01780 newinfo->clause = (Expr *)
01781 adjust_appendrel_attrs_mutator((Node *) oldinfo->clause, context);
01782
01783
01784 newinfo->orclause = (Expr *)
01785 adjust_appendrel_attrs_mutator((Node *) oldinfo->orclause, context);
01786
01787
01788 newinfo->clause_relids = adjust_relid_set(oldinfo->clause_relids,
01789 appinfo->parent_relid,
01790 appinfo->child_relid);
01791 newinfo->required_relids = adjust_relid_set(oldinfo->required_relids,
01792 appinfo->parent_relid,
01793 appinfo->child_relid);
01794 newinfo->outer_relids = adjust_relid_set(oldinfo->outer_relids,
01795 appinfo->parent_relid,
01796 appinfo->child_relid);
01797 newinfo->nullable_relids = adjust_relid_set(oldinfo->nullable_relids,
01798 appinfo->parent_relid,
01799 appinfo->child_relid);
01800 newinfo->left_relids = adjust_relid_set(oldinfo->left_relids,
01801 appinfo->parent_relid,
01802 appinfo->child_relid);
01803 newinfo->right_relids = adjust_relid_set(oldinfo->right_relids,
01804 appinfo->parent_relid,
01805 appinfo->child_relid);
01806
01807
01808
01809
01810
01811
01812
01813 newinfo->eval_cost.startup = -1;
01814 newinfo->norm_selec = -1;
01815 newinfo->outer_selec = -1;
01816 newinfo->left_em = NULL;
01817 newinfo->right_em = NULL;
01818 newinfo->scansel_cache = NIL;
01819 newinfo->left_bucketsize = -1;
01820 newinfo->right_bucketsize = -1;
01821
01822 return (Node *) newinfo;
01823 }
01824
01825
01826
01827
01828
01829 Assert(!IsA(node, SubLink));
01830 Assert(!IsA(node, Query));
01831
01832 return expression_tree_mutator(node, adjust_appendrel_attrs_mutator,
01833 (void *) context);
01834 }
01835
01836
01837
01838
01839 static Relids
01840 adjust_relid_set(Relids relids, Index oldrelid, Index newrelid)
01841 {
01842 if (bms_is_member(oldrelid, relids))
01843 {
01844
01845 relids = bms_copy(relids);
01846
01847 relids = bms_del_member(relids, oldrelid);
01848 relids = bms_add_member(relids, newrelid);
01849 }
01850 return relids;
01851 }
01852
01853
01854
01855
01856
01857
01858
01859
01860
01861
01862
01863
01864
01865
01866
01867
01868
01869 static List *
01870 adjust_inherited_tlist(List *tlist, AppendRelInfo *context)
01871 {
01872 bool changed_it = false;
01873 ListCell *tl;
01874 List *new_tlist;
01875 bool more;
01876 int attrno;
01877
01878
01879 Assert(OidIsValid(context->parent_reloid));
01880
01881
01882 foreach(tl, tlist)
01883 {
01884 TargetEntry *tle = (TargetEntry *) lfirst(tl);
01885 Var *childvar;
01886
01887 if (tle->resjunk)
01888 continue;
01889
01890
01891 if (tle->resno <= 0 ||
01892 tle->resno > list_length(context->translated_vars))
01893 elog(ERROR, "attribute %d of relation \"%s\" does not exist",
01894 tle->resno, get_rel_name(context->parent_reloid));
01895 childvar = (Var *) list_nth(context->translated_vars, tle->resno - 1);
01896 if (childvar == NULL || !IsA(childvar, Var))
01897 elog(ERROR, "attribute %d of relation \"%s\" does not exist",
01898 tle->resno, get_rel_name(context->parent_reloid));
01899
01900 if (tle->resno != childvar->varattno)
01901 {
01902 tle->resno = childvar->varattno;
01903 changed_it = true;
01904 }
01905 }
01906
01907
01908
01909
01910
01911
01912
01913 if (!changed_it)
01914 return tlist;
01915
01916 new_tlist = NIL;
01917 more = true;
01918 for (attrno = 1; more; attrno++)
01919 {
01920 more = false;
01921 foreach(tl, tlist)
01922 {
01923 TargetEntry *tle = (TargetEntry *) lfirst(tl);
01924
01925 if (tle->resjunk)
01926 continue;
01927
01928 if (tle->resno == attrno)
01929 new_tlist = lappend(new_tlist, tle);
01930 else if (tle->resno > attrno)
01931 more = true;
01932 }
01933 }
01934
01935 foreach(tl, tlist)
01936 {
01937 TargetEntry *tle = (TargetEntry *) lfirst(tl);
01938
01939 if (!tle->resjunk)
01940 continue;
01941
01942 tle->resno = attrno;
01943 new_tlist = lappend(new_tlist, tle);
01944 attrno++;
01945 }
01946
01947 return new_tlist;
01948 }