diff options
author | Marc G. Fournier <scrappy@hub.org> | 1996-07-09 06:22:35 +0000 |
---|---|---|
committer | Marc G. Fournier <scrappy@hub.org> | 1996-07-09 06:22:35 +0000 |
commit | d31084e9d1118b25fd16580d9d8c2924b5740dff (patch) | |
tree | 3179e66307d54df9c7b966543550e601eb55e668 /src/backend/optimizer/plan/planmain.c | |
download | postgresql-PG95-1_01.tar.gz postgresql-PG95-1_01.zip |
Postgres95 1.01 Distribution - Virgin SourcesPG95-1_01
Diffstat (limited to 'src/backend/optimizer/plan/planmain.c')
-rw-r--r-- | src/backend/optimizer/plan/planmain.c | 422 |
1 files changed, 422 insertions, 0 deletions
diff --git a/src/backend/optimizer/plan/planmain.c b/src/backend/optimizer/plan/planmain.c new file mode 100644 index 00000000000..5740b83a2d3 --- /dev/null +++ b/src/backend/optimizer/plan/planmain.c @@ -0,0 +1,422 @@ +/*------------------------------------------------------------------------- + * + * planmain.c-- + * Routines to plan a single query + * + * Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.1.1.1 1996/07/09 06:21:37 scrappy Exp $ + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "nodes/pg_list.h" +#include "nodes/plannodes.h" +#include "nodes/parsenodes.h" +#include "nodes/relation.h" + +#include "optimizer/planmain.h" +#include "optimizer/internal.h" +#include "optimizer/paths.h" +#include "optimizer/clauses.h" +#include "optimizer/keys.h" +#include "optimizer/tlist.h" +#include "optimizer/xfunc.h" +#include "optimizer/cost.h" + +#include "tcop/dest.h" +#include "utils/elog.h" +#include "utils/palloc.h" +#include "nodes/memnodes.h" +#include "utils/mcxt.h" +#include "utils/lsyscache.h" + +static Plan *subplanner(Query *root, List *flat_tlist, List *qual); +static Result *make_result(List *tlist, Node *resconstantqual, Plan *subplan); + +static Plan *make_groupPlan(List *tlist, bool tuplePerGroup, + List *groupClause, Plan *subplan); + +/* + * query_planner-- + * Routine to create a query plan. It does so by first creating a + * subplan for the topmost level of attributes in the query. Then, + * it modifies all target list and qualifications to consider the next + * level of nesting and creates a plan for this modified query by + * recursively calling itself. The two pieces are then merged together + * by creating a result node that indicates which attributes should + * be placed where and any relation level qualifications to be + * satisfied. + * + * command-type is the query command, e.g., retrieve, delete, etc. + * tlist is the target list of the query + * qual is the qualification of the query + * + * Returns a query plan. + */ +Plan * +query_planner(Query *root, + int command_type, + List *tlist, + List *qual) +{ + List *constant_qual = NIL; + List *flattened_tlist = NIL; + List *level_tlist = NIL; + Plan *subplan = (Plan*)NULL; + Agg *aggplan = NULL; + + /* + * A command without a target list or qualification is an error, + * except for "delete foo". + */ + if (tlist==NIL && qual==NULL) { + if (command_type == CMD_DELETE || + /* Total hack here. I don't know how to handle + statements like notify in action bodies. + Notify doesn't return anything but + scans a system table. */ + command_type == CMD_NOTIFY) { + return ((Plan*)make_seqscan(NIL, + NIL, + root->resultRelation, + (Plan*)NULL)); + } else + return((Plan*)NULL); + } + + /* + * Pull out any non-variable qualifications so these can be put in + * the topmost result node. The opids for the remaining + * qualifications will be changed to regprocs later. + */ + qual = pull_constant_clauses(qual, &constant_qual); + fix_opids(constant_qual); + + /* + * Create a target list that consists solely of (resdom var) target + * list entries, i.e., contains no arbitrary expressions. + */ + flattened_tlist = flatten_tlist(tlist); + if (flattened_tlist) { + level_tlist = flattened_tlist; + } else { + /* from old code. the logic is beyond me. - ay 2/95 */ + level_tlist = tlist; + } + + /* + * Needs to add the group attribute(s) to the target list so that they + * are available to either the Group node or the Agg node. (The target + * list may not contain the group attribute(s).) + */ + if (root->groupClause) { + AddGroupAttrToTlist(level_tlist, root->groupClause); + } + + if (root->qry_aggs) { + aggplan = make_agg(tlist, root->qry_numAgg, root->qry_aggs); + tlist = level_tlist; + } + + /* + * A query may have a non-variable target list and a non-variable + * qualification only under certain conditions: + * - the query creates all-new tuples, or + * - the query is a replace (a scan must still be done in this case). + */ + if (flattened_tlist==NULL && qual==NULL) { + + switch (command_type) { + case CMD_SELECT: + case CMD_INSERT: + return ((Plan*)make_result(tlist, + (Node*)constant_qual, + (Plan*)NULL)); + break; + + case CMD_DELETE: + case CMD_UPDATE: + { + SeqScan *scan = make_seqscan(tlist, + (List *)NULL, + root->resultRelation, + (Plan*)NULL); + if (constant_qual!=NULL) { + return ((Plan*)make_result(tlist, + (Node*)constant_qual, + (Plan*)scan)); + } else { + return ((Plan*)scan); + } + } + break; + + default: + return ((Plan*)NULL); + } + } + + /* + * Find the subplan (access path) and destructively modify the + * target list of the newly created subplan to contain the appropriate + * join references. + */ + subplan = subplanner(root, level_tlist, qual); + + set_tlist_references(subplan); + + /* + * If we have a GROUP BY clause, insert a group node (with the appropriate + * sort node.) + */ + if (root->groupClause != NULL) { + bool tuplePerGroup; + + /* + * decide whether how many tuples per group the Group node needs + * to return. (Needs only one tuple per group if no aggregate is + * present. Otherwise, need every tuple from the group to do the + * aggregation.) + */ + tuplePerGroup = (aggplan == NULL) ? FALSE : TRUE; + + subplan = + make_groupPlan(tlist, tuplePerGroup, root->groupClause, subplan); + + /* XXX fake it: this works for the Group node too! very very ugly, + please change me -ay 2/95 */ + set_agg_tlist_references((Agg*)subplan); + } + + /* + * If aggregate is present, insert the agg node + */ + if (aggplan != NULL) { + aggplan->plan.lefttree = subplan; + subplan = (Plan*)aggplan; + + /* + * set the varno/attno entries to the appropriate references to + * the result tuple of the subplans. (We need to set those in the + * array of aggreg's in the Agg node also. Even though they're + * pointers, after a few dozen's of copying, they're not the same as + * those in the target list.) + */ + set_agg_tlist_references((Agg*)subplan); + set_agg_agglist_references((Agg*)subplan); + + tlist = aggplan->plan.targetlist; + } + + /* + * Build a result node linking the plan if we have constant quals + */ + if (constant_qual) { + Plan *plan; + + plan = (Plan*)make_result(tlist, + (Node*)constant_qual, + subplan); + /* + * Change all varno's of the Result's node target list. + */ + set_result_tlist_references((Result*)plan); + + return (plan); + } + + /* + * fix up the flattened target list of the plan root node so that + * expressions are evaluated. this forces expression evaluations + * that may involve expensive function calls to be delayed to + * the very last stage of query execution. this could be bad. + * but it is joey's responsibility to optimally push these + * expressions down the plan tree. -- Wei + */ + subplan->targetlist = flatten_tlist_vars(tlist, + subplan->targetlist); + + /* + * Destructively modify the query plan's targetlist to add fjoin + * lists to flatten functions that return sets of base types + */ + subplan->targetlist = generate_fjoin(subplan->targetlist); + + return (subplan); +} + +/* + * subplanner + * + * Subplanner creates an entire plan consisting of joins and scans + * for processing a single level of attributes. + * + * flat-tlist is the flattened target list + * qual is the qualification to be satisfied + * + * Returns a subplan. + * + */ +static Plan * +subplanner(Query *root, + List *flat_tlist, + List *qual) +{ + Rel *final_relation; + List *final_relation_list; + + /* Initialize the targetlist and qualification, adding entries to + * *query-relation-list* as relation references are found (e.g., in the + * qualification, the targetlist, etc.) + */ + root->base_relation_list_ = NIL; + root->join_relation_list_ = NIL; + initialize_base_rels_list(root, flat_tlist); + initialize_base_rels_jinfo(root, qual); + add_missing_vars_to_base_rels(root, flat_tlist); + + /* Find all possible scan and join paths. + * Mark all the clauses and relations that can be processed using special + * join methods, then do the exhaustive path search. + */ + initialize_join_clause_info(root->base_relation_list_); + final_relation_list = find_paths(root, + root->base_relation_list_); + + if (final_relation_list) + final_relation = (Rel*)lfirst (final_relation_list); + else + final_relation = (Rel*)NIL; + +#if 0 /* fix xfunc */ + /* + * Perform Predicate Migration on each path, to optimize and correctly + * assess the cost of each before choosing the cheapest one. + * -- JMH, 11/16/92 + * + * Needn't do so if the top rel is pruneable: that means there's no + * expensive functions left to pull up. -- JMH, 11/22/92 + */ + if (XfuncMode != XFUNC_OFF && XfuncMode != XFUNC_NOPM && + XfuncMode != XFUNC_NOPULL && !final_relation->pruneable) + { + List *pathnode; + foreach(pathnode, final_relation->pathlist) + { + if (xfunc_do_predmig((Path*)lfirst(pathnode))) + set_cheapest(final_relation, final_relation->pathlist); + } + } +#endif + + /* + * Determine the cheapest path and create a subplan corresponding to it. + */ + if (final_relation) { + return (create_plan ((Path*)final_relation->cheapestpath)); + }else { + elog(NOTICE, "final relation is nil"); + return(create_plan ((Path*)NULL)); + } + +} + +/***************************************************************************** + * + *****************************************************************************/ + +static Result * +make_result(List *tlist, + Node *resconstantqual, + Plan *subplan) +{ + Result *node = makeNode(Result); + Plan *plan = &node->plan; + + tlist = generate_fjoin(tlist); + plan->cost = 0.0; + plan->state = (EState *)NULL; + plan->targetlist = tlist; + plan->lefttree = subplan; + plan->righttree = NULL; + node->resconstantqual = resconstantqual; + node->resstate = NULL; + + return(node); +} + +/***************************************************************************** + * + *****************************************************************************/ + +static Plan * +make_groupPlan(List *tlist, + bool tuplePerGroup, + List *groupClause, + Plan *subplan) +{ + List *sort_tlist; + List *gl; + int keyno; + Sort *sortplan; + Group *grpplan; + int numCols; + AttrNumber *grpColIdx; + + numCols = length(groupClause); + grpColIdx = (AttrNumber *)palloc(sizeof(AttrNumber)*numCols); + + /* + * first, make a sort node. Group node expects the tuples it gets + * from the subplan is in the order as specified by the group columns. + */ + keyno = 1; + sort_tlist = new_unsorted_tlist(subplan->targetlist); + + { + /* if this is a mergejoin node, varno could be OUTER/INNER */ + List *l; + foreach(l, sort_tlist) { + TargetEntry *tle; + tle = lfirst(l); + ((Var*)tle->expr)->varno = 1; + } + } + + foreach (gl, groupClause) { + GroupClause *grpcl = (GroupClause*)lfirst(gl); + TargetEntry *tle; + + tle = match_varid(grpcl->grpAttr, sort_tlist); + /* + * the parser should have checked to make sure the group attribute + * is valid but the optimizer might have screwed up and hence we + * check again. + */ + if (tle==NULL) { + elog(WARN, "group attribute disappeared from target list"); + } + tle->resdom->reskey = keyno; + tle->resdom->reskeyop = get_opcode(grpcl->grpOpoid); + + grpColIdx[keyno-1] = tle->resdom->resno; + keyno++; + } + sortplan = make_sort(sort_tlist, + _TEMP_RELATION_ID_, + subplan, + numCols); + sortplan->plan.cost = subplan->cost; /* XXX assume no cost */ + + /* + * make the Group node + */ + tlist = copyObject(tlist); /* make a copy */ + grpplan = make_group(tlist, tuplePerGroup, numCols, grpColIdx, sortplan); + + return (Plan*)grpplan; +} |