diff options
Diffstat (limited to 'src/backend/optimizer/plan/planner.c')
-rw-r--r-- | src/backend/optimizer/plan/planner.c | 355 |
1 files changed, 188 insertions, 167 deletions
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 86977028f7b..65327a12631 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.53 1999/05/17 17:03:15 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.54 1999/05/25 16:09:37 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -56,10 +56,10 @@ #include "parser/parse_oper.h" static List *make_subplanTargetList(Query *parse, List *tlist, - AttrNumber **groupColIdx); + AttrNumber **groupColIdx); static Plan *make_groupplan(List *group_tlist, bool tuplePerGroup, - List *groupClause, AttrNumber *grpColIdx, - Plan *subplan); + List *groupClause, AttrNumber *grpColIdx, + Plan *subplan); static bool need_sortplan(List *sortcls, Plan *plan); static Plan *make_sortplan(List *tlist, List *sortcls, Plan *plannode); @@ -113,12 +113,12 @@ union_planner(Query *parse) if (parse->unionClause) { - result_plan = (Plan *) plan_union_queries(parse); - /* XXX do we need to do this? bjm 12/19/97 */ - tlist = preprocess_targetlist(tlist, - parse->commandType, - parse->resultRelation, - parse->rtable); + result_plan = (Plan *) plan_union_queries(parse); + /* XXX do we need to do this? bjm 12/19/97 */ + tlist = preprocess_targetlist(tlist, + parse->commandType, + parse->resultRelation, + parse->rtable); } else if ((rt_index = first_inherit_rt_entry(rangetable)) != -1) { @@ -127,78 +127,80 @@ union_planner(Query *parse) result_plan = (Plan *) plan_inherit_queries(parse, rt_index); /* XXX do we need to do this? bjm 12/19/97 */ tlist = preprocess_targetlist(tlist, - parse->commandType, - parse->resultRelation, - parse->rtable); + parse->commandType, + parse->resultRelation, + parse->rtable); } else { - List **vpm = NULL; - List *sub_tlist; + List **vpm = NULL; + List *sub_tlist; - /* Preprocess targetlist in case we are inside an INSERT/UPDATE. */ - tlist = preprocess_targetlist(tlist, - parse->commandType, - parse->resultRelation, - parse->rtable); + /* Preprocess targetlist in case we are inside an INSERT/UPDATE. */ + tlist = preprocess_targetlist(tlist, + parse->commandType, + parse->resultRelation, + parse->rtable); - /* Add row-mark targets for UPDATE - * (should this be done in preprocess_targetlist?) - */ - if (parse->rowMark != NULL) - { - List *l; + /* + * Add row-mark targets for UPDATE (should this be done in + * preprocess_targetlist?) + */ + if (parse->rowMark != NULL) + { + List *l; + + foreach(l, parse->rowMark) + { + RowMark *rowmark = (RowMark *) lfirst(l); + TargetEntry *ctid; + Resdom *resdom; + Var *var; + char *resname; + + if (!(rowmark->info & ROW_MARK_FOR_UPDATE)) + continue; + + resname = (char *) palloc(32); + sprintf(resname, "ctid%u", rowmark->rti); + resdom = makeResdom(length(tlist) + 1, + TIDOID, + -1, + resname, + 0, + 0, + true); + + var = makeVar(rowmark->rti, -1, TIDOID, + -1, 0, rowmark->rti, -1); + + ctid = makeTargetEntry(resdom, (Node *) var); + tlist = lappend(tlist, ctid); + } + } + + /* + * Generate appropriate target list for subplan; may be different + * from tlist if grouping or aggregation is needed. + */ + sub_tlist = make_subplanTargetList(parse, tlist, &groupColIdx); - foreach (l, parse->rowMark) + /* Generate the (sub) plan */ + if (parse->rtable != NULL) { - RowMark *rowmark = (RowMark*) lfirst(l); - TargetEntry *ctid; - Resdom *resdom; - Var *var; - char *resname; - - if (!(rowmark->info & ROW_MARK_FOR_UPDATE)) - continue; - - resname = (char*) palloc(32); - sprintf(resname, "ctid%u", rowmark->rti); - resdom = makeResdom(length(tlist) + 1, - TIDOID, - -1, - resname, - 0, - 0, - true); - - var = makeVar(rowmark->rti, -1, TIDOID, - -1, 0, rowmark->rti, -1); - - ctid = makeTargetEntry(resdom, (Node *) var); - tlist = lappend(tlist, ctid); + vpm = (List **) palloc(length(parse->rtable) * sizeof(List *)); + memset(vpm, 0, length(parse->rtable) * sizeof(List *)); } - } - - /* Generate appropriate target list for subplan; may be different - * from tlist if grouping or aggregation is needed. - */ - sub_tlist = make_subplanTargetList(parse, tlist, &groupColIdx); - - /* Generate the (sub) plan */ - if (parse->rtable != NULL) - { - vpm = (List **) palloc(length(parse->rtable) * sizeof(List *)); - memset(vpm, 0, length(parse->rtable) * sizeof(List *)); - } - PlannerVarParam = lcons(vpm, PlannerVarParam); - result_plan = query_planner(parse, - parse->commandType, - sub_tlist, - (List *) parse->qual); - PlannerVarParam = lnext(PlannerVarParam); - if (vpm != NULL) - pfree(vpm); + PlannerVarParam = lcons(vpm, PlannerVarParam); + result_plan = query_planner(parse, + parse->commandType, + sub_tlist, + (List *) parse->qual); + PlannerVarParam = lnext(PlannerVarParam); + if (vpm != NULL) + pfree(vpm); } - + /* * If we have a GROUP BY clause, insert a group node (with the * appropriate sort node.) @@ -216,7 +218,8 @@ union_planner(Query *parse) */ tuplePerGroup = parse->hasAggs; - /* If there are aggregates then the Group node should just return + /* + * If there are aggregates then the Group node should just return * the same (simplified) tlist as the subplan, which we indicate * to make_groupplan by passing NIL. If there are no aggregates * then the Group node had better compute the final tlist. @@ -235,7 +238,7 @@ union_planner(Query *parse) */ if (parse->havingQual) { - List **vpm = NULL; + List **vpm = NULL; if (parse->rtable != NULL) { @@ -249,15 +252,20 @@ union_planner(Query *parse) if (parse->hasSubLinks) { - /* There is a subselect in the havingQual, so we have to process it - * using the same function as for a subselect in 'where' + + /* + * There is a subselect in the havingQual, so we have to + * process it using the same function as for a subselect in + * 'where' */ parse->havingQual = (Node *) SS_process_sublinks(parse->havingQual); - /* Check for ungrouped variables passed to subplans. - * (Probably this should be done by the parser, but right now - * the parser is not smart enough to tell which level the vars - * belong to?) + + /* + * Check for ungrouped variables passed to subplans. (Probably + * this should be done by the parser, but right now the parser + * is not smart enough to tell which level the vars belong + * to?) */ check_having_for_ungrouped_vars(parse->havingQual, parse->groupClause, @@ -269,7 +277,7 @@ union_planner(Query *parse) PlannerVarParam = lnext(PlannerVarParam); if (vpm != NULL) - pfree(vpm); + pfree(vpm); } /* @@ -283,22 +291,22 @@ union_planner(Query *parse) result_plan->qual = (List *) parse->havingQual; /* - * Update vars to refer to subplan result tuples, - * find Aggrefs, make sure there is an Aggref in every HAVING clause. + * Update vars to refer to subplan result tuples, find Aggrefs, + * make sure there is an Aggref in every HAVING clause. */ - if (! set_agg_tlist_references((Agg *) result_plan)) + if (!set_agg_tlist_references((Agg *) result_plan)) elog(ERROR, "SELECT/HAVING requires aggregates to be valid"); /* * Check that we actually found some aggregates, else executor * will die unpleasantly. (The rewrite module currently has bugs - * that allow hasAggs to be incorrectly set 'true' sometimes. - * It's not easy to recover here, since we've already made decisions + * that allow hasAggs to be incorrectly set 'true' sometimes. It's + * not easy to recover here, since we've already made decisions * assuming there will be an Agg node.) */ if (((Agg *) result_plan)->aggs == NIL) elog(ERROR, "union_planner: query is marked hasAggs, but I don't see any"); - } + } /* * For now, before we hand back the plan, check to see if there is a @@ -363,7 +371,7 @@ union_planner(Query *parse) * SELECT a+1, ... GROUP BY a+1 * Note, however, that other varnodes in the parent's targetlist (and * havingQual, if any) will still need to be updated to refer to outputs - * of the subplan. This routine is quite large enough already, so we do + * of the subplan. This routine is quite large enough already, so we do * that later. *--------------- */ @@ -384,13 +392,15 @@ make_subplanTargetList(Query *parse, *groupColIdx = NULL; - /* If we're not grouping or aggregating, nothing to do here; + /* + * If we're not grouping or aggregating, nothing to do here; * query_planner should receive the unmodified target list. */ if (!parse->hasAggs && !parse->groupClause && !parse->havingQual) return tlist; - /* If grouping, make a working copy of groupClause list (which we use + /* + * If grouping, make a working copy of groupClause list (which we use * just to verify that we found all the groupClause items in tlist). * Also allocate space to remember where the group columns are in the * subplan tlist. @@ -403,14 +413,14 @@ make_subplanTargetList(Query *parse, *groupColIdx = grpColIdx; } - sub_tlist = new_unsorted_tlist(tlist); /* make a modifiable copy */ + sub_tlist = new_unsorted_tlist(tlist); /* make a modifiable copy */ /* * Step 1: build grpColIdx by finding targetlist items that match * GroupBy entries. If there are aggregates, remove non-GroupBy items * from sub_tlist, and reset its resnos accordingly. When we leave an - * expression in the subplan tlist, modify the parent tlist to copy the - * value from the subplan output rather than re-evaluating it. + * expression in the subplan tlist, modify the parent tlist to copy + * the value from the subplan output rather than re-evaluating it. */ prnt_tlist = tlist; /* scans parent tlist in sync with sl */ foreach(sl, sub_tlist) @@ -434,23 +444,28 @@ make_subplanTargetList(Query *parse, resdom->reskey = keyno; resdom->reskeyop = get_opcode(grpcl->grpOpoid); grpColIdx[keyno - 1] = next_resno; - /* Remove groupclause from our list of unmatched groupclauses. - * NB: this depends on having used a shallow listCopy() above. + + /* + * Remove groupclause from our list of unmatched + * groupclauses. NB: this depends on having used a shallow + * listCopy() above. */ - glc = lremove((void*) grpcl, glc); + glc = lremove((void *) grpcl, glc); break; } } - if (! foundGroupClause) + if (!foundGroupClause) { + /* * Non-GroupBy entry: remove it from subplan if there are - * aggregates in query - it will be evaluated by Aggregate plan. - * But do not remove simple-Var entries; we'd just have to add - * them back anyway, and we risk confusing INSERT/UPDATE. + * aggregates in query - it will be evaluated by Aggregate + * plan. But do not remove simple-Var entries; we'd just have + * to add them back anyway, and we risk confusing + * INSERT/UPDATE. */ - if (parse->hasAggs && ! IsA(te->expr, Var)) + if (parse->hasAggs && !IsA(te->expr, Var)) keepInSubPlan = false; } @@ -458,15 +473,16 @@ make_subplanTargetList(Query *parse, { /* Assign new sequential resnos to subplan tlist items */ resdom->resno = next_resno++; - if (! IsA(parentte->expr, Var)) + if (!IsA(parentte->expr, Var)) { - /* Since the item is being computed in the subplan, - * we can just make a Var node to reference it in the - * outer plan, rather than recomputing it there. - * Note we use varnoold = -1 as a flag to let - * replace_vars_with_subplan_refs know it needn't change - * this Var node. - * If it's only a Var anyway, we leave it alone for now; + + /* + * Since the item is being computed in the subplan, we can + * just make a Var node to reference it in the outer plan, + * rather than recomputing it there. Note we use varnoold + * = -1 as a flag to let replace_vars_with_subplan_refs + * know it needn't change this Var node. If it's only a + * Var anyway, we leave it alone for now; * replace_vars_with_subplan_refs will fix it later. */ parentte->expr = (Node *) makeVar(1, resdom->resno, @@ -477,9 +493,11 @@ make_subplanTargetList(Query *parse, } else { - /* Remove this tlist item from the subplan, but remember the - * vars it needs. The outer tlist item probably needs changes, - * but that will happen later. + + /* + * Remove this tlist item from the subplan, but remember the + * vars it needs. The outer tlist item probably needs + * changes, but that will happen later. */ sub_tlist = lremove(te, sub_tlist); extravars = nconc(extravars, pull_var_clause(te->expr)); @@ -493,8 +511,8 @@ make_subplanTargetList(Query *parse, elog(ERROR, "make_subplanTargetList: GROUP BY attribute not found in target list"); /* - * Add subplan targets for any variables needed by removed tlist entries - * that aren't otherwise mentioned in the subplan target list. + * Add subplan targets for any variables needed by removed tlist + * entries that aren't otherwise mentioned in the subplan target list. * We'll also need targets for any variables seen only in HAVING. */ extravars = nconc(extravars, pull_var_clause(parse->havingQual)); @@ -505,9 +523,11 @@ make_subplanTargetList(Query *parse, if (tlist_member(v, sub_tlist) == NULL) { - /* Make sure sub_tlist element is a fresh object not shared with - * any other structure; not sure if anything will break if it is - * shared, but better to be safe... + + /* + * Make sure sub_tlist element is a fresh object not shared + * with any other structure; not sure if anything will break + * if it is shared, but better to be safe... */ sub_tlist = lappend(sub_tlist, create_tl_element((Var *) copyObject(v), @@ -535,9 +555,9 @@ make_groupplan(List *group_tlist, /* * Make the targetlist for the Sort node; it always just references * each of the corresponding target items of the subplan. We need to - * ensure that simple Vars in the subplan's target list are recognizable - * by replace_vars_with_subplan_refs when it's applied to the Sort/Group - * target list, so copy up their varnoold/varoattno. + * ensure that simple Vars in the subplan's target list are + * recognizable by replace_vars_with_subplan_refs when it's applied to + * the Sort/Group target list, so copy up their varnoold/varoattno. */ sort_tlist = NIL; foreach(sl, subplan->targetlist) @@ -548,7 +568,8 @@ make_groupplan(List *group_tlist, if (IsA(te->expr, Var)) { - Var *subvar = (Var *) te->expr; + Var *subvar = (Var *) te->expr; + newvar = makeVar(1, resdom->resno, resdom->restype, resdom->restypmod, 0, subvar->varnoold, subvar->varoattno); @@ -561,8 +582,8 @@ make_groupplan(List *group_tlist, } sort_tlist = lappend(sort_tlist, - makeTargetEntry((Resdom *) copyObject(resdom), - (Node *) newvar)); + makeTargetEntry((Resdom *) copyObject(resdom), + (Node *) newvar)); } /* @@ -575,20 +596,19 @@ make_groupplan(List *group_tlist, sortplan->plan.cost = subplan->cost; /* XXX assume no cost */ /* - * If the caller gave us a target list, use it after fixing the variables. - * If not, we need the same sort of "repeater" tlist as for the Sort node. + * If the caller gave us a target list, use it after fixing the + * variables. If not, we need the same sort of "repeater" tlist as for + * the Sort node. */ if (group_tlist) { - group_tlist = copyObject(group_tlist); /* necessary?? */ + group_tlist = copyObject(group_tlist); /* necessary?? */ replace_tlist_with_subplan_refs(group_tlist, (Index) 0, subplan->targetlist); } else - { group_tlist = copyObject(sort_tlist); - } /* * Make the Group node @@ -686,7 +706,7 @@ pg_checkretval(Oid rettype, List *queryTreeList) int i; /* find the final query */ - parse = (Query *) nth(length(queryTreeList)-1, queryTreeList); + parse = (Query *) nth(length(queryTreeList) - 1, queryTreeList); /* * test 1: if the last query is a utility invocation, then there had @@ -787,7 +807,7 @@ pg_checkretval(Oid rettype, List *queryTreeList) tlist = lnext(tlist); tletype = exprType(thenode); -#ifdef NOT_USED /* fix me */ +#ifdef NOT_USED /* fix me */ /* this is tedious */ if (IsA(thenode, Var)) tletype = (Oid) ((Var *) thenode)->vartype; @@ -830,11 +850,12 @@ pg_checkretval(Oid rettype, List *queryTreeList) static TargetEntry * get_matching_tle(Plan *plan, Resdom *resdom) { - List *i; - TargetEntry *tle; + List *i; + TargetEntry *tle; - foreach (i, plan->targetlist) { - tle = (TargetEntry *)lfirst(i); + foreach(i, plan->targetlist) + { + tle = (TargetEntry *) lfirst(i); if (tle->resdom->resno == resdom->resno) return tle; } @@ -853,50 +874,45 @@ static bool need_sortplan(List *sortcls, Plan *plan) { Relation indexRel; - IndexScan *indexScan; - Oid indexId; - List *i; + IndexScan *indexScan; + Oid indexId; + List *i; HeapTuple htup; - Form_pg_index index_tup; - int key_no = 0; + Form_pg_index index_tup; + int key_no = 0; /* ---------- * Must be an IndexScan * ---------- */ - if (nodeTag(plan) != T_IndexScan) { + if (nodeTag(plan) != T_IndexScan) return TRUE; - } - indexScan = (IndexScan *)plan; + indexScan = (IndexScan *) plan; /* ---------- * Should not have left- or righttree * ---------- */ - if (plan->lefttree != NULL) { + if (plan->lefttree != NULL) return TRUE; - } - if (plan->righttree != NULL) { + if (plan->righttree != NULL) return TRUE; - } /* ---------- * Must be a single index scan * ---------- */ - if (length(indexScan->indxid) != 1) { + if (length(indexScan->indxid) != 1) return TRUE; - } /* ---------- * Indices can only have up to 8 attributes. So an ORDER BY using * more that 8 attributes could never be satisfied by an index. * ---------- */ - if (length(sortcls) > 8) { + if (length(sortcls) > 8) return TRUE; - } /* ---------- * The choosen Index must be a btree @@ -905,7 +921,8 @@ need_sortplan(List *sortcls, Plan *plan) indexId = lfirsti(indexScan->indxid); indexRel = index_open(indexId); - if (strcmp(nameout(&(indexRel->rd_am->amname)), "btree") != 0) { + if (strcmp(nameout(&(indexRel->rd_am->amname)), "btree") != 0) + { heap_close(indexRel); return TRUE; } @@ -916,34 +933,36 @@ need_sortplan(List *sortcls, Plan *plan) * ---------- */ htup = SearchSysCacheTuple(INDEXRELID, - ObjectIdGetDatum(indexId), 0, 0, 0); - if (!HeapTupleIsValid(htup)) { + ObjectIdGetDatum(indexId), 0, 0, 0); + if (!HeapTupleIsValid(htup)) elog(ERROR, "cache lookup for index %u failed", indexId); - } index_tup = (Form_pg_index) GETSTRUCT(htup); /* ---------- * Check if all the sort clauses match the attributes in the index * ---------- */ - foreach (i, sortcls) { - SortClause *sortcl; - Resdom *resdom; - TargetEntry *tle; - Var *var; + foreach(i, sortcls) + { + SortClause *sortcl; + Resdom *resdom; + TargetEntry *tle; + Var *var; sortcl = (SortClause *) lfirst(i); resdom = sortcl->resdom; tle = get_matching_tle(plan, resdom); - if (tle == NULL) { + if (tle == NULL) + { /* ---------- * Could this happen? * ---------- */ return TRUE; } - if (nodeTag(tle->expr) != T_Var) { + if (nodeTag(tle->expr) != T_Var) + { /* ---------- * The target list expression isn't a var, so it * cannot be the indexed attribute @@ -951,9 +970,10 @@ need_sortplan(List *sortcls, Plan *plan) */ return TRUE; } - var = (Var *)(tle->expr); + var = (Var *) (tle->expr); - if (var->varno != indexScan->scan.scanrelid) { + if (var->varno != indexScan->scan.scanrelid) + { /* ---------- * This Var isn't from the scan relation. So it isn't * that of the index @@ -962,7 +982,8 @@ need_sortplan(List *sortcls, Plan *plan) return TRUE; } - if (var->varattno != index_tup->indkey[key_no]) { + if (var->varattno != index_tup->indkey[key_no]) + { /* ---------- * It isn't the indexed attribute. * ---------- @@ -970,7 +991,8 @@ need_sortplan(List *sortcls, Plan *plan) return TRUE; } - if (oprid(oper("<", resdom->restype, resdom->restype, FALSE)) != sortcl->opoid) { + if (oprid(oper("<", resdom->restype, resdom->restype, FALSE)) != sortcl->opoid) + { /* ---------- * Sort order isn't in ascending order. * ---------- @@ -987,4 +1009,3 @@ need_sortplan(List *sortcls, Plan *plan) */ return FALSE; } - |