diff options
Diffstat (limited to 'src/backend/optimizer/prep/prepunion.c')
-rw-r--r-- | src/backend/optimizer/prep/prepunion.c | 196 |
1 files changed, 105 insertions, 91 deletions
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c index 85058757e5e..968b9ded780 100644 --- a/src/backend/optimizer/prep/prepunion.c +++ b/src/backend/optimizer/prep/prepunion.c @@ -5,7 +5,7 @@ * from a time when only UNIONs were implemented. * * There is also some code here to support planning of queries that use - * inheritance (SELECT FROM foo*). This no longer has much connection + * inheritance (SELECT FROM foo*). This no longer has much connection * to the processing of UNION queries, but it's still here. * * @@ -14,7 +14,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.60 2001/01/24 19:42:59 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.61 2001/03/22 03:59:38 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -50,22 +50,22 @@ typedef struct } adjust_inherited_attrs_context; static Plan *recurse_set_operations(Node *setOp, Query *parse, - List *colTypes, bool junkOK, - int flag, List *refnames_tlist); + List *colTypes, bool junkOK, + int flag, List *refnames_tlist); static Plan *generate_union_plan(SetOperationStmt *op, Query *parse, - List *refnames_tlist); + List *refnames_tlist); static Plan *generate_nonunion_plan(SetOperationStmt *op, Query *parse, - List *refnames_tlist); + List *refnames_tlist); static List *recurse_union_children(Node *setOp, Query *parse, - SetOperationStmt *top_union, - List *refnames_tlist); + SetOperationStmt *top_union, + List *refnames_tlist); static List *generate_setop_tlist(List *colTypes, int flag, - bool hack_constants, - List *input_tlist, - List *refnames_tlist); + bool hack_constants, + List *input_tlist, + List *refnames_tlist); static bool tlist_same_datatypes(List *tlist, List *colTypes, bool junkOK); static Node *adjust_inherited_attrs_mutator(Node *node, - adjust_inherited_attrs_context *context); + adjust_inherited_attrs_context *context); /* @@ -99,10 +99,10 @@ plan_set_operations(Query *parse) Assert(leftmostQuery != NULL); /* - * Recurse on setOperations tree to generate plans for set ops. - * The final output plan should have just the column types shown - * as the output from the top-level node, plus possibly a resjunk - * working column (we can rely on upper-level nodes to deal with that). + * Recurse on setOperations tree to generate plans for set ops. The + * final output plan should have just the column types shown as the + * output from the top-level node, plus possibly a resjunk working + * column (we can rely on upper-level nodes to deal with that). */ return recurse_set_operations((Node *) topop, parse, topop->colTypes, true, -1, @@ -127,16 +127,18 @@ recurse_set_operations(Node *setOp, Query *parse, { RangeTblRef *rtr = (RangeTblRef *) setOp; RangeTblEntry *rte = rt_fetch(rtr->rtindex, parse->rtable); - Query *subquery = rte->subquery; - Plan *subplan, - *plan; + Query *subquery = rte->subquery; + Plan *subplan, + *plan; Assert(subquery != NULL); + /* * Generate plan for primitive subquery */ subplan = subquery_planner(subquery, -1.0 /* default case */ ); + /* * Add a SubqueryScan with the caller-requested targetlist */ @@ -152,28 +154,30 @@ recurse_set_operations(Node *setOp, Query *parse, else if (IsA(setOp, SetOperationStmt)) { SetOperationStmt *op = (SetOperationStmt *) setOp; - Plan *plan; + Plan *plan; /* UNIONs are much different from INTERSECT/EXCEPT */ if (op->op == SETOP_UNION) plan = generate_union_plan(op, parse, refnames_tlist); else plan = generate_nonunion_plan(op, parse, refnames_tlist); + /* * If necessary, add a Result node to project the caller-requested * output columns. * * XXX you don't really want to know about this: setrefs.c will apply * replace_vars_with_subplan_refs() to the Result node's tlist. - * This would fail if the input plan's non-resjunk tlist entries were - * not all simple Vars equal() to the referencing Vars generated by - * generate_setop_tlist(). However, since the input plan was - * generated by generate_union_plan() or generate_nonunion_plan(), - * the referencing Vars will equal the tlist entries they reference. - * Ugly but I don't feel like making that code more general right now. + * This would fail if the input plan's non-resjunk tlist entries + * were not all simple Vars equal() to the referencing Vars + * generated by generate_setop_tlist(). However, since the input + * plan was generated by generate_union_plan() or + * generate_nonunion_plan(), the referencing Vars will equal the + * tlist entries they reference. Ugly but I don't feel like making + * that code more general right now. */ if (flag >= 0 || - ! tlist_same_datatypes(plan->targetlist, colTypes, junkOK)) + !tlist_same_datatypes(plan->targetlist, colTypes, junkOK)) { plan = (Plan *) make_result(generate_setop_tlist(colTypes, flag, false, @@ -199,8 +203,8 @@ static Plan * generate_union_plan(SetOperationStmt *op, Query *parse, List *refnames_tlist) { - List *planlist; - Plan *plan; + List *planlist; + Plan *plan; /* * If any of my children are identical UNION nodes (same op, all-flag, @@ -212,27 +216,29 @@ generate_union_plan(SetOperationStmt *op, Query *parse, op, refnames_tlist), recurse_union_children(op->rarg, parse, op, refnames_tlist)); + /* * Append the child results together. * - * The tlist for an Append plan isn't important as far as the Append - * is concerned, but we must make it look real anyway for the benefit - * of the next plan level up. + * The tlist for an Append plan isn't important as far as the Append is + * concerned, but we must make it look real anyway for the benefit of + * the next plan level up. */ plan = (Plan *) make_append(planlist, false, generate_setop_tlist(op->colTypes, -1, false, - ((Plan *) lfirst(planlist))->targetlist, - refnames_tlist)); + ((Plan *) lfirst(planlist))->targetlist, + refnames_tlist)); + /* - * For UNION ALL, we just need the Append plan. For UNION, - * need to add Sort and Unique nodes to produce unique output. + * For UNION ALL, we just need the Append plan. For UNION, need to + * add Sort and Unique nodes to produce unique output. */ - if (! op->all) + if (!op->all) { - List *tlist, - *sortList; + List *tlist, + *sortList; tlist = new_unsorted_tlist(plan->targetlist); sortList = addAllTargetsToSortList(NIL, tlist); @@ -249,12 +255,12 @@ static Plan * generate_nonunion_plan(SetOperationStmt *op, Query *parse, List *refnames_tlist) { - Plan *lplan, - *rplan, - *plan; - List *tlist, - *sortList; - SetOpCmd cmd; + Plan *lplan, + *rplan, + *plan; + List *tlist, + *sortList; + SetOpCmd cmd; /* Recurse on children, ensuring their outputs are marked */ lplan = recurse_set_operations(op->larg, parse, @@ -263,12 +269,13 @@ generate_nonunion_plan(SetOperationStmt *op, Query *parse, rplan = recurse_set_operations(op->rarg, parse, op->colTypes, false, 1, refnames_tlist); + /* * Append the child results together. * - * The tlist for an Append plan isn't important as far as the Append - * is concerned, but we must make it look real anyway for the benefit - * of the next plan level up. + * The tlist for an Append plan isn't important as far as the Append is + * concerned, but we must make it look real anyway for the benefit of + * the next plan level up. */ plan = (Plan *) make_append(makeList2(lplan, rplan), @@ -276,9 +283,10 @@ generate_nonunion_plan(SetOperationStmt *op, Query *parse, generate_setop_tlist(op->colTypes, 0, false, lplan->targetlist, refnames_tlist)); + /* - * Sort the child results, then add a SetOp plan node to - * generate the correct output. + * Sort the child results, then add a SetOp plan node to generate the + * correct output. */ tlist = new_unsorted_tlist(plan->targetlist); sortList = addAllTargetsToSortList(NIL, tlist); @@ -293,11 +301,11 @@ generate_nonunion_plan(SetOperationStmt *op, Query *parse, break; default: elog(ERROR, "generate_nonunion_plan: bogus operation code"); - cmd = SETOPCMD_INTERSECT; /* keep compiler quiet */ + cmd = SETOPCMD_INTERSECT; /* keep compiler quiet */ break; } plan = (Plan *) make_setop(cmd, tlist, plan, sortList, - length(op->colTypes)+1); + length(op->colTypes) + 1); return plan; } @@ -322,20 +330,21 @@ recurse_union_children(Node *setOp, Query *parse, { /* Same UNION, so fold children into parent's subplan list */ return nconc(recurse_union_children(op->larg, parse, - top_union, refnames_tlist), + top_union, refnames_tlist), recurse_union_children(op->rarg, parse, - top_union, refnames_tlist)); + top_union, refnames_tlist)); } } + /* * Not same, so plan this child separately. * - * Note we disallow any resjunk columns in child results. This - * is necessary since the Append node that implements the union - * won't do any projection, and upper levels will get confused if - * some of our output tuples have junk and some don't. This case - * only arises when we have an EXCEPT or INTERSECT as child, else - * there won't be resjunk anyway. + * Note we disallow any resjunk columns in child results. This is + * necessary since the Append node that implements the union won't do + * any projection, and upper levels will get confused if some of our + * output tuples have junk and some don't. This case only arises when + * we have an EXCEPT or INTERSECT as child, else there won't be + * resjunk anyway. */ return makeList1(recurse_set_operations(setOp, parse, top_union->colTypes, false, @@ -359,7 +368,7 @@ generate_setop_tlist(List *colTypes, int flag, foreach(i, colTypes) { - Oid colType = (Oid) lfirsti(i); + Oid colType = (Oid) lfirsti(i); TargetEntry *inputtle = (TargetEntry *) lfirst(input_tlist); TargetEntry *reftle = (TargetEntry *) lfirst(refnames_tlist); @@ -367,18 +376,19 @@ generate_setop_tlist(List *colTypes, int flag, Assert(reftle->resdom->resno == resno); Assert(!inputtle->resdom->resjunk); Assert(!reftle->resdom->resjunk); + /* * Generate columns referencing input columns and having * appropriate data types and column names. Insert datatype * coercions where necessary. * * HACK: constants in the input's targetlist are copied up as-is - * rather than being referenced as subquery outputs. This is mainly - * to ensure that when we try to coerce them to the output column's - * datatype, the right things happen for UNKNOWN constants. But do - * this only at the first level of subquery-scan plans; we don't - * want phony constants appearing in the output tlists of upper-level - * nodes! + * rather than being referenced as subquery outputs. This is + * mainly to ensure that when we try to coerce them to the output + * column's datatype, the right things happen for UNKNOWN + * constants. But do this only at the first level of + * subquery-scan plans; we don't want phony constants appearing in + * the output tlists of upper-level nodes! */ resdom = makeResdom((AttrNumber) resno++, colType, @@ -440,7 +450,7 @@ tlist_same_datatypes(List *tlist, List *colTypes, bool junkOK) if (tle->resdom->resjunk) { - if (! junkOK) + if (!junkOK) return false; } else @@ -484,11 +494,11 @@ find_all_inheritors(Oid parentrel) currentchildren = find_inheritance_children(currentrel); /* - * Add to the queue only those children not already seen. - * This avoids making duplicate entries in case of multiple - * inheritance paths from the same parent. (It'll also keep - * us from getting into an infinite loop, though theoretically - * there can't be any cycles in the inheritance graph anyway.) + * Add to the queue only those children not already seen. This + * avoids making duplicate entries in case of multiple inheritance + * paths from the same parent. (It'll also keep us from getting + * into an infinite loop, though theoretically there can't be any + * cycles in the inheritance graph anyway.) */ currentchildren = set_differencei(currentchildren, examined_relids); unexamined_relids = set_unioni(unexamined_relids, currentchildren); @@ -524,20 +534,21 @@ expand_inherted_rtentry(Query *parse, Index rti) List *l; /* Does RT entry allow inheritance? */ - if (! rte->inh) + if (!rte->inh) return NIL; Assert(parentOID != InvalidOid && rte->subquery == NULL); /* Always clear the parent's inh flag, see above comments */ rte->inh = false; /* Fast path for common case of childless table */ - if (! has_subclass(parentOID)) + if (!has_subclass(parentOID)) return NIL; /* Scan for all members of inheritance set */ inhOIDs = find_all_inheritors(parentOID); + /* - * Check that there's at least one descendant, else treat as - * no-child case. This could happen despite above has_subclass() - * check, if table once had a child but no longer does. + * Check that there's at least one descendant, else treat as no-child + * case. This could happen despite above has_subclass() check, if + * table once had a child but no longer does. */ if (lnext(inhOIDs) == NIL) return NIL; @@ -545,18 +556,19 @@ expand_inherted_rtentry(Query *parse, Index rti) inhRTIs = makeListi1(rti); foreach(l, inhOIDs) { - Oid childOID = (Oid) lfirsti(l); + Oid childOID = (Oid) lfirsti(l); RangeTblEntry *childrte; - Index childRTindex; + Index childRTindex; /* parent will be in the list too, so ignore it */ if (childOID == parentOID) continue; /* - * Build an RTE for the child, and attach to query's rangetable list. - * We copy most fields of the parent's RTE, but replace relation - * real name and OID. Note that inh will be false at this point. + * Build an RTE for the child, and attach to query's rangetable + * list. We copy most fields of the parent's RTE, but replace + * relation real name and OID. Note that inh will be false at + * this point. */ childrte = copyObject(rte); childrte->relname = get_rel_name(childOID); @@ -575,12 +587,12 @@ expand_inherted_rtentry(Query *parse, Index rti) * to old_rt_index to refer to new_rt_index. * * We also adjust varattno to match the new table by column name, rather - * than column number. This hack makes it possible for child tables to have + * than column number. This hack makes it possible for child tables to have * different column positions for the "same" attribute as a parent, which * helps ALTER TABLE ADD COLUMN. Unfortunately this isn't nearly enough to * make it work transparently; there are other places where things fall down * if children and parents don't have the same column numbers for inherited - * attributes. It'd be better to rip this code out and fix ALTER TABLE... + * attributes. It'd be better to rip this code out and fix ALTER TABLE... */ Node * adjust_inherited_attrs(Node *node, @@ -643,12 +655,13 @@ adjust_inherited_attrs_mutator(Node *node, } if (IsA(node, RangeTblRef)) { - RangeTblRef *rtr = (RangeTblRef *) copyObject(node); + RangeTblRef *rtr = (RangeTblRef *) copyObject(node); if (rtr->rtindex == context->old_rt_index) rtr->rtindex = context->new_rt_index; return (Node *) rtr; } + /* * We have to process RestrictInfo nodes specially: we do NOT want to * copy the original subclauseindices list, since the new rel may have @@ -656,8 +669,8 @@ adjust_inherited_attrs_mutator(Node *node, */ if (IsA(node, RestrictInfo)) { - RestrictInfo *oldinfo = (RestrictInfo *) node; - RestrictInfo *newinfo = makeNode(RestrictInfo); + RestrictInfo *oldinfo = (RestrictInfo *) node; + RestrictInfo *newinfo = makeNode(RestrictInfo); /* Copy all flat-copiable fields */ memcpy(newinfo, oldinfo, sizeof(RestrictInfo)); @@ -666,18 +679,19 @@ adjust_inherited_attrs_mutator(Node *node, adjust_inherited_attrs_mutator((Node *) oldinfo->clause, context); newinfo->subclauseindices = NIL; - newinfo->eval_cost = -1; /* reset this too */ - newinfo->left_pathkey = NIL; /* and these */ + newinfo->eval_cost = -1;/* reset this too */ + newinfo->left_pathkey = NIL; /* and these */ newinfo->right_pathkey = NIL; newinfo->left_dispersion = -1; newinfo->right_dispersion = -1; return (Node *) newinfo; } + /* * NOTE: we do not need to recurse into sublinks, because they should * already have been converted to subplans before we see them. */ return expression_tree_mutator(node, adjust_inherited_attrs_mutator, - (void *) context); + (void *) context); } |