aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/plan/planmain.c
diff options
context:
space:
mode:
authorMarc G. Fournier <scrappy@hub.org>1996-07-09 06:22:35 +0000
committerMarc G. Fournier <scrappy@hub.org>1996-07-09 06:22:35 +0000
commitd31084e9d1118b25fd16580d9d8c2924b5740dff (patch)
tree3179e66307d54df9c7b966543550e601eb55e668 /src/backend/optimizer/plan/planmain.c
downloadpostgresql-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.c422
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;
+}