summaryrefslogtreecommitdiff
path: root/src/backend/optimizer/plan
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/plan')
-rw-r--r--src/backend/optimizer/plan/createplan.c2005
-rw-r--r--src/backend/optimizer/plan/initsplan.c579
-rw-r--r--src/backend/optimizer/plan/planmain.c952
-rw-r--r--src/backend/optimizer/plan/planner.c635
-rw-r--r--src/backend/optimizer/plan/setrefs.c1148
5 files changed, 2782 insertions, 2537 deletions
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 7637d15f20..bdceec18be 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* createplan.c--
- * Routines to create the desired plan for processing a query
+ * Routines to create the desired plan for processing a query
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.11 1997/04/24 15:59:58 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.12 1997/09/07 04:43:57 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -41,766 +41,836 @@
#include "optimizer/internal.h"
-#define TEMP_SORT 1
+#define TEMP_SORT 1
#define TEMP_MATERIAL 2
-static List *switch_outer(List *clauses);
-static Scan *create_scan_node(Path *best_path, List *tlist);
-static Join *create_join_node(JoinPath *best_path, List *tlist);
-static SeqScan *create_seqscan_node(Path *best_path, List *tlist,
- List *scan_clauses);
-static IndexScan *create_indexscan_node(IndexPath *best_path, List *tlist,
- List *scan_clauses);
-static NestLoop *create_nestloop_node(JoinPath *best_path, List *tlist,
- List *clauses, Plan *outer_node, List *outer_tlist,
- Plan *inner_node, List *inner_tlist);
-static MergeJoin *create_mergejoin_node(MergePath *best_path, List *tlist,
- List *clauses, Plan *outer_node, List *outer_tlist,
- Plan *inner_node, List *inner_tlist);
-static HashJoin *create_hashjoin_node(HashPath *best_path, List *tlist,
- List *clauses, Plan *outer_node, List *outer_tlist,
- Plan *inner_node, List *inner_tlist);
-static Node *fix_indxqual_references(Node *clause, Path *index_path);
-static Temp *make_temp(List *tlist, List *keys, Oid *operators,
- Plan *plan_node, int temptype);
-static IndexScan *make_indexscan(List *qptlist, List *qpqual, Index scanrelid,
- List *indxid, List *indxqual);
-static NestLoop *make_nestloop(List *qptlist, List *qpqual, Plan *lefttree,
- Plan *righttree);
-static HashJoin *make_hashjoin(List *tlist, List *qpqual,
- List *hashclauses, Plan *lefttree, Plan *righttree);
-static Hash *make_hash(List *tlist, Var *hashkey, Plan *lefttree);
-static MergeJoin *make_mergesort(List * tlist, List *qpqual,
- List *mergeclauses, Oid opcode, Oid *rightorder,
- Oid *leftorder, Plan *righttree, Plan *lefttree);
-static Material *make_material(List *tlist, Oid tempid, Plan *lefttree,
- int keycount);
-
-/*
+static List *switch_outer(List * clauses);
+static Scan *create_scan_node(Path * best_path, List * tlist);
+static Join *create_join_node(JoinPath * best_path, List * tlist);
+static SeqScan *
+create_seqscan_node(Path * best_path, List * tlist,
+ List * scan_clauses);
+static IndexScan *
+create_indexscan_node(IndexPath * best_path, List * tlist,
+ List * scan_clauses);
+static NestLoop *
+create_nestloop_node(JoinPath * best_path, List * tlist,
+ List * clauses, Plan * outer_node, List * outer_tlist,
+ Plan * inner_node, List * inner_tlist);
+static MergeJoin *
+create_mergejoin_node(MergePath * best_path, List * tlist,
+ List * clauses, Plan * outer_node, List * outer_tlist,
+ Plan * inner_node, List * inner_tlist);
+static HashJoin *
+create_hashjoin_node(HashPath * best_path, List * tlist,
+ List * clauses, Plan * outer_node, List * outer_tlist,
+ Plan * inner_node, List * inner_tlist);
+static Node *fix_indxqual_references(Node * clause, Path * index_path);
+static Temp *
+make_temp(List * tlist, List * keys, Oid * operators,
+ Plan * plan_node, int temptype);
+static IndexScan *
+make_indexscan(List * qptlist, List * qpqual, Index scanrelid,
+ List * indxid, List * indxqual);
+static NestLoop *
+make_nestloop(List * qptlist, List * qpqual, Plan * lefttree,
+ Plan * righttree);
+static HashJoin *
+make_hashjoin(List * tlist, List * qpqual,
+ List * hashclauses, Plan * lefttree, Plan * righttree);
+static Hash *make_hash(List * tlist, Var * hashkey, Plan * lefttree);
+static MergeJoin *
+make_mergesort(List * tlist, List * qpqual,
+ List * mergeclauses, Oid opcode, Oid * rightorder,
+ Oid * leftorder, Plan * righttree, Plan * lefttree);
+static Material *
+make_material(List * tlist, Oid tempid, Plan * lefttree,
+ int keycount);
+
+/*
* create_plan--
- * Creates the access plan for a query by tracing backwards through the
- * desired chain of pathnodes, starting at the node 'best-path'. For
- * every pathnode found:
- * (1) Create a corresponding plan node containing appropriate id,
- * target list, and qualification information.
- * (2) Modify ALL clauses so that attributes are referenced using
- * relative values.
- * (3) Target lists are not modified, but will be in another routine.
- *
- * best-path is the best access path
+ * Creates the access plan for a query by tracing backwards through the
+ * desired chain of pathnodes, starting at the node 'best-path'. For
+ * every pathnode found:
+ * (1) Create a corresponding plan node containing appropriate id,
+ * target list, and qualification information.
+ * (2) Modify ALL clauses so that attributes are referenced using
+ * relative values.
+ * (3) Target lists are not modified, but will be in another routine.
+ *
+ * best-path is the best access path
*
- * Returns the optimal(?) access plan.
+ * Returns the optimal(?) access plan.
*/
-Plan *
-create_plan(Path *best_path)
+Plan *
+create_plan(Path * best_path)
{
- List *tlist;
- Plan *plan_node = (Plan*)NULL;
- Rel *parent_rel;
- int size;
- int width;
- int pages;
- int tuples;
-
- parent_rel = best_path->parent;
- tlist = get_actual_tlist(parent_rel->targetlist);
- size = parent_rel->size;
- width = parent_rel->width;
- pages = parent_rel->pages;
- tuples = parent_rel->tuples;
-
- switch(best_path->pathtype) {
- case T_IndexScan :
- case T_SeqScan :
- plan_node = (Plan*)create_scan_node(best_path, tlist);
- break;
- case T_HashJoin :
- case T_MergeJoin :
- case T_NestLoop:
- plan_node = (Plan*)create_join_node((JoinPath*)best_path, tlist);
- break;
- default:
- /* do nothing */
- break;
- }
-
- plan_node->plan_size = size;
- plan_node->plan_width = width;
- if (pages == 0) pages = 1;
- plan_node->plan_tupperpage = tuples/pages;
-
-#if 0 /* fix xfunc */
- /* sort clauses by cost/(1-selectivity) -- JMH 2/26/92 */
- if (XfuncMode != XFUNC_OFF)
+ List *tlist;
+ Plan *plan_node = (Plan *) NULL;
+ Rel *parent_rel;
+ int size;
+ int width;
+ int pages;
+ int tuples;
+
+ parent_rel = best_path->parent;
+ tlist = get_actual_tlist(parent_rel->targetlist);
+ size = parent_rel->size;
+ width = parent_rel->width;
+ pages = parent_rel->pages;
+ tuples = parent_rel->tuples;
+
+ switch (best_path->pathtype)
{
- set_qpqual((Plan) plan_node,
- lisp_qsort( get_qpqual((Plan) plan_node),
- xfunc_clause_compare));
- if (XfuncMode != XFUNC_NOR)
- /* sort the disjuncts within each clause by cost -- JMH 3/4/92 */
- xfunc_disjunct_sort(plan_node->qpqual);
+ case T_IndexScan:
+ case T_SeqScan:
+ plan_node = (Plan *) create_scan_node(best_path, tlist);
+ break;
+ case T_HashJoin:
+ case T_MergeJoin:
+ case T_NestLoop:
+ plan_node = (Plan *) create_join_node((JoinPath *) best_path, tlist);
+ break;
+ default:
+ /* do nothing */
+ break;
+ }
+
+ plan_node->plan_size = size;
+ plan_node->plan_width = width;
+ if (pages == 0)
+ pages = 1;
+ plan_node->plan_tupperpage = tuples / pages;
+
+#if 0 /* fix xfunc */
+ /* sort clauses by cost/(1-selectivity) -- JMH 2/26/92 */
+ if (XfuncMode != XFUNC_OFF)
+ {
+ set_qpqual((Plan) plan_node,
+ lisp_qsort(get_qpqual((Plan) plan_node),
+ xfunc_clause_compare));
+ if (XfuncMode != XFUNC_NOR)
+ /* sort the disjuncts within each clause by cost -- JMH 3/4/92 */
+ xfunc_disjunct_sort(plan_node->qpqual);
}
#endif
-
- return(plan_node);
+
+ return (plan_node);
}
-/*
+/*
* create_scan_node--
- * Create a scan path for the parent relation of 'best-path'.
- *
- * tlist is the targetlist for the base relation scanned by 'best-path'
- *
- * Returns the scan node.
+ * Create a scan path for the parent relation of 'best-path'.
+ *
+ * tlist is the targetlist for the base relation scanned by 'best-path'
+ *
+ * Returns the scan node.
*/
-static Scan *
-create_scan_node(Path *best_path, List *tlist)
+static Scan *
+create_scan_node(Path * best_path, List * tlist)
{
- Scan *node = NULL ;
- List *scan_clauses;
-
- /*
- * Extract the relevant clauses from the parent relation and replace the
- * operator OIDs with the corresponding regproc ids.
- *
- * now that local predicate clauses are copied into paths in
- * find_rel_paths() and then (possibly) pulled up in xfunc_trypullup(),
- * we get the relevant clauses from the path itself, not its parent
- * relation. --- JMH, 6/15/92
- */
- scan_clauses = fix_opids(get_actual_clauses(best_path->locclauseinfo));
-
- switch(best_path->pathtype) {
- case T_SeqScan :
- node = (Scan*)create_seqscan_node(best_path, tlist, scan_clauses);
- break;
-
- case T_IndexScan:
- node = (Scan*)create_indexscan_node((IndexPath*)best_path,
- tlist,
- scan_clauses);
- break;
-
- default :
- elog(WARN, "create_scan_node: unknown node type",
- best_path->pathtype);
- break;
- }
-
- return node;
+ Scan *node = NULL;
+ List *scan_clauses;
+
+ /*
+ * Extract the relevant clauses from the parent relation and replace
+ * the operator OIDs with the corresponding regproc ids.
+ *
+ * now that local predicate clauses are copied into paths in
+ * find_rel_paths() and then (possibly) pulled up in
+ * xfunc_trypullup(), we get the relevant clauses from the path
+ * itself, not its parent relation. --- JMH, 6/15/92
+ */
+ scan_clauses = fix_opids(get_actual_clauses(best_path->locclauseinfo));
+
+ switch (best_path->pathtype)
+ {
+ case T_SeqScan:
+ node = (Scan *) create_seqscan_node(best_path, tlist, scan_clauses);
+ break;
+
+ case T_IndexScan:
+ node = (Scan *) create_indexscan_node((IndexPath *) best_path,
+ tlist,
+ scan_clauses);
+ break;
+
+ default:
+ elog(WARN, "create_scan_node: unknown node type",
+ best_path->pathtype);
+ break;
+ }
+
+ return node;
}
-/*
+/*
* create_join_node --
- * Create a join path for 'best-path' and(recursively) paths for its
- * inner and outer paths.
- *
- * 'tlist' is the targetlist for the join relation corresponding to
- * 'best-path'
- *
- * Returns the join node.
+ * Create a join path for 'best-path' and(recursively) paths for its
+ * inner and outer paths.
+ *
+ * 'tlist' is the targetlist for the join relation corresponding to
+ * 'best-path'
+ *
+ * Returns the join node.
*/
-static Join *
-create_join_node(JoinPath *best_path, List *tlist)
+static Join *
+create_join_node(JoinPath * best_path, List * tlist)
{
- Plan *outer_node;
- List *outer_tlist;
- Plan *inner_node;
- List *inner_tlist;
- List *clauses;
- Join *retval = NULL;
-
- outer_node = create_plan((Path*)best_path->outerjoinpath);
- outer_tlist = outer_node->targetlist;
-
- inner_node = create_plan((Path*)best_path->innerjoinpath);
- inner_tlist = inner_node->targetlist;
-
- clauses = get_actual_clauses(best_path->pathclauseinfo);
-
- switch(best_path->path.pathtype) {
- case T_MergeJoin:
- retval = (Join*)create_mergejoin_node((MergePath*)best_path,
- tlist,
- clauses,
- outer_node,
- outer_tlist,
- inner_node,
- inner_tlist);
- break;
- case T_HashJoin:
- retval = (Join*)create_hashjoin_node((HashPath*)best_path,
- tlist,
- clauses,
- outer_node,
- outer_tlist,
- inner_node,
- inner_tlist);
- break;
- case T_NestLoop:
- retval = (Join*)create_nestloop_node((JoinPath*)best_path,
- tlist,
- clauses,
- outer_node,
- outer_tlist,
- inner_node,
- inner_tlist);
- break;
- default:
- /* do nothing */
- elog(WARN, "create_join_node: unknown node type",
- best_path->path.pathtype);
- }
+ Plan *outer_node;
+ List *outer_tlist;
+ Plan *inner_node;
+ List *inner_tlist;
+ List *clauses;
+ Join *retval = NULL;
+
+ outer_node = create_plan((Path *) best_path->outerjoinpath);
+ outer_tlist = outer_node->targetlist;
+
+ inner_node = create_plan((Path *) best_path->innerjoinpath);
+ inner_tlist = inner_node->targetlist;
+
+ clauses = get_actual_clauses(best_path->pathclauseinfo);
+
+ switch (best_path->path.pathtype)
+ {
+ case T_MergeJoin:
+ retval = (Join *) create_mergejoin_node((MergePath *) best_path,
+ tlist,
+ clauses,
+ outer_node,
+ outer_tlist,
+ inner_node,
+ inner_tlist);
+ break;
+ case T_HashJoin:
+ retval = (Join *) create_hashjoin_node((HashPath *) best_path,
+ tlist,
+ clauses,
+ outer_node,
+ outer_tlist,
+ inner_node,
+ inner_tlist);
+ break;
+ case T_NestLoop:
+ retval = (Join *) create_nestloop_node((JoinPath *) best_path,
+ tlist,
+ clauses,
+ outer_node,
+ outer_tlist,
+ inner_node,
+ inner_tlist);
+ break;
+ default:
+ /* do nothing */
+ elog(WARN, "create_join_node: unknown node type",
+ best_path->path.pathtype);
+ }
#if 0
- /*
- ** Expensive function pullups may have pulled local predicates
- ** into this path node. Put them in the qpqual of the plan node.
- ** -- JMH, 6/15/92
- */
- if (get_locclauseinfo(best_path) != NIL)
- set_qpqual((Plan)retval,
- nconc(get_qpqual((Plan) retval),
- fix_opids(get_actual_clauses
- (get_locclauseinfo(best_path)))));
+
+ /*
+ * * Expensive function pullups may have pulled local predicates *
+ * into this path node. Put them in the qpqual of the plan node. *
+ * -- JMH, 6/15/92
+ */
+ if (get_locclauseinfo(best_path) != NIL)
+ set_qpqual((Plan) retval,
+ nconc(get_qpqual((Plan) retval),
+ fix_opids(get_actual_clauses
+ (get_locclauseinfo(best_path)))));
#endif
- return(retval);
+ return (retval);
}
/*****************************************************************************
*
- * BASE-RELATION SCAN METHODS
+ * BASE-RELATION SCAN METHODS
*
*****************************************************************************/
-
-/*
+
+/*
* create_seqscan_node--
- * Returns a seqscan node for the base relation scanned by 'best-path'
- * with restriction clauses 'scan-clauses' and targetlist 'tlist'.
+ * Returns a seqscan node for the base relation scanned by 'best-path'
+ * with restriction clauses 'scan-clauses' and targetlist 'tlist'.
*/
static SeqScan *
-create_seqscan_node(Path *best_path, List *tlist, List *scan_clauses)
+create_seqscan_node(Path * best_path, List * tlist, List * scan_clauses)
{
- SeqScan *scan_node = (SeqScan*)NULL;
- Index scan_relid = -1;
- List *temp;
-
- temp = best_path->parent->relids;
- if(temp == NULL)
- elog(WARN,"scanrelid is empty");
- else
- scan_relid = (Index)lfirsti(temp); /* ??? who takes care of lnext? - ay */
- scan_node = make_seqscan(tlist,
- scan_clauses,
- scan_relid,
- (Plan*)NULL);
-
- scan_node->plan.cost = best_path->path_cost;
-
- return(scan_node);
+ SeqScan *scan_node = (SeqScan *) NULL;
+ Index scan_relid = -1;
+ List *temp;
+
+ temp = best_path->parent->relids;
+ if (temp == NULL)
+ elog(WARN, "scanrelid is empty");
+ else
+ scan_relid = (Index) lfirsti(temp); /* ??? who takes care of
+ * lnext? - ay */
+ scan_node = make_seqscan(tlist,
+ scan_clauses,
+ scan_relid,
+ (Plan *) NULL);
+
+ scan_node->plan.cost = best_path->path_cost;
+
+ return (scan_node);
}
-/*
+/*
* create_indexscan_node--
- * Returns a indexscan node for the base relation scanned by 'best-path'
- * with restriction clauses 'scan-clauses' and targetlist 'tlist'.
+ * Returns a indexscan node for the base relation scanned by 'best-path'
+ * with restriction clauses 'scan-clauses' and targetlist 'tlist'.
*/
static IndexScan *
-create_indexscan_node(IndexPath *best_path,
- List *tlist,
- List *scan_clauses)
+create_indexscan_node(IndexPath * best_path,
+ List * tlist,
+ List * scan_clauses)
{
- /*
- * Extract the(first if conjunct, only if disjunct) clause from the
- * clauseinfo list.
- */
- Expr *index_clause = (Expr*)NULL;
- List *indxqual = NIL;
- List *qpqual = NIL;
- List *fixed_indxqual = NIL;
- List *ixid;
- IndexScan *scan_node = (IndexScan*)NULL;
- bool lossy = FALSE;
- HeapTuple indexTuple;
- IndexTupleForm index;
-
- /*
- * If an 'or' clause is to be used with this index, the indxqual
- * field will contain a list of the 'or' clause arguments, e.g., the
- * clause(OR a b c) will generate: ((a) (b) (c)). Otherwise, the
- * indxqual will simply contain one conjunctive qualification: ((a)).
- */
- if (best_path->indexqual != NULL)
- /* added call to fix_opids, JMH 6/23/92 */
- index_clause = (Expr*)
- lfirst(fix_opids(get_actual_clauses(best_path->indexqual)));
-
- if (or_clause((Node*)index_clause)) {
- List *temp = NIL;
-
- foreach(temp, index_clause->args)
- indxqual = lappend(indxqual, lcons(lfirst(temp), NIL));
- } else {
- indxqual = lcons(get_actual_clauses(best_path->indexqual),
- NIL);
- }
-
- /* check and see if any indices are lossy */
- foreach (ixid, best_path->indexid) {
- indexTuple = SearchSysCacheTuple(INDEXRELID,
- ObjectIdGetDatum(lfirsti(ixid)),
- 0,0,0);
- if (!HeapTupleIsValid(indexTuple))
- elog(WARN, "create_plan: index %d not found",
- lfirsti(ixid));
- index = (IndexTupleForm)GETSTRUCT(indexTuple);
- if (index->indislossy)
- lossy = TRUE;
- }
-
-
- /*
- * The qpqual field contains all restrictions not automatically handled
- * by the index. Note that for non-lossy indices, the predicates
- * in the indxqual are handled by the index, while for lossy indices
- * the indxqual predicates need to be double-checked after the
- * index fetches the best-guess tuples.
- */
- if(or_clause((Node*)index_clause)) {
- qpqual = set_difference(scan_clauses,
- lcons(index_clause,NIL));
-
- if (lossy)
- qpqual = nconc(qpqual,
- lcons((List *)copyObject(index_clause),NIL));
- }
- else {
- qpqual = set_difference(scan_clauses, lfirst(indxqual));
- if (lossy)
- qpqual = nconc(qpqual,
- (List *)copyObject(lfirst(indxqual)));
- }
-
- fixed_indxqual =
- (List*)fix_indxqual_references((Node*)indxqual,(Path*)best_path);
-
- scan_node =
- make_indexscan(tlist,
- qpqual,
- lfirsti(best_path->path.parent->relids),
- best_path->indexid,
- fixed_indxqual);
-
- scan_node->scan.plan.cost = best_path->path.path_cost;
-
- return(scan_node);
+
+ /*
+ * Extract the(first if conjunct, only if disjunct) clause from the
+ * clauseinfo list.
+ */
+ Expr *index_clause = (Expr *) NULL;
+ List *indxqual = NIL;
+ List *qpqual = NIL;
+ List *fixed_indxqual = NIL;
+ List *ixid;
+ IndexScan *scan_node = (IndexScan *) NULL;
+ bool lossy = FALSE;
+ HeapTuple indexTuple;
+ IndexTupleForm index;
+
+ /*
+ * If an 'or' clause is to be used with this index, the indxqual field
+ * will contain a list of the 'or' clause arguments, e.g., the
+ * clause(OR a b c) will generate: ((a) (b) (c)). Otherwise, the
+ * indxqual will simply contain one conjunctive qualification: ((a)).
+ */
+ if (best_path->indexqual != NULL)
+ /* added call to fix_opids, JMH 6/23/92 */
+ index_clause = (Expr *)
+ lfirst(fix_opids(get_actual_clauses(best_path->indexqual)));
+
+ if (or_clause((Node *) index_clause))
+ {
+ List *temp = NIL;
+
+ foreach(temp, index_clause->args)
+ indxqual = lappend(indxqual, lcons(lfirst(temp), NIL));
+ }
+ else
+ {
+ indxqual = lcons(get_actual_clauses(best_path->indexqual),
+ NIL);
+ }
+
+ /* check and see if any indices are lossy */
+ foreach(ixid, best_path->indexid)
+ {
+ indexTuple = SearchSysCacheTuple(INDEXRELID,
+ ObjectIdGetDatum(lfirsti(ixid)),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(indexTuple))
+ elog(WARN, "create_plan: index %d not found",
+ lfirsti(ixid));
+ index = (IndexTupleForm) GETSTRUCT(indexTuple);
+ if (index->indislossy)
+ lossy = TRUE;
+ }
+
+
+ /*
+ * The qpqual field contains all restrictions not automatically
+ * handled by the index. Note that for non-lossy indices, the
+ * predicates in the indxqual are handled by the index, while for
+ * lossy indices the indxqual predicates need to be double-checked
+ * after the index fetches the best-guess tuples.
+ */
+ if (or_clause((Node *) index_clause))
+ {
+ qpqual = set_difference(scan_clauses,
+ lcons(index_clause, NIL));
+
+ if (lossy)
+ qpqual = nconc(qpqual,
+ lcons((List *) copyObject(index_clause), NIL));
+ }
+ else
+ {
+ qpqual = set_difference(scan_clauses, lfirst(indxqual));
+ if (lossy)
+ qpqual = nconc(qpqual,
+ (List *) copyObject(lfirst(indxqual)));
+ }
+
+ fixed_indxqual =
+ (List *) fix_indxqual_references((Node *) indxqual, (Path *) best_path);
+
+ scan_node =
+ make_indexscan(tlist,
+ qpqual,
+ lfirsti(best_path->path.parent->relids),
+ best_path->indexid,
+ fixed_indxqual);
+
+ scan_node->scan.plan.cost = best_path->path.path_cost;
+
+ return (scan_node);
}
/*****************************************************************************
*
- * JOIN METHODS
+ * JOIN METHODS
*
*****************************************************************************/
static NestLoop *
-create_nestloop_node(JoinPath *best_path,
- List *tlist,
- List *clauses,
- Plan *outer_node,
- List *outer_tlist,
- Plan *inner_node,
- List *inner_tlist)
+create_nestloop_node(JoinPath * best_path,
+ List * tlist,
+ List * clauses,
+ Plan * outer_node,
+ List * outer_tlist,
+ Plan * inner_node,
+ List * inner_tlist)
{
- NestLoop *join_node = (NestLoop*)NULL;
+ NestLoop *join_node = (NestLoop *) NULL;
- if (IsA(inner_node,IndexScan)) {
- /* An index is being used to reduce the number of tuples scanned in
- * the inner relation. There will never be more than one index used
- * in the inner scan path, so we need only consider the first set of
- * qualifications in indxqual.
- *
- * But there may be more than one clauses in this "first set"
- * in the case of multi-column indices. - vadim 03/18/97
- */
+ if (IsA(inner_node, IndexScan))
+ {
- List *inner_indxqual = lfirst(((IndexScan*)inner_node)->indxqual);
- List *inner_qual;
- bool found = false;
+ /*
+ * An index is being used to reduce the number of tuples scanned
+ * in the inner relation. There will never be more than one index
+ * used in the inner scan path, so we need only consider the first
+ * set of qualifications in indxqual.
+ *
+ * But there may be more than one clauses in this "first set" in the
+ * case of multi-column indices. - vadim 03/18/97
+ */
+
+ List *inner_indxqual = lfirst(((IndexScan *) inner_node)->indxqual);
+ List *inner_qual;
+ bool found = false;
+
+ foreach(inner_qual, inner_indxqual)
+ {
+ if (!qual_clause_p((Node *) lfirst(inner_qual)))
+ {
+ found = true;
+ break;
+ }
+ }
- foreach (inner_qual, inner_indxqual)
- {
- if ( !qual_clause_p ((Node*)lfirst(inner_qual)) )
- {
- found = true;
- break;
- }
+ /*
+ * If we have in fact found a join index qualification, remove
+ * these index clauses from the nestloop's join clauses and reset
+ * the inner(index) scan's qualification so that the var nodes
+ * refer to the proper outer join relation attributes.
+ *
+ * XXX Re-moving index clauses doesn't work properly: 1.
+ * fix_indxqual_references may change varattno-s in
+ * inner_indxqual; 2. clauses may be commuted I havn't time to fix
+ * it at the moment. - vadim 04/24/97
+ */
+ if (found)
+ {
+ List *new_inner_qual = NIL;
+
+ clauses = set_difference(clauses, inner_indxqual); /* XXX */
+ new_inner_qual =
+ index_outerjoin_references(inner_indxqual,
+ outer_node->targetlist,
+ ((Scan *) inner_node)->scanrelid);
+ ((IndexScan *) inner_node)->indxqual =
+ lcons(new_inner_qual, NIL);
+ }
}
-
- /* If we have in fact found a join index qualification, remove these
- * index clauses from the nestloop's join clauses and reset the
- * inner(index) scan's qualification so that the var nodes refer to
- * the proper outer join relation attributes.
- *
- * XXX Re-moving index clauses doesn't work properly:
- * 1. fix_indxqual_references may change varattno-s in
- * inner_indxqual;
- * 2. clauses may be commuted
- * I havn't time to fix it at the moment. - vadim 04/24/97
- */
- if ( found )
+ else if (IsA_Join(inner_node))
{
- List *new_inner_qual = NIL;
-
- clauses = set_difference(clauses,inner_indxqual); /* XXX */
- new_inner_qual =
- index_outerjoin_references(inner_indxqual,
- outer_node->targetlist,
- ((Scan*)inner_node)->scanrelid);
- ((IndexScan*)inner_node)->indxqual =
- lcons(new_inner_qual,NIL);
+ inner_node = (Plan *) make_temp(inner_tlist,
+ NIL,
+ NULL,
+ inner_node,
+ TEMP_MATERIAL);
}
- }else if (IsA_Join(inner_node)) {
- inner_node = (Plan*)make_temp(inner_tlist,
- NIL,
- NULL,
- inner_node,
- TEMP_MATERIAL);
- }
-
- join_node = make_nestloop(tlist,
- join_references(clauses,
- outer_tlist,
- inner_tlist),
- outer_node,
- inner_node);
-
- join_node->join.cost = best_path->path.path_cost;
-
- return(join_node);
+
+ join_node = make_nestloop(tlist,
+ join_references(clauses,
+ outer_tlist,
+ inner_tlist),
+ outer_node,
+ inner_node);
+
+ join_node->join.cost = best_path->path.path_cost;
+
+ return (join_node);
}
static MergeJoin *
-create_mergejoin_node(MergePath *best_path,
- List *tlist,
- List *clauses,
- Plan *outer_node,
- List *outer_tlist,
- Plan *inner_node,
- List *inner_tlist)
+create_mergejoin_node(MergePath * best_path,
+ List * tlist,
+ List * clauses,
+ Plan * outer_node,
+ List * outer_tlist,
+ Plan * inner_node,
+ List * inner_tlist)
{
- List *qpqual, *mergeclauses;
- RegProcedure opcode;
- Oid *outer_order, *inner_order;
- MergeJoin *join_node;
-
-
- /* Separate the mergeclauses from the other join qualification
- * clauses and set those clauses to contain references to lower
- * attributes.
- */
- qpqual = join_references(set_difference(clauses,
- best_path->path_mergeclauses),
- outer_tlist,
- inner_tlist);
-
- /* Now set the references in the mergeclauses and rearrange them so
- * that the outer variable is always on the left.
- */
- mergeclauses = switch_outer(join_references(best_path->path_mergeclauses,
- outer_tlist,
- inner_tlist));
-
- opcode =
- get_opcode((best_path->jpath.path.p_ordering.ord.merge)->join_operator);
-
- outer_order = (Oid *)palloc(sizeof(Oid)*2);
- outer_order[0] =
- (best_path->jpath.path.p_ordering.ord.merge)->left_operator;
- outer_order[1] = 0;
-
- inner_order = (Oid *)palloc(sizeof(Oid)*2);
- inner_order[0] =
- (best_path->jpath.path.p_ordering.ord.merge)->right_operator;
- inner_order[1] = 0;
-
- /* Create explicit sort paths for the outer and inner join paths if
- * necessary. The sort cost was already accounted for in the path.
- */
- if (best_path->outersortkeys) {
- Temp *sorted_outer_node = make_temp(outer_tlist,
- best_path->outersortkeys,
- outer_order,
- outer_node,
- TEMP_SORT);
- sorted_outer_node->plan.cost = outer_node->cost;
- outer_node = (Plan*)sorted_outer_node;
- }
-
- if (best_path->innersortkeys) {
- Temp *sorted_inner_node = make_temp(inner_tlist,
- best_path->innersortkeys,
- inner_order,
- inner_node,
- TEMP_SORT);
- sorted_inner_node->plan.cost = outer_node->cost;
- inner_node = (Plan*)sorted_inner_node;
- }
-
- join_node = make_mergesort(tlist,
- qpqual,
- mergeclauses,
- opcode,
- inner_order,
- outer_order,
- inner_node,
- outer_node);
-
- join_node->join.cost = best_path->jpath.path.path_cost;
-
- return(join_node);
+ List *qpqual,
+ *mergeclauses;
+ RegProcedure opcode;
+ Oid *outer_order,
+ *inner_order;
+ MergeJoin *join_node;
+
+
+ /*
+ * Separate the mergeclauses from the other join qualification clauses
+ * and set those clauses to contain references to lower attributes.
+ */
+ qpqual = join_references(set_difference(clauses,
+ best_path->path_mergeclauses),
+ outer_tlist,
+ inner_tlist);
+
+ /*
+ * Now set the references in the mergeclauses and rearrange them so
+ * that the outer variable is always on the left.
+ */
+ mergeclauses = switch_outer(join_references(best_path->path_mergeclauses,
+ outer_tlist,
+ inner_tlist));
+
+ opcode =
+ get_opcode((best_path->jpath.path.p_ordering.ord.merge)->join_operator);
+
+ outer_order = (Oid *) palloc(sizeof(Oid) * 2);
+ outer_order[0] =
+ (best_path->jpath.path.p_ordering.ord.merge)->left_operator;
+ outer_order[1] = 0;
+
+ inner_order = (Oid *) palloc(sizeof(Oid) * 2);
+ inner_order[0] =
+ (best_path->jpath.path.p_ordering.ord.merge)->right_operator;
+ inner_order[1] = 0;
+
+ /*
+ * Create explicit sort paths for the outer and inner join paths if
+ * necessary. The sort cost was already accounted for in the path.
+ */
+ if (best_path->outersortkeys)
+ {
+ Temp *sorted_outer_node = make_temp(outer_tlist,
+ best_path->outersortkeys,
+ outer_order,
+ outer_node,
+ TEMP_SORT);
+
+ sorted_outer_node->plan.cost = outer_node->cost;
+ outer_node = (Plan *) sorted_outer_node;
+ }
+
+ if (best_path->innersortkeys)
+ {
+ Temp *sorted_inner_node = make_temp(inner_tlist,
+ best_path->innersortkeys,
+ inner_order,
+ inner_node,
+ TEMP_SORT);
+
+ sorted_inner_node->plan.cost = outer_node->cost;
+ inner_node = (Plan *) sorted_inner_node;
+ }
+
+ join_node = make_mergesort(tlist,
+ qpqual,
+ mergeclauses,
+ opcode,
+ inner_order,
+ outer_order,
+ inner_node,
+ outer_node);
+
+ join_node->join.cost = best_path->jpath.path.path_cost;
+
+ return (join_node);
}
-/*
- * create_hashjoin_node-- XXX HASH
- *
- * Returns a new hashjoin node.
- *
- * XXX hash join ops are totally bogus -- how the hell do we choose
- * these?? at runtime? what about a hash index?
+/*
+ * create_hashjoin_node-- XXX HASH
+ *
+ * Returns a new hashjoin node.
+ *
+ * XXX hash join ops are totally bogus -- how the hell do we choose
+ * these?? at runtime? what about a hash index?
*/
static HashJoin *
-create_hashjoin_node(HashPath *best_path,
- List *tlist,
- List *clauses,
- Plan *outer_node,
- List *outer_tlist,
- Plan *inner_node,
- List *inner_tlist)
+create_hashjoin_node(HashPath * best_path,
+ List * tlist,
+ List * clauses,
+ Plan * outer_node,
+ List * outer_tlist,
+ Plan * inner_node,
+ List * inner_tlist)
{
- List *qpqual;
- List *hashclauses;
- HashJoin *join_node;
- Hash *hash_node;
- Var *innerhashkey;
-
- /* Separate the hashclauses from the other join qualification clauses
- * and set those clauses to contain references to lower attributes.
- */
- qpqual =
- join_references(set_difference(clauses,
- best_path->path_hashclauses),
- outer_tlist,
- inner_tlist);
-
- /* Now set the references in the hashclauses and rearrange them so
- * that the outer variable is always on the left.
- */
- hashclauses =
- switch_outer(join_references(best_path->path_hashclauses,
- outer_tlist,
- inner_tlist));
-
- innerhashkey = get_rightop(lfirst(hashclauses));
-
- hash_node = make_hash(inner_tlist, innerhashkey, inner_node);
- join_node = make_hashjoin(tlist,
- qpqual,
- hashclauses,
- outer_node,
- (Plan*)hash_node);
- join_node->join.cost = best_path->jpath.path.path_cost;
-
- return(join_node);
+ List *qpqual;
+ List *hashclauses;
+ HashJoin *join_node;
+ Hash *hash_node;
+ Var *innerhashkey;
+
+ /*
+ * Separate the hashclauses from the other join qualification clauses
+ * and set those clauses to contain references to lower attributes.
+ */
+ qpqual =
+ join_references(set_difference(clauses,
+ best_path->path_hashclauses),
+ outer_tlist,
+ inner_tlist);
+
+ /*
+ * Now set the references in the hashclauses and rearrange them so
+ * that the outer variable is always on the left.
+ */
+ hashclauses =
+ switch_outer(join_references(best_path->path_hashclauses,
+ outer_tlist,
+ inner_tlist));
+
+ innerhashkey = get_rightop(lfirst(hashclauses));
+
+ hash_node = make_hash(inner_tlist, innerhashkey, inner_node);
+ join_node = make_hashjoin(tlist,
+ qpqual,
+ hashclauses,
+ outer_node,
+ (Plan *) hash_node);
+ join_node->join.cost = best_path->jpath.path.path_cost;
+
+ return (join_node);
}
/*****************************************************************************
*
- * SUPPORTING ROUTINES
+ * SUPPORTING ROUTINES
*
*****************************************************************************/
-static Node *
-fix_indxqual_references(Node *clause, Path *index_path)
+static Node *
+fix_indxqual_references(Node * clause, Path * index_path)
{
- Node *newclause;
-
- if (IsA(clause,Var)) {
- if (lfirsti(index_path->parent->relids) == ((Var*)clause)->varno) {
- int pos = 0;
- int varatt = ((Var*)clause)->varattno;
- int *indexkeys = ((IndexPath*)index_path)->indexkeys;
-
- if (indexkeys) {
- while (indexkeys[pos] != 0) {
- if(varatt == indexkeys[pos]) {
- break;
- }
- pos++;
+ Node *newclause;
+
+ if (IsA(clause, Var))
+ {
+ if (lfirsti(index_path->parent->relids) == ((Var *) clause)->varno)
+ {
+ int pos = 0;
+ int varatt = ((Var *) clause)->varattno;
+ int *indexkeys = ((IndexPath *) index_path)->indexkeys;
+
+ if (indexkeys)
+ {
+ while (indexkeys[pos] != 0)
+ {
+ if (varatt == indexkeys[pos])
+ {
+ break;
+ }
+ pos++;
+ }
+ }
+ newclause = copyObject((Node *) clause);
+ ((Var *) newclause)->varattno = pos + 1;
+ return (newclause);
+ }
+ else
+ {
+ return (clause);
}
- }
- newclause = copyObject((Node*)clause);
- ((Var*)newclause)->varattno = pos + 1;
- return (newclause);
- } else {
- return (clause);
}
- } else if(IsA(clause,Const)) {
- return(clause);
+ else if (IsA(clause, Const))
+ {
+ return (clause);
#ifdef INDEXSCAN_PATCH
- } else if(IsA(clause,Param)) {
- /* Function parameter used as index scan arg. DZ - 27-8-1996 */
- return(clause);
+ }
+ else if (IsA(clause, Param))
+ {
+ /* Function parameter used as index scan arg. DZ - 27-8-1996 */
+ return (clause);
#endif
- } else if(is_opclause(clause) &&
- is_funcclause((Node*)get_leftop((Expr*)clause)) &&
- ((Func*)((Expr*)get_leftop((Expr*)clause))->oper)->funcisindex){
- Var *newvar =
- makeVar((Index)lfirsti(index_path->parent->relids),
- 1, /* func indices have one key */
- ((Func*)((Expr*)clause)->oper)->functype,
- (Index)lfirsti(index_path->parent->relids),
- 0);
-
- return
- ((Node*)make_opclause((Oper*)((Expr*)clause)->oper,
- newvar,
- get_rightop((Expr*)clause)));
-
- } else if (IsA(clause,Expr)) {
- Expr *expr = (Expr*)clause;
- List *new_subclauses = NIL;
- Node *subclause = NULL;
- List *i = NIL;
-
- foreach(i, expr->args) {
- subclause = lfirst(i);
- if(subclause)
- new_subclauses =
- lappend(new_subclauses,
- fix_indxqual_references(subclause,
- index_path));
+ }
+ else if (is_opclause(clause) &&
+ is_funcclause((Node *) get_leftop((Expr *) clause)) &&
+ ((Func *) ((Expr *) get_leftop((Expr *) clause))->oper)->funcisindex)
+ {
+ Var *newvar =
+ makeVar((Index) lfirsti(index_path->parent->relids),
+ 1, /* func indices have one key */
+ ((Func *) ((Expr *) clause)->oper)->functype,
+ (Index) lfirsti(index_path->parent->relids),
+ 0);
+
+ return
+ ((Node *) make_opclause((Oper *) ((Expr *) clause)->oper,
+ newvar,
+ get_rightop((Expr *) clause)));
}
-
- /* XXX new_subclauses should be a list of the form:
- * ( (var var) (var const) ...) ?
- */
- if(new_subclauses) {
- return (Node*)
- make_clause(expr->opType, expr->oper, new_subclauses);
- } else {
- return(clause);
- }
- } else {
- List *oldclauses = (List*)clause;
- List *new_subclauses = NIL;
- Node *subclause = NULL;
- List *i = NIL;
-
- foreach(i, oldclauses) {
- subclause = lfirst(i);
- if(subclause)
- new_subclauses =
- lappend(new_subclauses,
- fix_indxqual_references(subclause,
- index_path));
+ else if (IsA(clause, Expr))
+ {
+ Expr *expr = (Expr *) clause;
+ List *new_subclauses = NIL;
+ Node *subclause = NULL;
+ List *i = NIL;
+
+ foreach(i, expr->args)
+ {
+ subclause = lfirst(i);
+ if (subclause)
+ new_subclauses =
+ lappend(new_subclauses,
+ fix_indxqual_references(subclause,
+ index_path));
+
+ }
+
+ /*
+ * XXX new_subclauses should be a list of the form: ( (var var)
+ * (var const) ...) ?
+ */
+ if (new_subclauses)
+ {
+ return (Node *)
+ make_clause(expr->opType, expr->oper, new_subclauses);
+ }
+ else
+ {
+ return (clause);
+ }
+ }
+ else
+ {
+ List *oldclauses = (List *) clause;
+ List *new_subclauses = NIL;
+ Node *subclause = NULL;
+ List *i = NIL;
+
+ foreach(i, oldclauses)
+ {
+ subclause = lfirst(i);
+ if (subclause)
+ new_subclauses =
+ lappend(new_subclauses,
+ fix_indxqual_references(subclause,
+ index_path));
+
+ }
+ /*
+ * XXX new_subclauses should be a list of the form: ( (var var)
+ * (var const) ...) ?
+ */
+ if (new_subclauses)
+ {
+ return (Node *) new_subclauses;
+ }
+ else
+ {
+ return (clause);
+ }
}
-
- /* XXX new_subclauses should be a list of the form:
- * ( (var var) (var const) ...) ?
- */
- if(new_subclauses) {
- return (Node*)new_subclauses;
- } else {
- return (clause);
- }
- }
}
-/*
+/*
* switch_outer--
- * Given a list of merge clauses, rearranges the elements within the
- * clauses so the outer join variable is on the left and the inner is on
- * the right.
- *
- * Returns the rearranged list ?
- *
- * XXX Shouldn't the operator be commuted?!
+ * Given a list of merge clauses, rearranges the elements within the
+ * clauses so the outer join variable is on the left and the inner is on
+ * the right.
+ *
+ * Returns the rearranged list ?
+ *
+ * XXX Shouldn't the operator be commuted?!
*/
-static List *
-switch_outer(List *clauses)
+static List *
+switch_outer(List * clauses)
{
- List *t_list = NIL;
- Expr *temp = NULL;
- List *i = NIL;
- Expr *clause;
- Node *op;
-
- foreach(i,clauses) {
- clause = lfirst(i);
- op = (Node*)get_rightop(clause);
- if ( IsA (op, ArrayRef) )
- op = ((ArrayRef*)op)->refexpr;
- Assert ( IsA (op, Var) );
- if ( var_is_outer ((Var*)op) )
+ List *t_list = NIL;
+ Expr *temp = NULL;
+ List *i = NIL;
+ Expr *clause;
+ Node *op;
+
+ foreach(i, clauses)
{
- temp = make_clause(clause->opType, clause->oper,
- lcons(get_rightop(clause),
- lcons(get_leftop(clause),
- NIL)));
- t_list = lappend(t_list,temp);
- }
- else
- t_list = lappend(t_list,clause);
- }
- return(t_list);
+ clause = lfirst(i);
+ op = (Node *) get_rightop(clause);
+ if (IsA(op, ArrayRef))
+ op = ((ArrayRef *) op)->refexpr;
+ Assert(IsA(op, Var));
+ if (var_is_outer((Var *) op))
+ {
+ temp = make_clause(clause->opType, clause->oper,
+ lcons(get_rightop(clause),
+ lcons(get_leftop(clause),
+ NIL)));
+ t_list = lappend(t_list, temp);
+ }
+ else
+ t_list = lappend(t_list, clause);
+ }
+ return (t_list);
}
-/*
+/*
* set-temp-tlist-operators--
- * Sets the key and keyop fields of resdom nodes in a target list.
- *
- * 'tlist' is the target list
- * 'pathkeys' is a list of N keys in the form((key1) (key2)...(keyn)),
- * corresponding to vars in the target list that are to
- * be sorted or hashed
- * 'operators' is the corresponding list of N sort or hash operators
- * 'keyno' is the first key number
- * XXX - keyno ? doesn't exist - jeff
- *
- * Returns the modified target list.
+ * Sets the key and keyop fields of resdom nodes in a target list.
+ *
+ * 'tlist' is the target list
+ * 'pathkeys' is a list of N keys in the form((key1) (key2)...(keyn)),
+ * corresponding to vars in the target list that are to
+ * be sorted or hashed
+ * 'operators' is the corresponding list of N sort or hash operators
+ * 'keyno' is the first key number
+ * XXX - keyno ? doesn't exist - jeff
+ *
+ * Returns the modified target list.
*/
-static List *
-set_temp_tlist_operators(List *tlist, List *pathkeys, Oid *operators)
+static List *
+set_temp_tlist_operators(List * tlist, List * pathkeys, Oid * operators)
{
- Node *keys = NULL;
- int keyno = 1;
- Resdom *resdom = (Resdom*)NULL ;
- List *i = NIL;
-
- foreach(i, pathkeys) {
- keys = lfirst((List*)lfirst(i));
- resdom = tlist_member((Var*)keys, tlist);
- if (resdom) {
-
- /* Order the resdom keys and replace the operator OID for each
- * key with the regproc OID.
- *
- * XXX Note that the optimizer only generates merge joins
- * with 1 operator (see create_mergejoin_node) - ay 2/95
- */
- resdom->reskey = keyno;
- resdom->reskeyop = get_opcode(operators[0]);
+ Node *keys = NULL;
+ int keyno = 1;
+ Resdom *resdom = (Resdom *) NULL;
+ List *i = NIL;
+
+ foreach(i, pathkeys)
+ {
+ keys = lfirst((List *) lfirst(i));
+ resdom = tlist_member((Var *) keys, tlist);
+ if (resdom)
+ {
+
+ /*
+ * Order the resdom keys and replace the operator OID for each
+ * key with the regproc OID.
+ *
+ * XXX Note that the optimizer only generates merge joins with 1
+ * operator (see create_mergejoin_node) - ay 2/95
+ */
+ resdom->reskey = keyno;
+ resdom->reskeyop = get_opcode(operators[0]);
+ }
+ keyno += 1;
}
- keyno += 1;
- }
- return(tlist);
+ return (tlist);
}
/*****************************************************************************
@@ -808,355 +878,362 @@ set_temp_tlist_operators(List *tlist, List *pathkeys, Oid *operators)
*
*****************************************************************************/
-/*
+/*
* make_temp--
- * Create plan nodes to sort or materialize relations into temporaries. The
- * result returned for a sort will look like (SEQSCAN(SORT(plan-node)))
- * or (SEQSCAN(MATERIAL(plan-node)))
- *
- * 'tlist' is the target list of the scan to be sorted or hashed
- * 'keys' is the list of keys which the sort or hash will be done on
- * 'operators' is the operators with which the sort or hash is to be done
- * (a list of operator OIDs)
- * 'plan-node' is the node which yields tuples for the sort
- * 'temptype' indicates which operation(sort or hash) to perform
+ * Create plan nodes to sort or materialize relations into temporaries. The
+ * result returned for a sort will look like (SEQSCAN(SORT(plan-node)))
+ * or (SEQSCAN(MATERIAL(plan-node)))
+ *
+ * 'tlist' is the target list of the scan to be sorted or hashed
+ * 'keys' is the list of keys which the sort or hash will be done on
+ * 'operators' is the operators with which the sort or hash is to be done
+ * (a list of operator OIDs)
+ * 'plan-node' is the node which yields tuples for the sort
+ * 'temptype' indicates which operation(sort or hash) to perform
*/
-static Temp *
-make_temp(List *tlist,
- List *keys,
- Oid *operators,
- Plan *plan_node,
- int temptype)
+static Temp *
+make_temp(List * tlist,
+ List * keys,
+ Oid * operators,
+ Plan * plan_node,
+ int temptype)
{
- List *temp_tlist;
- Temp *retval = NULL;
-
- /* Create a new target list for the temporary, with keys set. */
- temp_tlist = set_temp_tlist_operators(new_unsorted_tlist(tlist),
- keys,
- operators);
- switch(temptype) {
- case TEMP_SORT :
- retval = (Temp*)make_seqscan(tlist,
- NIL,
- _TEMP_RELATION_ID_,
- (Plan*)make_sort(temp_tlist,
- _TEMP_RELATION_ID_,
- plan_node,
- length(keys)));
- break;
-
- case TEMP_MATERIAL :
- retval = (Temp*)make_seqscan(tlist,
- NIL,
- _TEMP_RELATION_ID_,
- (Plan*)make_material(temp_tlist,
- _TEMP_RELATION_ID_,
- plan_node,
- length(keys)));
- break;
-
- default:
- elog(WARN,"make_temp: unknown temp type %d", temptype);
-
- }
- return(retval);
+ List *temp_tlist;
+ Temp *retval = NULL;
+
+ /* Create a new target list for the temporary, with keys set. */
+ temp_tlist = set_temp_tlist_operators(new_unsorted_tlist(tlist),
+ keys,
+ operators);
+ switch (temptype)
+ {
+ case TEMP_SORT:
+ retval = (Temp *) make_seqscan(tlist,
+ NIL,
+ _TEMP_RELATION_ID_,
+ (Plan *) make_sort(temp_tlist,
+ _TEMP_RELATION_ID_,
+ plan_node,
+ length(keys)));
+ break;
+
+ case TEMP_MATERIAL:
+ retval = (Temp *) make_seqscan(tlist,
+ NIL,
+ _TEMP_RELATION_ID_,
+ (Plan *) make_material(temp_tlist,
+ _TEMP_RELATION_ID_,
+ plan_node,
+ length(keys)));
+ break;
+
+ default:
+ elog(WARN, "make_temp: unknown temp type %d", temptype);
+
+ }
+ return (retval);
}
-SeqScan *
-make_seqscan(List *qptlist,
- List *qpqual,
- Index scanrelid,
- Plan *lefttree)
+SeqScan *
+make_seqscan(List * qptlist,
+ List * qpqual,
+ Index scanrelid,
+ Plan * lefttree)
{
- SeqScan *node = makeNode(SeqScan);
- Plan *plan = &node->plan;
-
- plan->cost = 0.0;
- plan->state = (EState *)NULL;
- plan->targetlist = qptlist;
- plan->qual = qpqual;
- plan->lefttree = lefttree;
- plan->righttree = NULL;
- node->scanrelid = scanrelid;
- node->scanstate = (CommonScanState *)NULL;
-
- return(node);
+ SeqScan *node = makeNode(SeqScan);
+ Plan *plan = &node->plan;
+
+ plan->cost = 0.0;
+ plan->state = (EState *) NULL;
+ plan->targetlist = qptlist;
+ plan->qual = qpqual;
+ plan->lefttree = lefttree;
+ plan->righttree = NULL;
+ node->scanrelid = scanrelid;
+ node->scanstate = (CommonScanState *) NULL;
+
+ return (node);
}
static IndexScan *
-make_indexscan(List *qptlist,
- List *qpqual,
- Index scanrelid,
- List *indxid,
- List *indxqual)
+make_indexscan(List * qptlist,
+ List * qpqual,
+ Index scanrelid,
+ List * indxid,
+ List * indxqual)
{
- IndexScan *node = makeNode(IndexScan);
- Plan *plan = &node->scan.plan;
-
- plan->cost = 0.0;
- plan->state = (EState *)NULL;
- plan->targetlist = qptlist;
- plan->qual = qpqual;
- plan->lefttree = NULL;
- plan->righttree = NULL;
- node->scan.scanrelid = scanrelid;
- node->indxid = indxid;
- node->indxqual = indxqual;
- node->scan.scanstate = (CommonScanState *)NULL;
-
- return(node);
+ IndexScan *node = makeNode(IndexScan);
+ Plan *plan = &node->scan.plan;
+
+ plan->cost = 0.0;
+ plan->state = (EState *) NULL;
+ plan->targetlist = qptlist;
+ plan->qual = qpqual;
+ plan->lefttree = NULL;
+ plan->righttree = NULL;
+ node->scan.scanrelid = scanrelid;
+ node->indxid = indxid;
+ node->indxqual = indxqual;
+ node->scan.scanstate = (CommonScanState *) NULL;
+
+ return (node);
}
static NestLoop *
-make_nestloop(List *qptlist,
- List *qpqual,
- Plan *lefttree,
- Plan *righttree)
+make_nestloop(List * qptlist,
+ List * qpqual,
+ Plan * lefttree,
+ Plan * righttree)
{
- NestLoop *node = makeNode(NestLoop);
- Plan *plan = &node->join;
-
- plan->cost = 0.0;
- plan->state = (EState *)NULL;
- plan->targetlist = qptlist;
- plan->qual = qpqual;
- plan->lefttree = lefttree;
- plan->righttree = righttree;
- node->nlstate = (NestLoopState*)NULL;
-
- return(node);
+ NestLoop *node = makeNode(NestLoop);
+ Plan *plan = &node->join;
+
+ plan->cost = 0.0;
+ plan->state = (EState *) NULL;
+ plan->targetlist = qptlist;
+ plan->qual = qpqual;
+ plan->lefttree = lefttree;
+ plan->righttree = righttree;
+ node->nlstate = (NestLoopState *) NULL;
+
+ return (node);
}
static HashJoin *
-make_hashjoin(List *tlist,
- List *qpqual,
- List *hashclauses,
- Plan *lefttree,
- Plan *righttree)
+make_hashjoin(List * tlist,
+ List * qpqual,
+ List * hashclauses,
+ Plan * lefttree,
+ Plan * righttree)
{
- HashJoin *node = makeNode(HashJoin);
- Plan *plan = &node->join;
-
- plan->cost = 0.0;
- plan->state = (EState *)NULL;
- plan->targetlist = tlist;
- plan->qual = qpqual;
- plan->lefttree = lefttree;
- plan->righttree = righttree;
- node->hashclauses = hashclauses;
- node->hashjointable = NULL;
- node->hashjointablekey = 0;
- node->hashjointablesize = 0;
- node->hashdone = false;
-
- return(node);
+ HashJoin *node = makeNode(HashJoin);
+ Plan *plan = &node->join;
+
+ plan->cost = 0.0;
+ plan->state = (EState *) NULL;
+ plan->targetlist = tlist;
+ plan->qual = qpqual;
+ plan->lefttree = lefttree;
+ plan->righttree = righttree;
+ node->hashclauses = hashclauses;
+ node->hashjointable = NULL;
+ node->hashjointablekey = 0;
+ node->hashjointablesize = 0;
+ node->hashdone = false;
+
+ return (node);
}
-static Hash *
-make_hash(List *tlist, Var *hashkey, Plan *lefttree)
+static Hash *
+make_hash(List * tlist, Var * hashkey, Plan * lefttree)
{
- Hash *node = makeNode(Hash);
- Plan *plan = &node->plan;
-
- plan->cost = 0.0;
- plan->state = (EState *)NULL;
- plan->targetlist = tlist;
- plan->qual = NULL;
- plan->lefttree = lefttree;
- plan->righttree = NULL;
- node->hashkey = hashkey;
- node->hashtable = NULL;
- node->hashtablekey = 0;
- node->hashtablesize = 0;
-
- return(node);
+ Hash *node = makeNode(Hash);
+ Plan *plan = &node->plan;
+
+ plan->cost = 0.0;
+ plan->state = (EState *) NULL;
+ plan->targetlist = tlist;
+ plan->qual = NULL;
+ plan->lefttree = lefttree;
+ plan->righttree = NULL;
+ node->hashkey = hashkey;
+ node->hashtable = NULL;
+ node->hashtablekey = 0;
+ node->hashtablesize = 0;
+
+ return (node);
}
static MergeJoin *
-make_mergesort(List *tlist,
- List *qpqual,
- List *mergeclauses,
- Oid opcode,
- Oid *rightorder,
- Oid *leftorder,
- Plan *righttree,
- Plan *lefttree)
+make_mergesort(List * tlist,
+ List * qpqual,
+ List * mergeclauses,
+ Oid opcode,
+ Oid * rightorder,
+ Oid * leftorder,
+ Plan * righttree,
+ Plan * lefttree)
{
- MergeJoin *node = makeNode(MergeJoin);
- Plan *plan = &node->join;
-
- plan->cost = 0.0;
- plan->state = (EState *)NULL;
- plan->targetlist = tlist;
- plan->qual = qpqual;
- plan->lefttree = lefttree;
- plan->righttree = righttree;
- node->mergeclauses = mergeclauses;
- node->mergesortop = opcode;
- node->mergerightorder = rightorder;
- node->mergeleftorder = leftorder;
-
- return(node);
+ MergeJoin *node = makeNode(MergeJoin);
+ Plan *plan = &node->join;
+
+ plan->cost = 0.0;
+ plan->state = (EState *) NULL;
+ plan->targetlist = tlist;
+ plan->qual = qpqual;
+ plan->lefttree = lefttree;
+ plan->righttree = righttree;
+ node->mergeclauses = mergeclauses;
+ node->mergesortop = opcode;
+ node->mergerightorder = rightorder;
+ node->mergeleftorder = leftorder;
+
+ return (node);
}
-Sort *
-make_sort(List *tlist, Oid tempid, Plan *lefttree, int keycount)
+Sort *
+make_sort(List * tlist, Oid tempid, Plan * lefttree, int keycount)
{
- Sort *node = makeNode(Sort);
- Plan *plan = &node->plan;
-
- plan->cost = 0.0;
- plan->state = (EState *)NULL;
- plan->targetlist = tlist;
- plan->qual = NIL;
- plan->lefttree = lefttree;
- plan->righttree = NULL;
- node->tempid = tempid;
- node->keycount = keycount;
-
- return(node);
+ Sort *node = makeNode(Sort);
+ Plan *plan = &node->plan;
+
+ plan->cost = 0.0;
+ plan->state = (EState *) NULL;
+ plan->targetlist = tlist;
+ plan->qual = NIL;
+ plan->lefttree = lefttree;
+ plan->righttree = NULL;
+ node->tempid = tempid;
+ node->keycount = keycount;
+
+ return (node);
}
static Material *
-make_material(List *tlist,
- Oid tempid,
- Plan *lefttree,
- int keycount)
+make_material(List * tlist,
+ Oid tempid,
+ Plan * lefttree,
+ int keycount)
{
- Material *node = makeNode(Material);
- Plan *plan = &node->plan;
-
- plan->cost = 0.0;
- plan->state = (EState *)NULL;
- plan->targetlist = tlist;
- plan->qual = NIL;
- plan->lefttree = lefttree;
- plan->righttree = NULL;
- node->tempid = tempid;
- node->keycount = keycount;
-
- return(node);
+ Material *node = makeNode(Material);
+ Plan *plan = &node->plan;
+
+ plan->cost = 0.0;
+ plan->state = (EState *) NULL;
+ plan->targetlist = tlist;
+ plan->qual = NIL;
+ plan->lefttree = lefttree;
+ plan->righttree = NULL;
+ node->tempid = tempid;
+ node->keycount = keycount;
+
+ return (node);
}
-Agg *
-make_agg(List *tlist, int nagg, Aggreg **aggs)
+Agg *
+make_agg(List * tlist, int nagg, Aggreg ** aggs)
{
- Agg *node = makeNode(Agg);
-
- node->plan.cost = 0.0;
- node->plan.state = (EState*)NULL;
- node->plan.qual = NULL;
- node->plan.targetlist = tlist;
- node->plan.lefttree = (Plan*)NULL;
- node->plan.righttree = (Plan*)NULL;
- node->numAgg = nagg;
- node->aggs = aggs;
-
- return(node);
+ Agg *node = makeNode(Agg);
+
+ node->plan.cost = 0.0;
+ node->plan.state = (EState *) NULL;
+ node->plan.qual = NULL;
+ node->plan.targetlist = tlist;
+ node->plan.lefttree = (Plan *) NULL;
+ node->plan.righttree = (Plan *) NULL;
+ node->numAgg = nagg;
+ node->aggs = aggs;
+
+ return (node);
}
-Group *
-make_group(List *tlist,
- bool tuplePerGroup,
- int ngrp,
- AttrNumber *grpColIdx,
- Sort *lefttree)
+Group *
+make_group(List * tlist,
+ bool tuplePerGroup,
+ int ngrp,
+ AttrNumber * grpColIdx,
+ Sort * lefttree)
{
- Group *node = makeNode(Group);
-
- node->plan.cost = 0.0;
- node->plan.state = (EState*)NULL;
- node->plan.qual = NULL;
- node->plan.targetlist = tlist;
- node->plan.lefttree = (Plan*)lefttree;
- node->plan.righttree = (Plan*)NULL;
- node->tuplePerGroup = tuplePerGroup;
- node->numCols = ngrp;
- node->grpColIdx = grpColIdx;
-
- return(node);
+ Group *node = makeNode(Group);
+
+ node->plan.cost = 0.0;
+ node->plan.state = (EState *) NULL;
+ node->plan.qual = NULL;
+ node->plan.targetlist = tlist;
+ node->plan.lefttree = (Plan *) lefttree;
+ node->plan.righttree = (Plan *) NULL;
+ node->tuplePerGroup = tuplePerGroup;
+ node->numCols = ngrp;
+ node->grpColIdx = grpColIdx;
+
+ return (node);
}
/*
- * A unique node always has a SORT node in the lefttree.
+ * A unique node always has a SORT node in the lefttree.
*
- * the uniqueAttr argument must be a null-terminated string,
- * either the name of the attribute to select unique on
+ * the uniqueAttr argument must be a null-terminated string,
+ * either the name of the attribute to select unique on
* or "*"
*/
-Unique *
-make_unique(List *tlist, Plan *lefttree, char* uniqueAttr)
+Unique *
+make_unique(List * tlist, Plan * lefttree, char *uniqueAttr)
{
- Unique *node = makeNode(Unique);
- Plan *plan = &node->plan;
-
- plan->cost = 0.0;
- plan->state = (EState *)NULL;
- plan->targetlist = tlist;
- plan->qual = NIL;
- plan->lefttree = lefttree;
- plan->righttree = NULL;
- node->tempid = _TEMP_RELATION_ID_;
- node->keycount = 0;
- if (strcmp(uniqueAttr,"*") == 0)
- node->uniqueAttr = NULL;
- else
- {
- node->uniqueAttr=pstrdup(uniqueAttr);
- }
- return(node);
+ Unique *node = makeNode(Unique);
+ Plan *plan = &node->plan;
+
+ plan->cost = 0.0;
+ plan->state = (EState *) NULL;
+ plan->targetlist = tlist;
+ plan->qual = NIL;
+ plan->lefttree = lefttree;
+ plan->righttree = NULL;
+ node->tempid = _TEMP_RELATION_ID_;
+ node->keycount = 0;
+ if (strcmp(uniqueAttr, "*") == 0)
+ node->uniqueAttr = NULL;
+ else
+ {
+ node->uniqueAttr = pstrdup(uniqueAttr);
+ }
+ return (node);
}
-List *generate_fjoin(List *tlist)
+List *
+generate_fjoin(List * tlist)
{
#if 0
- List tlistP;
- List newTlist = NIL;
- List fjoinList = NIL;
- int nIters = 0;
-
- /*
- * Break the target list into elements with Iter nodes,
- * and those without them.
- */
- foreach(tlistP, tlist) {
- List tlistElem;
-
- tlistElem = lfirst(tlistP);
- if (IsA(lsecond(tlistElem),Iter)) {
- nIters++;
- fjoinList = lappend(fjoinList, tlistElem);
- } else {
- newTlist = lappend(newTlist, tlistElem);
+ List tlistP;
+ List newTlist = NIL;
+ List fjoinList = NIL;
+ int nIters = 0;
+
+ /*
+ * Break the target list into elements with Iter nodes, and those
+ * without them.
+ */
+ foreach(tlistP, tlist)
+ {
+ List tlistElem;
+
+ tlistElem = lfirst(tlistP);
+ if (IsA(lsecond(tlistElem), Iter))
+ {
+ nIters++;
+ fjoinList = lappend(fjoinList, tlistElem);
+ }
+ else
+ {
+ newTlist = lappend(newTlist, tlistElem);
+ }
+ }
+
+ /*
+ * if we have an Iter node then we need to flatten.
+ */
+ if (nIters > 0)
+ {
+ List *inner;
+ List *tempList;
+ Fjoin *fjoinNode;
+ DatumPtr results = (DatumPtr) palloc(nIters * sizeof(Datum));
+ BoolPtr alwaysDone = (BoolPtr) palloc(nIters * sizeof(bool));
+
+ inner = lfirst(fjoinList);
+ fjoinList = lnext(fjoinList);
+ fjoinNode = (Fjoin) MakeFjoin(false,
+ nIters,
+ inner,
+ results,
+ alwaysDone);
+ tempList = lcons(fjoinNode, NIL);
+ tempList = nconc(tempList, fjoinList);
+ newTlist = lappend(newTlist, tempList);
}
- }
-
- /*
- * if we have an Iter node then we need to flatten.
- */
- if (nIters > 0) {
- List *inner;
- List *tempList;
- Fjoin *fjoinNode;
- DatumPtr results = (DatumPtr)palloc(nIters*sizeof(Datum));
- BoolPtr alwaysDone = (BoolPtr)palloc(nIters*sizeof(bool));
-
- inner = lfirst(fjoinList);
- fjoinList = lnext(fjoinList);
- fjoinNode = (Fjoin)MakeFjoin(false,
- nIters,
- inner,
- results,
- alwaysDone);
- tempList = lcons(fjoinNode, NIL);
- tempList = nconc(tempList, fjoinList);
- newTlist = lappend(newTlist, tempList);
- }
- return newTlist;
+ return newTlist;
#endif
- return tlist; /* do nothing for now - ay 10/94 */
+ return tlist; /* do nothing for now - ay 10/94 */
}
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 35b3969b70..62ff23f207 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* initsplan.c--
- * Target list, qualification, joininfo initialization routines
+ * Target list, qualification, joininfo initialization routines
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.5 1997/04/24 16:04:23 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.6 1997/09/07 04:44:00 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -33,370 +33,397 @@
#include "optimizer/clauses.h"
#include "optimizer/cost.h"
-extern int Quiet;
+extern int Quiet;
-static void add_clause_to_rels(Query *root, List *clause);
-static void add_join_clause_info_to_rels(Query *root, CInfo *clauseinfo,
- List *join_relids);
-static void add_vars_to_rels(Query *root, List *vars, List *join_relids);
+static void add_clause_to_rels(Query * root, List * clause);
+static void
+add_join_clause_info_to_rels(Query * root, CInfo * clauseinfo,
+ List * join_relids);
+static void add_vars_to_rels(Query * root, List * vars, List * join_relids);
-static MergeOrder *mergesortop(Expr *clause);
-static Oid hashjoinop(Expr *clause);
+static MergeOrder *mergesortop(Expr * clause);
+static Oid hashjoinop(Expr * clause);
/*****************************************************************************
*
- * TARGET LISTS
+ * TARGET LISTS
*
*****************************************************************************/
-/*
+/*
* initialize_rel_nodes--
- * Creates rel nodes for every relation mentioned in the target list
- * 'tlist' (if a node hasn't already been created) and adds them to
- * *query-relation-list*. Creates targetlist entries for each member of
- * 'tlist' and adds them to the tlist field of the appropriate rel node.
- *
- * Returns nothing.
+ * Creates rel nodes for every relation mentioned in the target list
+ * 'tlist' (if a node hasn't already been created) and adds them to
+ * *query-relation-list*. Creates targetlist entries for each member of
+ * 'tlist' and adds them to the tlist field of the appropriate rel node.
+ *
+ * Returns nothing.
*/
void
-initialize_base_rels_list(Query *root, List *tlist)
+initialize_base_rels_list(Query * root, List * tlist)
{
- List *tlist_vars = NIL;
- List *l = NIL;
- List *tvar = NIL;
-
- foreach (l, tlist) {
- TargetEntry *entry = (TargetEntry *) lfirst(l);
-
- tlist_vars = append(tlist_vars, pull_var_clause(entry->expr));
- }
-
- /* now, the target list only contains Var nodes */
- foreach (tvar, tlist_vars) {
- Var *var;
- Index varno;
- Rel *result;
-
- var = (Var*)lfirst(tvar);
- varno = var->varno;
- result = get_base_rel(root, varno);
-
- add_tl_element(result, var);
- }
+ List *tlist_vars = NIL;
+ List *l = NIL;
+ List *tvar = NIL;
+
+ foreach(l, tlist)
+ {
+ TargetEntry *entry = (TargetEntry *) lfirst(l);
+
+ tlist_vars = append(tlist_vars, pull_var_clause(entry->expr));
+ }
+
+ /* now, the target list only contains Var nodes */
+ foreach(tvar, tlist_vars)
+ {
+ Var *var;
+ Index varno;
+ Rel *result;
+
+ var = (Var *) lfirst(tvar);
+ varno = var->varno;
+ result = get_base_rel(root, varno);
+
+ add_tl_element(result, var);
+ }
}
/*
* add_missing_variables_to_base_rels -
- * If we have range variable(s) in the FROM clause that does not appear
- * in the target list nor qualifications, we add it to the base relation
- * list. For instance, "select f.x from foo f, foo f2" is a join of f and
- * f2. Note that if we have "select foo.x from foo f", it also gets turned
- * into a join.
+ * If we have range variable(s) in the FROM clause that does not appear
+ * in the target list nor qualifications, we add it to the base relation
+ * list. For instance, "select f.x from foo f, foo f2" is a join of f and
+ * f2. Note that if we have "select foo.x from foo f", it also gets turned
+ * into a join.
*/
void
-add_missing_vars_to_base_rels(Query *root, List *tlist)
+add_missing_vars_to_base_rels(Query * root, List * tlist)
{
- List *l;
- int varno;
-
- varno = 1;
- foreach (l, root->rtable) {
- RangeTblEntry *rte = (RangeTblEntry *)lfirst(l);
- List *relids;
- Rel *result;
- Var *var;
-
- relids = lconsi(varno, NIL);
- if (rte->inFromCl &&
- !rel_member(relids, root->base_relation_list_)) {
-
- var = makeVar(varno, -2 , 26, varno, -2);
- /* add it to base_relation_list_ */
- result = get_base_rel(root, varno);
- add_tl_element(result, var);
+ List *l;
+ int varno;
+
+ varno = 1;
+ foreach(l, root->rtable)
+ {
+ RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
+ List *relids;
+ Rel *result;
+ Var *var;
+
+ relids = lconsi(varno, NIL);
+ if (rte->inFromCl &&
+ !rel_member(relids, root->base_relation_list_))
+ {
+
+ var = makeVar(varno, -2, 26, varno, -2);
+ /* add it to base_relation_list_ */
+ result = get_base_rel(root, varno);
+ add_tl_element(result, var);
+ }
+ pfree(relids);
+ varno++;
}
- pfree(relids);
- varno++;
- }
- return;
+ return;
}
/*****************************************************************************
*
- * QUALIFICATIONS
+ * QUALIFICATIONS
*
*****************************************************************************/
-/*
+/*
* initialize-qualification--
- * Initializes ClauseInfo and JoinInfo fields of relation entries for all
- * relations appearing within clauses. Creates new relation entries if
- * necessary, adding them to *query-relation-list*.
- *
- * Returns nothing of interest.
+ * Initializes ClauseInfo and JoinInfo fields of relation entries for all
+ * relations appearing within clauses. Creates new relation entries if
+ * necessary, adding them to *query-relation-list*.
+ *
+ * Returns nothing of interest.
*/
void
-initialize_base_rels_jinfo(Query *root, List *clauses)
+initialize_base_rels_jinfo(Query * root, List * clauses)
{
- List *clause;
+ List *clause;
- foreach (clause, clauses) {
- add_clause_to_rels(root, lfirst(clause));
- }
- return;
+ foreach(clause, clauses)
+ {
+ add_clause_to_rels(root, lfirst(clause));
+ }
+ return;
}
-/*
+/*
* add-clause-to-rels--
- * Add clause information to either the 'ClauseInfo' or 'JoinInfo' field
- * of a relation entry(depending on whether or not the clause is a join)
- * by creating a new ClauseInfo node and setting appropriate fields
- * within the nodes.
- *
- * Returns nothing of interest.
+ * Add clause information to either the 'ClauseInfo' or 'JoinInfo' field
+ * of a relation entry(depending on whether or not the clause is a join)
+ * by creating a new ClauseInfo node and setting appropriate fields
+ * within the nodes.
+ *
+ * Returns nothing of interest.
*/
static void
-add_clause_to_rels(Query *root, List *clause)
+add_clause_to_rels(Query * root, List * clause)
{
- List *relids;
- List *vars;
- CInfo *clauseinfo = makeNode(CInfo);
+ List *relids;
+ List *vars;
+ CInfo *clauseinfo = makeNode(CInfo);
- /*
- * Retrieve all relids and vars contained within the clause.
- */
- clause_relids_vars((Node*)clause, &relids, &vars);
+ /*
+ * Retrieve all relids and vars contained within the clause.
+ */
+ clause_relids_vars((Node *) clause, &relids, &vars);
- clauseinfo->clause = (Expr*)clause;
- clauseinfo->notclause = contains_not((Node*)clause);
- clauseinfo->selectivity = 0;
- clauseinfo->indexids = NIL;
- clauseinfo->mergesortorder = (MergeOrder*)NULL;
- clauseinfo->hashjoinoperator = (Oid)0;
-
+ clauseinfo->clause = (Expr *) clause;
+ clauseinfo->notclause = contains_not((Node *) clause);
+ clauseinfo->selectivity = 0;
+ clauseinfo->indexids = NIL;
+ clauseinfo->mergesortorder = (MergeOrder *) NULL;
+ clauseinfo->hashjoinoperator = (Oid) 0;
- if(length(relids) == 1) {
- Rel *rel = get_base_rel(root, lfirsti(relids));
-
- /*
- * There is only one relation participating in 'clause',
- * so 'clause' must be a restriction clause.
- */
- /* the selectivity of the clause must be computed
- regardless of whether it's a restriction or a join clause */
- if (is_funcclause((Node*)clause))
- {
+ if (length(relids) == 1)
+ {
+ Rel *rel = get_base_rel(root, lfirsti(relids));
+
/*
- * XXX If we have a func clause set selectivity to 1/3,
- * really need a true selectivity function.
+ * There is only one relation participating in 'clause', so
+ * 'clause' must be a restriction clause.
*/
- clauseinfo->selectivity = (Cost)0.3333333;
- }
- else
- {
- clauseinfo->selectivity =
- compute_clause_selec(root, (Node*)clause,
- NIL);
- }
- rel->clauseinfo = lcons(clauseinfo,
- rel->clauseinfo);
- } else {
- /*
- * 'clause' is a join clause, since there is more than one
- * atom in the relid list.
- */
-
- if (is_funcclause((Node*)clause))
- {
+
/*
- * XXX If we have a func clause set selectivity to 1/3,
- * really need a true selectivity function.
+ * the selectivity of the clause must be computed regardless of
+ * whether it's a restriction or a join clause
*/
- clauseinfo->selectivity = (Cost)0.3333333;
- }
+ if (is_funcclause((Node *) clause))
+ {
+
+ /*
+ * XXX If we have a func clause set selectivity to 1/3, really
+ * need a true selectivity function.
+ */
+ clauseinfo->selectivity = (Cost) 0.3333333;
+ }
+ else
+ {
+ clauseinfo->selectivity =
+ compute_clause_selec(root, (Node *) clause,
+ NIL);
+ }
+ rel->clauseinfo = lcons(clauseinfo,
+ rel->clauseinfo);
+ }
else
- {
- clauseinfo->selectivity =
- compute_clause_selec(root, (Node*)clause,
- NIL);
- }
- add_join_clause_info_to_rels(root, clauseinfo, relids);
- add_vars_to_rels(root,vars, relids);
- }
+ {
+
+ /*
+ * 'clause' is a join clause, since there is more than one atom in
+ * the relid list.
+ */
+
+ if (is_funcclause((Node *) clause))
+ {
+
+ /*
+ * XXX If we have a func clause set selectivity to 1/3, really
+ * need a true selectivity function.
+ */
+ clauseinfo->selectivity = (Cost) 0.3333333;
+ }
+ else
+ {
+ clauseinfo->selectivity =
+ compute_clause_selec(root, (Node *) clause,
+ NIL);
+ }
+ add_join_clause_info_to_rels(root, clauseinfo, relids);
+ add_vars_to_rels(root, vars, relids);
+ }
}
-/*
+/*
* add-join-clause-info-to-rels--
- * For every relation participating in a join clause, add 'clauseinfo' to
- * the appropriate joininfo node(creating a new one and adding it to the
- * appropriate rel node if necessary).
- *
+ * For every relation participating in a join clause, add 'clauseinfo' to
+ * the appropriate joininfo node(creating a new one and adding it to the
+ * appropriate rel node if necessary).
+ *
* 'clauseinfo' describes the join clause
* 'join-relids' is the list of relations participating in the join clause
- *
+ *
* Returns nothing.
- *
+ *
*/
static void
-add_join_clause_info_to_rels(Query *root, CInfo *clauseinfo, List *join_relids)
+add_join_clause_info_to_rels(Query * root, CInfo * clauseinfo, List * join_relids)
{
- List *join_relid;
-
- foreach (join_relid, join_relids) {
- JInfo *joininfo;
- List *other_rels = NIL;
- List *rel;
-
- foreach (rel, join_relids)
- {
- if ( lfirsti(rel) != lfirsti(join_relid) )
- other_rels = lappendi (other_rels, lfirsti(rel));
- }
-
- joininfo =
- find_joininfo_node(get_base_rel(root, lfirsti(join_relid)),
- other_rels);
- joininfo->jinfoclauseinfo =
- lcons(copyObject((void*)clauseinfo), joininfo->jinfoclauseinfo);
-
- }
+ List *join_relid;
+
+ foreach(join_relid, join_relids)
+ {
+ JInfo *joininfo;
+ List *other_rels = NIL;
+ List *rel;
+
+ foreach(rel, join_relids)
+ {
+ if (lfirsti(rel) != lfirsti(join_relid))
+ other_rels = lappendi(other_rels, lfirsti(rel));
+ }
+
+ joininfo =
+ find_joininfo_node(get_base_rel(root, lfirsti(join_relid)),
+ other_rels);
+ joininfo->jinfoclauseinfo =
+ lcons(copyObject((void *) clauseinfo), joininfo->jinfoclauseinfo);
+
+ }
}
-/*
+/*
* add-vars-to-rels--
- * For each variable appearing in a clause,
- * (1) If a targetlist entry for the variable is not already present in
- * the appropriate relation's target list, add one.
- * (2) If a targetlist entry is already present, but the var is part of a
- * join clause, add the relids of the join relations to the JoinList
- * entry of the targetlist entry.
- *
- * 'vars' is the list of var nodes
- * 'join-relids' is the list of relids appearing in the join clause
- * (if this is a join clause)
- *
- * Returns nothing.
+ * For each variable appearing in a clause,
+ * (1) If a targetlist entry for the variable is not already present in
+ * the appropriate relation's target list, add one.
+ * (2) If a targetlist entry is already present, but the var is part of a
+ * join clause, add the relids of the join relations to the JoinList
+ * entry of the targetlist entry.
+ *
+ * 'vars' is the list of var nodes
+ * 'join-relids' is the list of relids appearing in the join clause
+ * (if this is a join clause)
+ *
+ * Returns nothing.
*/
static void
-add_vars_to_rels(Query *root, List *vars, List *join_relids)
+add_vars_to_rels(Query * root, List * vars, List * join_relids)
{
- Var *var;
- List *temp = NIL;
- Rel *rel = (Rel*)NULL;
- TargetEntry *tlistentry;
-
- foreach (temp, vars) {
- var = (Var*)lfirst(temp);
- rel = get_base_rel(root, var->varno);
- tlistentry = tlistentry_member(var, rel->targetlist);
- if(tlistentry==NULL)
- /* add a new entry */
- add_tl_element(rel, var);
- }
+ Var *var;
+ List *temp = NIL;
+ Rel *rel = (Rel *) NULL;
+ TargetEntry *tlistentry;
+
+ foreach(temp, vars)
+ {
+ var = (Var *) lfirst(temp);
+ rel = get_base_rel(root, var->varno);
+ tlistentry = tlistentry_member(var, rel->targetlist);
+ if (tlistentry == NULL)
+ /* add a new entry */
+ add_tl_element(rel, var);
+ }
}
/*****************************************************************************
*
- * JOININFO
+ * JOININFO
*
*****************************************************************************/
-/*
+/*
* initialize-join-clause-info--
- * Set the MergeSortable or HashJoinable field for every joininfo node
- * (within a rel node) and the MergeSortOrder or HashJoinOp field for
- * each clauseinfo node(within a joininfo node) for all relations in a
- * query.
- *
- * Returns nothing.
+ * Set the MergeSortable or HashJoinable field for every joininfo node
+ * (within a rel node) and the MergeSortOrder or HashJoinOp field for
+ * each clauseinfo node(within a joininfo node) for all relations in a
+ * query.
+ *
+ * Returns nothing.
*/
void
-initialize_join_clause_info(List *rel_list)
+initialize_join_clause_info(List * rel_list)
{
- List *x, *y, *z;
- Rel *rel;
- JInfo *joininfo;
- CInfo *clauseinfo;
- Expr *clause;
-
- foreach (x, rel_list) {
- rel = (Rel*)lfirst(x);
- foreach (y, rel->joininfo) {
- joininfo = (JInfo*)lfirst(y);
- foreach (z, joininfo->jinfoclauseinfo) {
- clauseinfo = (CInfo*)lfirst(z);
- clause = clauseinfo->clause;
- if(join_clause_p((Node*)clause)) {
- MergeOrder *sortop = (MergeOrder*)NULL;
- Oid hashop = (Oid)NULL;
-
- if (_enable_mergesort_)
- sortop = mergesortop(clause);
- if (_enable_hashjoin_)
- hashop = hashjoinop(clause);
-
- if (sortop) {
- clauseinfo->mergesortorder = sortop;
- joininfo->mergesortable = true;
- }
- if (hashop) {
- clauseinfo->hashjoinoperator = hashop;
- joininfo->hashjoinable = true;
- }
+ List *x,
+ *y,
+ *z;
+ Rel *rel;
+ JInfo *joininfo;
+ CInfo *clauseinfo;
+ Expr *clause;
+
+ foreach(x, rel_list)
+ {
+ rel = (Rel *) lfirst(x);
+ foreach(y, rel->joininfo)
+ {
+ joininfo = (JInfo *) lfirst(y);
+ foreach(z, joininfo->jinfoclauseinfo)
+ {
+ clauseinfo = (CInfo *) lfirst(z);
+ clause = clauseinfo->clause;
+ if (join_clause_p((Node *) clause))
+ {
+ MergeOrder *sortop = (MergeOrder *) NULL;
+ Oid hashop = (Oid) NULL;
+
+ if (_enable_mergesort_)
+ sortop = mergesortop(clause);
+ if (_enable_hashjoin_)
+ hashop = hashjoinop(clause);
+
+ if (sortop)
+ {
+ clauseinfo->mergesortorder = sortop;
+ joininfo->mergesortable = true;
+ }
+ if (hashop)
+ {
+ clauseinfo->hashjoinoperator = hashop;
+ joininfo->hashjoinable = true;
+ }
+ }
+ }
}
- }
}
- }
}
-/*
+/*
* mergesortop--
- * Returns the mergesort operator of an operator iff 'clause' is
- * mergesortable, i.e., both operands are single vars and the operator is
- * a mergesortable operator.
+ * Returns the mergesort operator of an operator iff 'clause' is
+ * mergesortable, i.e., both operands are single vars and the operator is
+ * a mergesortable operator.
*/
static MergeOrder *
-mergesortop(Expr *clause)
+mergesortop(Expr * clause)
{
- Oid leftOp, rightOp;
- bool sortable;
-
- sortable = op_mergesortable(((Oper*)clause->oper)->opno,
- (get_leftop(clause))->vartype,
- (get_rightop(clause))->vartype,
- &leftOp,
- &rightOp);
-
- if (sortable) {
- MergeOrder *morder = makeNode(MergeOrder);
-
- morder->join_operator = ((Oper*)clause->oper)->opno;
- morder->left_operator = leftOp;
- morder->right_operator = rightOp;
- morder->left_type = (get_leftop(clause))->vartype;
- morder->right_type = (get_rightop(clause))->vartype;
- return (morder);
- } else
- return(NULL);
+ Oid leftOp,
+ rightOp;
+ bool sortable;
+
+ sortable = op_mergesortable(((Oper *) clause->oper)->opno,
+ (get_leftop(clause))->vartype,
+ (get_rightop(clause))->vartype,
+ &leftOp,
+ &rightOp);
+
+ if (sortable)
+ {
+ MergeOrder *morder = makeNode(MergeOrder);
+
+ morder->join_operator = ((Oper *) clause->oper)->opno;
+ morder->left_operator = leftOp;
+ morder->right_operator = rightOp;
+ morder->left_type = (get_leftop(clause))->vartype;
+ morder->right_type = (get_rightop(clause))->vartype;
+ return (morder);
+ }
+ else
+ return (NULL);
}
-/*
+/*
* hashjoinop--
- * Returns the hashjoin operator of an operator iff 'clause' is
- * hashjoinable, i.e., both operands are single vars and the operator is
- * a hashjoinable operator.
+ * Returns the hashjoin operator of an operator iff 'clause' is
+ * hashjoinable, i.e., both operands are single vars and the operator is
+ * a hashjoinable operator.
*/
-static Oid
-hashjoinop(Expr *clause)
+static Oid
+hashjoinop(Expr * clause)
{
- return(op_hashjoinable(((Oper*)clause->oper)->opno,
- (get_leftop(clause))->vartype,
- (get_rightop(clause))->vartype));
+ return (op_hashjoinable(((Oper *) clause->oper)->opno,
+ (get_leftop(clause))->vartype,
+ (get_rightop(clause))->vartype));
}
diff --git a/src/backend/optimizer/plan/planmain.c b/src/backend/optimizer/plan/planmain.c
index 7f70d76ac6..630ed12d2a 100644
--- a/src/backend/optimizer/plan/planmain.c
+++ b/src/backend/optimizer/plan/planmain.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* planmain.c--
- * Routines to plan a single query
+ * 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.4 1997/04/29 04:32:50 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.5 1997/09/07 04:44:02 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -38,506 +38,536 @@
#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 *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);
+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.
+ * 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)
+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;
- }
-
- /*
- * 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);
+ 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;
}
- }
-
- /*
- * 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.)
+ * 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).
*/
- tuplePerGroup = ( root->qry_aggs ) ? TRUE : FALSE;
-
- subplan =
- make_groupPlan(&tlist, tuplePerGroup, root->groupClause, subplan);
-
- }
-
- /*
- * If aggregate is present, insert the agg node
- */
- if ( root->qry_aggs )
- {
- aggplan = make_agg(tlist, root->qry_numAgg, root->qry_aggs);
- aggplan->plan.lefttree = subplan;
+ 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);
+ }
+ }
+
/*
- * 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.)
+ * Find the subplan (access path) and destructively modify the target
+ * list of the newly created subplan to contain the appropriate join
+ * references.
*/
- set_agg_tlist_references (aggplan);
- set_agg_agglist_references (aggplan);
-
- subplan = (Plan*)aggplan;
-
- 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);
+ subplan = subplanner(root, level_tlist, qual);
+
+ set_tlist_references(subplan);
+
/*
- * Change all varno's of the Result's node target list.
+ * If we have a GROUP BY clause, insert a group node (with the
+ * appropriate sort node.)
*/
- 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
- *
- * But now nothing to do if there are GroupBy and/or Aggregates:
- * 1. make_groupPlan fixes tlist; 2. flatten_tlist_vars does nothing
- * with aggregates fixing only other entries (i.e. - GroupBy-ed and
- * so fixed by make_groupPlan). - vadim 04/05/97
- */
- if ( root->groupClause == NULL && aggplan == NULL )
- {
- 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);
+ 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 = (root->qry_aggs) ? TRUE : FALSE;
+
+ subplan =
+ make_groupPlan(&tlist, tuplePerGroup, root->groupClause, subplan);
+
+ }
+
+ /*
+ * If aggregate is present, insert the agg node
+ */
+ if (root->qry_aggs)
+ {
+ aggplan = make_agg(tlist, root->qry_numAgg, root->qry_aggs);
+ aggplan->plan.lefttree = subplan;
+
+ /*
+ * 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(aggplan);
+ set_agg_agglist_references(aggplan);
+
+ subplan = (Plan *) aggplan;
+
+ 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
+ *
+ * But now nothing to do if there are GroupBy and/or Aggregates: 1.
+ * make_groupPlan fixes tlist; 2. flatten_tlist_vars does nothing with
+ * aggregates fixing only other entries (i.e. - GroupBy-ed and so
+ * fixed by make_groupPlan). - vadim 04/05/97
+ */
+ if (root->groupClause == NULL && aggplan == NULL)
+ {
+ 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.
- *
+ *
+ * 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)
+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)
+ 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)
+ List *pathnode;
+
+ foreach(pathnode, final_relation->pathlist)
{
- if (xfunc_do_predmig((Path*)lfirst(pathnode)))
- set_cheapest(final_relation, 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));
- }
-
+
+ /*
+ * 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)
+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);
-}
+ 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)
+static Plan *
+make_groupPlan(List ** tlist,
+ bool tuplePerGroup,
+ List * groupClause,
+ Plan * subplan)
{
- List *sort_tlist;
- List *sl, *gl;
- List *glc = listCopy (groupClause);
- List *otles = NIL; /* list of removed non-GroupBy entries */
- List *otlvars = NIL; /* list of var in them */
- int otlvcnt;
- Sort *sortplan;
- Group *grpplan;
- int numCols;
- AttrNumber *grpColIdx;
- int keyno = 1;
- int last_resno = 1;
-
- numCols = length(groupClause);
- grpColIdx = (AttrNumber *)palloc(sizeof(AttrNumber)*numCols);
-
- sort_tlist = new_unsorted_tlist(*tlist); /* it's copy */
-
- /*
- * Make template TL for subplan, Sort & Group:
- * 1. If there are aggregates (tuplePerGroup is true) then take
- * away non-GroupBy entries and re-set resno-s accordantly.
- * 2. Make grpColIdx
- *
- * Note: we assume that TLEs in *tlist are ordered in accordance
- * with their resdom->resno.
- */
- foreach (sl, sort_tlist)
- {
- Resdom *resdom = NULL;
- TargetEntry *te = (TargetEntry *) lfirst (sl);
-
- foreach (gl, glc)
- {
- GroupClause *grpcl = (GroupClause*)lfirst(gl);
-
- if ( grpcl->entry->resdom->resno == te->resdom->resno )
- {
-
- resdom = te->resdom;
- resdom->reskey = keyno;
- resdom->reskeyop = get_opcode (grpcl->grpOpoid);
- resdom->resno = last_resno; /* re-set */
- grpColIdx[keyno-1] = last_resno++;
- keyno++;
- glc = lremove (lfirst (gl), glc); /* TLE found for it */
- break;
- }
- }
- /*
- * Non-GroupBy entry: remove it from Group/Sort TL if there are
- * aggregates in query - it will be evaluated by Aggregate plan
+ List *sort_tlist;
+ List *sl,
+ *gl;
+ List *glc = listCopy(groupClause);
+ List *otles = NIL;/* list of removed non-GroupBy entries */
+ List *otlvars = NIL; /* list of var in them */
+ int otlvcnt;
+ Sort *sortplan;
+ Group *grpplan;
+ int numCols;
+ AttrNumber *grpColIdx;
+ int keyno = 1;
+ int last_resno = 1;
+
+ numCols = length(groupClause);
+ grpColIdx = (AttrNumber *) palloc(sizeof(AttrNumber) * numCols);
+
+ sort_tlist = new_unsorted_tlist(*tlist); /* it's copy */
+
+ /*
+ * Make template TL for subplan, Sort & Group: 1. If there are
+ * aggregates (tuplePerGroup is true) then take away non-GroupBy
+ * entries and re-set resno-s accordantly. 2. Make grpColIdx
+ *
+ * Note: we assume that TLEs in *tlist are ordered in accordance with
+ * their resdom->resno.
*/
- if ( resdom == NULL )
+ foreach(sl, sort_tlist)
{
- if ( tuplePerGroup )
- {
- otlvars = nconc (otlvars, pull_var_clause (te->expr));
- otles = lcons (te, otles);
- sort_tlist = lremove (te, sort_tlist);
- }
- else
- te->resdom->resno = last_resno++;
+ Resdom *resdom = NULL;
+ TargetEntry *te = (TargetEntry *) lfirst(sl);
+
+ foreach(gl, glc)
+ {
+ GroupClause *grpcl = (GroupClause *) lfirst(gl);
+
+ if (grpcl->entry->resdom->resno == te->resdom->resno)
+ {
+
+ resdom = te->resdom;
+ resdom->reskey = keyno;
+ resdom->reskeyop = get_opcode(grpcl->grpOpoid);
+ resdom->resno = last_resno; /* re-set */
+ grpColIdx[keyno - 1] = last_resno++;
+ keyno++;
+ glc = lremove(lfirst(gl), glc); /* TLE found for it */
+ break;
+ }
+ }
+
+ /*
+ * Non-GroupBy entry: remove it from Group/Sort TL if there are
+ * aggregates in query - it will be evaluated by Aggregate plan
+ */
+ if (resdom == NULL)
+ {
+ if (tuplePerGroup)
+ {
+ otlvars = nconc(otlvars, pull_var_clause(te->expr));
+ otles = lcons(te, otles);
+ sort_tlist = lremove(te, sort_tlist);
+ }
+ else
+ te->resdom->resno = last_resno++;
+ }
}
- }
-
- if ( length (glc) != 0 )
- {
- elog(WARN, "group attribute disappeared from target list");
- }
-
- /*
- * If non-GroupBy entries were removed from TL - we are to add Vars for
- * them to the end of TL if there are no such Vars in TL already.
- */
-
- otlvcnt = length (otlvars);
- foreach (gl, otlvars)
- {
- Var *v = (Var*)lfirst (gl);
-
- if ( tlist_member (v, sort_tlist) == NULL )
+
+ if (length(glc) != 0)
{
- sort_tlist = lappend (sort_tlist,
- create_tl_element (v, last_resno));
- last_resno++;
+ elog(WARN, "group attribute disappeared from target list");
}
- else /* already in TL */
- otlvcnt--;
- }
- /* Now otlvcnt is number of Vars added in TL for non-GroupBy entries */
-
- /* Make TL for subplan: substitute Vars from subplan TL into new TL */
- sl = flatten_tlist_vars (sort_tlist, subplan->targetlist);
-
- subplan->targetlist = new_unsorted_tlist (sl); /* there */
-
- /*
- * Make Sort/Group TL :
- * 1. make Var nodes (with varno = 1 and varnoold = -1) for all
- * functions, 'couse they will be evaluated by subplan;
- * 2. for real Vars: set varno = 1 and varattno to its resno in subplan
- */
- foreach (sl, sort_tlist)
- {
- TargetEntry *te = (TargetEntry *) lfirst (sl);
- Resdom *resdom = te->resdom;
- Node *expr = te->expr;
-
- if ( IsA (expr, Var) )
- {
-#if 0 /* subplanVar->resdom->resno expected to be = te->resdom->resno */
- TargetEntry *subplanVar;
-
- subplanVar = match_varid ((Var*)expr, subplan->targetlist);
- ((Var*)expr)->varattno = subplanVar->resdom->resno;
+
+ /*
+ * If non-GroupBy entries were removed from TL - we are to add Vars
+ * for them to the end of TL if there are no such Vars in TL already.
+ */
+
+ otlvcnt = length(otlvars);
+ foreach(gl, otlvars)
+ {
+ Var *v = (Var *) lfirst(gl);
+
+ if (tlist_member(v, sort_tlist) == NULL)
+ {
+ sort_tlist = lappend(sort_tlist,
+ create_tl_element(v, last_resno));
+ last_resno++;
+ }
+ else
+/* already in TL */
+ otlvcnt--;
+ }
+ /* Now otlvcnt is number of Vars added in TL for non-GroupBy entries */
+
+ /* Make TL for subplan: substitute Vars from subplan TL into new TL */
+ sl = flatten_tlist_vars(sort_tlist, subplan->targetlist);
+
+ subplan->targetlist = new_unsorted_tlist(sl); /* there */
+
+ /*
+ * Make Sort/Group TL : 1. make Var nodes (with varno = 1 and varnoold
+ * = -1) for all functions, 'couse they will be evaluated by subplan;
+ * 2. for real Vars: set varno = 1 and varattno to its resno in
+ * subplan
+ */
+ foreach(sl, sort_tlist)
+ {
+ TargetEntry *te = (TargetEntry *) lfirst(sl);
+ Resdom *resdom = te->resdom;
+ Node *expr = te->expr;
+
+ if (IsA(expr, Var))
+ {
+#if 0 /* subplanVar->resdom->resno expected to
+ * be = te->resdom->resno */
+ TargetEntry *subplanVar;
+
+ subplanVar = match_varid((Var *) expr, subplan->targetlist);
+ ((Var *) expr)->varattno = subplanVar->resdom->resno;
#endif
- ((Var*)expr)->varattno = te->resdom->resno;
- ((Var*)expr)->varno = 1;
- }
- else
- te->expr = (Node*) makeVar (1, resdom->resno,
- resdom->restype,
- -1, resdom->resno);
- }
-
- sortplan = make_sort(sort_tlist,
- _TEMP_RELATION_ID_,
- subplan,
- numCols);
- sortplan->plan.cost = subplan->cost; /* XXX assume no cost */
-
- /*
- * make the Group node
- */
- sort_tlist = copyObject (sort_tlist);
- grpplan = make_group(sort_tlist, tuplePerGroup, numCols,
- grpColIdx, sortplan);
-
- /*
- * Make TL for parent: "restore" non-GroupBy entries (if they
- * were removed) and set resno-s of others accordantly.
- */
- sl = sort_tlist;
- sort_tlist = NIL; /* to be new parent TL */
- foreach (gl, *tlist)
- {
- List *temp = NIL;
- TargetEntry *te = (TargetEntry *) lfirst (gl);
-
- foreach (temp, otles) /* Is it removed non-GroupBy entry ? */
- {
- TargetEntry *ote = (TargetEntry *) lfirst (temp);
-
- if ( ote->resdom->resno == te->resdom->resno )
- {
- otles = lremove (ote, otles);
- break;
- }
- }
- if ( temp == NIL ) /* It's "our" TLE - we're to return */
- { /* it from Sort/Group plans */
- TargetEntry *my = (TargetEntry *) lfirst (sl); /* get it */
-
- sl = sl->next; /* prepare for the next "our" */
- my = copyObject (my);
- my->resdom->resno = te->resdom->resno; /* order of parent TL */
- sort_tlist = lappend (sort_tlist, my);
- continue;
+ ((Var *) expr)->varattno = te->resdom->resno;
+ ((Var *) expr)->varno = 1;
+ }
+ else
+ te->expr = (Node *) makeVar(1, resdom->resno,
+ resdom->restype,
+ -1, resdom->resno);
}
- /* else - it's TLE of an non-GroupBy entry */
- sort_tlist = lappend (sort_tlist, copyObject(te));
- }
- /*
- * Pure non-GroupBy entries Vars were at the end of Group' TL.
- * They shouldn't appear in parent TL, all others shouldn't
- * disappear.
- */
- Assert ( otlvcnt == length (sl) );
- Assert ( length (otles) == 0 );
-
- *tlist = sort_tlist;
-
- return (Plan*)grpplan;
+
+ sortplan = make_sort(sort_tlist,
+ _TEMP_RELATION_ID_,
+ subplan,
+ numCols);
+ sortplan->plan.cost = subplan->cost; /* XXX assume no cost */
+
+ /*
+ * make the Group node
+ */
+ sort_tlist = copyObject(sort_tlist);
+ grpplan = make_group(sort_tlist, tuplePerGroup, numCols,
+ grpColIdx, sortplan);
+
+ /*
+ * Make TL for parent: "restore" non-GroupBy entries (if they were
+ * removed) and set resno-s of others accordantly.
+ */
+ sl = sort_tlist;
+ sort_tlist = NIL; /* to be new parent TL */
+ foreach(gl, *tlist)
+ {
+ List *temp = NIL;
+ TargetEntry *te = (TargetEntry *) lfirst(gl);
+
+ foreach(temp, otles) /* Is it removed non-GroupBy entry ? */
+ {
+ TargetEntry *ote = (TargetEntry *) lfirst(temp);
+
+ if (ote->resdom->resno == te->resdom->resno)
+ {
+ otles = lremove(ote, otles);
+ break;
+ }
+ }
+ if (temp == NIL) /* It's "our" TLE - we're to return */
+ { /* it from Sort/Group plans */
+ TargetEntry *my = (TargetEntry *) lfirst(sl); /* get it */
+
+ sl = sl->next; /* prepare for the next "our" */
+ my = copyObject(my);
+ my->resdom->resno = te->resdom->resno; /* order of parent TL */
+ sort_tlist = lappend(sort_tlist, my);
+ continue;
+ }
+ /* else - it's TLE of an non-GroupBy entry */
+ sort_tlist = lappend(sort_tlist, copyObject(te));
+ }
+
+ /*
+ * Pure non-GroupBy entries Vars were at the end of Group' TL. They
+ * shouldn't appear in parent TL, all others shouldn't disappear.
+ */
+ Assert(otlvcnt == length(sl));
+ Assert(length(otles) == 0);
+
+ *tlist = sort_tlist;
+
+ return (Plan *) grpplan;
}
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 5a6b78384b..43441a3b7f 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* planner.c--
- * The query optimizer external interface.
+ * The query optimizer external interface.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.6 1997/09/05 20:20:48 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.7 1997/09/07 04:44:03 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -28,7 +28,7 @@
#include "optimizer/internal.h"
#include "optimizer/planner.h"
-#include "optimizer/plancat.h"
+#include "optimizer/plancat.h"
#include "optimizer/prep.h"
#include "optimizer/planmain.h"
#include "optimizer/paths.h"
@@ -47,215 +47,225 @@
#include "executor/executor.h"
-static Plan *make_sortplan(List *tlist, List *sortcls, Plan *plannode);
-static Plan *init_query_planner(Query *parse);
-static Existential *make_existential(Plan *left, Plan *right);
+static Plan *make_sortplan(List * tlist, List * sortcls, Plan * plannode);
+static Plan *init_query_planner(Query * parse);
+static Existential *make_existential(Plan * left, Plan * right);
/*****************************************************************************
*
- * Query optimizer entry point
- *
+ * Query optimizer entry point
+ *
*****************************************************************************/
-/*
+/*
* planner--
- * Main query optimizer routine.
- *
- * Invokes the planner on union queries if there are any left,
- * recursing if necessary to get them all, then processes normal plans.
- *
+ * Main query optimizer routine.
+ *
+ * Invokes the planner on union queries if there are any left,
+ * recursing if necessary to get them all, then processes normal plans.
+ *
* Returns a query plan.
- *
+ *
*/
-Plan*
-planner(Query *parse)
+Plan *
+planner(Query * parse)
{
- List *tlist = parse->targetList;
- List *rangetable = parse->rtable;
- char* uniqueflag = parse->uniqueFlag;
- List *sortclause = parse->sortClause;
- Plan *special_plans = (Plan*)NULL;
-
- Plan *result_plan = (Plan*) NULL;
-
- int rt_index;
-
- /*
- * plan inheritance
- */
- rt_index = first_matching_rt_entry(rangetable, INHERITS_FLAG);
- if (rt_index != -1) {
- special_plans = (Plan *)plan_union_queries((Index)rt_index,
- parse,
- INHERITS_FLAG);
- }
-
- /*
- * plan archive queries
- */
- rt_index = first_matching_rt_entry(rangetable, ARCHIVE_FLAG);
- if (rt_index != -1) {
- special_plans = (Plan *)plan_union_queries((Index)rt_index,
- parse,
- ARCHIVE_FLAG);
- }
-
- if (special_plans)
- result_plan = special_plans;
- else
- result_plan = init_query_planner(parse); /* regular plans */
-
- /*
- * For now, before we hand back the plan, check to see if there
- * is a user-specified sort that needs to be done. Eventually, this
- * will be moved into the guts of the planner s.t. user specified
- * sorts will be considered as part of the planning process.
- * Since we can only make use of user-specified sorts in
- * special cases, we can do the optimization step later.
- */
-
- if (uniqueflag) {
- Plan *sortplan = make_sortplan(tlist, sortclause, result_plan);
-
- return((Plan*)make_unique(tlist,sortplan,uniqueflag));
- } else {
- if (sortclause)
- return(make_sortplan(tlist,sortclause,result_plan));
- else
- return((Plan*)result_plan);
- }
+ List *tlist = parse->targetList;
+ List *rangetable = parse->rtable;
+ char *uniqueflag = parse->uniqueFlag;
+ List *sortclause = parse->sortClause;
+ Plan *special_plans = (Plan *) NULL;
+
+ Plan *result_plan = (Plan *) NULL;
+
+ int rt_index;
+
+ /*
+ * plan inheritance
+ */
+ rt_index = first_matching_rt_entry(rangetable, INHERITS_FLAG);
+ if (rt_index != -1)
+ {
+ special_plans = (Plan *) plan_union_queries((Index) rt_index,
+ parse,
+ INHERITS_FLAG);
+ }
+
+ /*
+ * plan archive queries
+ */
+ rt_index = first_matching_rt_entry(rangetable, ARCHIVE_FLAG);
+ if (rt_index != -1)
+ {
+ special_plans = (Plan *) plan_union_queries((Index) rt_index,
+ parse,
+ ARCHIVE_FLAG);
+ }
+
+ if (special_plans)
+ result_plan = special_plans;
+ else
+ result_plan = init_query_planner(parse); /* regular plans */
+
+ /*
+ * For now, before we hand back the plan, check to see if there is a
+ * user-specified sort that needs to be done. Eventually, this will
+ * be moved into the guts of the planner s.t. user specified sorts
+ * will be considered as part of the planning process. Since we can
+ * only make use of user-specified sorts in special cases, we can do
+ * the optimization step later.
+ */
+
+ if (uniqueflag)
+ {
+ Plan *sortplan = make_sortplan(tlist, sortclause, result_plan);
+
+ return ((Plan *) make_unique(tlist, sortplan, uniqueflag));
+ }
+ else
+ {
+ if (sortclause)
+ return (make_sortplan(tlist, sortclause, result_plan));
+ else
+ return ((Plan *) result_plan);
+ }
}
/*
* make_sortplan--
- * Returns a sortplan which is basically a SORT node attached to the
- * top of the plan returned from the planner. It also adds the
- * cost of sorting into the plan.
- *
+ * Returns a sortplan which is basically a SORT node attached to the
+ * top of the plan returned from the planner. It also adds the
+ * cost of sorting into the plan.
+ *
* sortkeys: ( resdom1 resdom2 resdom3 ...)
* sortops: (sortop1 sortop2 sortop3 ...)
*/
-static Plan *
-make_sortplan(List *tlist, List *sortcls, Plan *plannode)
+static Plan *
+make_sortplan(List * tlist, List * sortcls, Plan * plannode)
{
- Plan *sortplan = (Plan*)NULL;
- List *temp_tlist = NIL;
- List *i = NIL;
- Resdom *resnode = (Resdom*)NULL;
- Resdom *resdom = (Resdom*)NULL;
- int keyno =1;
-
- /* First make a copy of the tlist so that we don't corrupt the
- * the original .
- */
-
- temp_tlist = new_unsorted_tlist(tlist);
-
- foreach (i, sortcls) {
- SortClause *sortcl = (SortClause*)lfirst(i);
-
- resnode = sortcl->resdom;
- resdom = tlist_resdom(temp_tlist, resnode);
-
- /* Order the resdom keys and replace the operator OID for each
- * key with the regproc OID.
+ Plan *sortplan = (Plan *) NULL;
+ List *temp_tlist = NIL;
+ List *i = NIL;
+ Resdom *resnode = (Resdom *) NULL;
+ Resdom *resdom = (Resdom *) NULL;
+ int keyno = 1;
+
+ /*
+ * First make a copy of the tlist so that we don't corrupt the the
+ * original .
+ */
+
+ temp_tlist = new_unsorted_tlist(tlist);
+
+ foreach(i, sortcls)
+ {
+ SortClause *sortcl = (SortClause *) lfirst(i);
+
+ resnode = sortcl->resdom;
+ resdom = tlist_resdom(temp_tlist, resnode);
+
+ /*
+ * Order the resdom keys and replace the operator OID for each key
+ * with the regproc OID.
+ */
+ resdom->reskey = keyno;
+ resdom->reskeyop = get_opcode(sortcl->opoid);
+ keyno += 1;
+ }
+
+ sortplan = (Plan *) make_sort(temp_tlist,
+ _TEMP_RELATION_ID_,
+ (Plan *) plannode,
+ length(sortcls));
+
+ /*
+ * XXX Assuming that an internal sort has no. cost. This is wrong, but
+ * given that at this point, we don't know the no. of tuples returned,
+ * etc, we can't do better than to add a constant cost. This will be
+ * fixed once we move the sort further into the planner, but for now
+ * ... functionality....
*/
- resdom->reskey = keyno;
- resdom->reskeyop = get_opcode(sortcl->opoid);
- keyno += 1;
- }
-
- sortplan = (Plan*)make_sort(temp_tlist,
- _TEMP_RELATION_ID_,
- (Plan*)plannode,
- length(sortcls));
-
- /*
- * XXX Assuming that an internal sort has no. cost.
- * This is wrong, but given that at this point, we don't
- * know the no. of tuples returned, etc, we can't do
- * better than to add a constant cost.
- * This will be fixed once we move the sort further into the planner,
- * but for now ... functionality....
- */
-
- sortplan->cost = plannode->cost;
-
- return(sortplan);
+
+ sortplan->cost = plannode->cost;
+
+ return (sortplan);
}
-/*
+/*
* init-query-planner--
- * Deals with all non-union preprocessing, including existential
- * qualifications and CNFifying the qualifications.
- *
+ * Deals with all non-union preprocessing, including existential
+ * qualifications and CNFifying the qualifications.
+ *
* Returns a query plan.
* MODIFIES: tlist,qual
- *
+ *
*/
-static Plan *
-init_query_planner(Query *root)
+static Plan *
+init_query_planner(Query * root)
{
- List *primary_qual;
- List *existential_qual;
- Existential *exist_plan;
- List *tlist = root->targetList;
-
- tlist = preprocess_targetlist(tlist,
- root->commandType,
- root->resultRelation,
- root->rtable);
-
- primary_qual =
- preprocess_qualification((Expr*)root->qual,
- tlist,
- &existential_qual);
-
- if(existential_qual==NULL) {
- return(query_planner(root,
- root->commandType,
- tlist,
- primary_qual));
- } else {
- int temp = root->commandType;
- Plan *existential_plan;
-
- root->commandType = CMD_SELECT;
- existential_plan = query_planner(root,
- temp,
- NIL,
- existential_qual);
-
- exist_plan = make_existential(existential_plan,
- query_planner(root,
- root->commandType,
- tlist,
- primary_qual));
- return((Plan*)exist_plan);
- }
+ List *primary_qual;
+ List *existential_qual;
+ Existential *exist_plan;
+ List *tlist = root->targetList;
+
+ tlist = preprocess_targetlist(tlist,
+ root->commandType,
+ root->resultRelation,
+ root->rtable);
+
+ primary_qual =
+ preprocess_qualification((Expr *) root->qual,
+ tlist,
+ &existential_qual);
+
+ if (existential_qual == NULL)
+ {
+ return (query_planner(root,
+ root->commandType,
+ tlist,
+ primary_qual));
+ }
+ else
+ {
+ int temp = root->commandType;
+ Plan *existential_plan;
+
+ root->commandType = CMD_SELECT;
+ existential_plan = query_planner(root,
+ temp,
+ NIL,
+ existential_qual);
+
+ exist_plan = make_existential(existential_plan,
+ query_planner(root,
+ root->commandType,
+ tlist,
+ primary_qual));
+ return ((Plan *) exist_plan);
+ }
}
-/*
+/*
* make_existential--
- * Instantiates an existential plan node and fills in
- * the left and right subtree slots.
+ * Instantiates an existential plan node and fills in
+ * the left and right subtree slots.
*/
static Existential *
-make_existential(Plan *left, Plan *right)
+make_existential(Plan * left, Plan * right)
{
- Existential *node = makeNode(Existential);
+ Existential *node = makeNode(Existential);
- node->lefttree = left;
- node->righttree = left;
- return(node);
+ node->lefttree = left;
+ node->righttree = left;
+ return (node);
}
/*
* pg_checkretval() -- check return value of a list of sql parse
- * trees.
+ * trees.
*
* The return value of a sql function is the value returned by
* the final query in the function. We do some ad-hoc define-time
@@ -263,145 +273,152 @@ make_existential(Plan *left, Plan *right)
* type he claims.
*/
void
-pg_checkretval(Oid rettype, QueryTreeList *queryTreeList)
+pg_checkretval(Oid rettype, QueryTreeList * queryTreeList)
{
- Query *parse;
- List *tlist;
- List *rt;
- int cmd;
- Type typ;
- Resdom *resnode;
- Relation reln;
- Oid relid;
- Oid tletype;
- int relnatts;
- int i;
-
- /* find the final query */
- parse = queryTreeList->qtrees[queryTreeList->len - 1];
-
- /*
- * test 1: if the last query is a utility invocation, then there
- * had better not be a return value declared.
- */
- if (parse->commandType == CMD_UTILITY) {
+ Query *parse;
+ List *tlist;
+ List *rt;
+ int cmd;
+ Type typ;
+ Resdom *resnode;
+ Relation reln;
+ Oid relid;
+ Oid tletype;
+ int relnatts;
+ int i;
+
+ /* find the final query */
+ parse = queryTreeList->qtrees[queryTreeList->len - 1];
+
+ /*
+ * test 1: if the last query is a utility invocation, then there had
+ * better not be a return value declared.
+ */
+ if (parse->commandType == CMD_UTILITY)
+ {
+ if (rettype == InvalidOid)
+ return;
+ else
+ elog(WARN, "return type mismatch in function decl: final query is a catalog utility");
+ }
+
+ /* okay, it's an ordinary query */
+ tlist = parse->targetList;
+ rt = parse->rtable;
+ cmd = parse->commandType;
+
+ /*
+ * test 2: if the function is declared to return no value, then the
+ * final query had better not be a retrieve.
+ */
if (rettype == InvalidOid)
- return;
- else
- elog(WARN, "return type mismatch in function decl: final query is a catalog utility");
- }
-
- /* okay, it's an ordinary query */
- tlist = parse->targetList;
- rt = parse->rtable;
- cmd = parse->commandType;
-
- /*
- * test 2: if the function is declared to return no value, then the
- * final query had better not be a retrieve.
- */
- if (rettype == InvalidOid) {
- if (cmd == CMD_SELECT)
- elog(WARN,
- "function declared with no return type, but final query is a retrieve");
- else
- return;
- }
-
- /* by here, the function is declared to return some type */
- if ((typ = (Type)get_id_type(rettype)) == NULL)
- elog(WARN, "can't find return type %d for function\n", rettype);
-
- /*
- * test 3: if the function is declared to return a value, then the
- * final query had better be a retrieve.
- */
- if (cmd != CMD_SELECT)
- elog(WARN, "function declared to return type %s, but final query is not a retrieve", tname(typ));
-
- /*
- * test 4: for base type returns, the target list should have exactly
- * one entry, and its type should agree with what the user declared.
- */
-
- if (get_typrelid(typ) == InvalidOid) {
- if (exec_tlist_length(tlist) > 1)
- elog(WARN, "function declared to return %s returns multiple values in final retrieve", tname(typ));
-
- resnode = (Resdom*) ((TargetEntry*)lfirst(tlist))->resdom;
- if (resnode->restype != rettype)
- elog(WARN, "return type mismatch in function: declared to return %s, returns %s", tname(typ), tname(get_id_type(resnode->restype)));
-
- /* by here, base return types match */
- return;
- }
-
- /*
- * If the target list is of length 1, and the type of the varnode
- * in the target list is the same as the declared return type, this
- * is okay. This can happen, for example, where the body of the
- * function is 'retrieve (x = func2())', where func2 has the same
- * return type as the function that's calling it.
- */
- if (exec_tlist_length(tlist) == 1) {
- resnode = (Resdom*) ((TargetEntry*)lfirst(tlist))->resdom;
- if (resnode->restype == rettype)
- return;
- }
-
- /*
- * By here, the procedure returns a (set of) tuples. This part of
- * the typechecking is a hack. We look up the relation that is
- * the declared return type, and be sure that attributes 1 .. n
- * in the target list match the declared types.
- */
- reln = heap_open(get_typrelid(typ));
-
- if (!RelationIsValid(reln))
- elog(WARN, "cannot open relation relid %d", get_typrelid(typ));
-
- relid = reln->rd_id;
- relnatts = reln->rd_rel->relnatts;
-
- if (exec_tlist_length(tlist) != relnatts)
- elog(WARN, "function declared to return type %s does not retrieve (%s.*)", tname(typ), tname(typ));
-
- /* expect attributes 1 .. n in order */
- for (i = 1; i <= relnatts; i++) {
- TargetEntry *tle = lfirst(tlist);
- Node *thenode = tle->expr;
-
- tlist = lnext(tlist);
- tletype = exprType(thenode);
-
-#if 0 /* fix me */
- /* this is tedious */
- if (IsA(thenode,Var))
- tletype = (Oid) ((Var*)thenode)->vartype;
- else if (IsA(thenode,Const))
- tletype = (Oid) ((Const*)thenode)->consttype;
- else if (IsA(thenode,Param))
- tletype = (Oid) ((Param*)thenode)->paramtype;
- else if (IsA(thenode,Expr))
- tletype = Expr;
- else if (IsA(thenode,LispList)) {
- thenode = lfirst(thenode);
- if (IsA(thenode,Oper))
- tletype = (Oid) get_opresulttype((Oper*)thenode);
- else if (IsA(thenode,Func))
- tletype = (Oid) get_functype((Func*)thenode);
- else
- elog(WARN, "function declared to return type %s does not retrieve (%s.all)", tname(typ), tname(typ));
- } else
- elog(WARN, "function declared to return type %s does not retrieve (%s.all)", tname(typ), tname(typ));
+ {
+ if (cmd == CMD_SELECT)
+ elog(WARN,
+ "function declared with no return type, but final query is a retrieve");
+ else
+ return;
+ }
+
+ /* by here, the function is declared to return some type */
+ if ((typ = (Type) get_id_type(rettype)) == NULL)
+ elog(WARN, "can't find return type %d for function\n", rettype);
+
+ /*
+ * test 3: if the function is declared to return a value, then the
+ * final query had better be a retrieve.
+ */
+ if (cmd != CMD_SELECT)
+ elog(WARN, "function declared to return type %s, but final query is not a retrieve", tname(typ));
+
+ /*
+ * test 4: for base type returns, the target list should have exactly
+ * one entry, and its type should agree with what the user declared.
+ */
+
+ if (get_typrelid(typ) == InvalidOid)
+ {
+ if (exec_tlist_length(tlist) > 1)
+ elog(WARN, "function declared to return %s returns multiple values in final retrieve", tname(typ));
+
+ resnode = (Resdom *) ((TargetEntry *) lfirst(tlist))->resdom;
+ if (resnode->restype != rettype)
+ elog(WARN, "return type mismatch in function: declared to return %s, returns %s", tname(typ), tname(get_id_type(resnode->restype)));
+
+ /* by here, base return types match */
+ return;
+ }
+
+ /*
+ * If the target list is of length 1, and the type of the varnode in
+ * the target list is the same as the declared return type, this is
+ * okay. This can happen, for example, where the body of the function
+ * is 'retrieve (x = func2())', where func2 has the same return type
+ * as the function that's calling it.
+ */
+ if (exec_tlist_length(tlist) == 1)
+ {
+ resnode = (Resdom *) ((TargetEntry *) lfirst(tlist))->resdom;
+ if (resnode->restype == rettype)
+ return;
+ }
+
+ /*
+ * By here, the procedure returns a (set of) tuples. This part of the
+ * typechecking is a hack. We look up the relation that is the
+ * declared return type, and be sure that attributes 1 .. n in the
+ * target list match the declared types.
+ */
+ reln = heap_open(get_typrelid(typ));
+
+ if (!RelationIsValid(reln))
+ elog(WARN, "cannot open relation relid %d", get_typrelid(typ));
+
+ relid = reln->rd_id;
+ relnatts = reln->rd_rel->relnatts;
+
+ if (exec_tlist_length(tlist) != relnatts)
+ elog(WARN, "function declared to return type %s does not retrieve (%s.*)", tname(typ), tname(typ));
+
+ /* expect attributes 1 .. n in order */
+ for (i = 1; i <= relnatts; i++)
+ {
+ TargetEntry *tle = lfirst(tlist);
+ Node *thenode = tle->expr;
+
+ tlist = lnext(tlist);
+ tletype = exprType(thenode);
+
+#if 0 /* fix me */
+ /* this is tedious */
+ if (IsA(thenode, Var))
+ tletype = (Oid) ((Var *) thenode)->vartype;
+ else if (IsA(thenode, Const))
+ tletype = (Oid) ((Const *) thenode)->consttype;
+ else if (IsA(thenode, Param))
+ tletype = (Oid) ((Param *) thenode)->paramtype;
+ else if (IsA(thenode, Expr))
+ tletype = Expr;
+ else if (IsA(thenode, LispList))
+ {
+ thenode = lfirst(thenode);
+ if (IsA(thenode, Oper))
+ tletype = (Oid) get_opresulttype((Oper *) thenode);
+ else if (IsA(thenode, Func))
+ tletype = (Oid) get_functype((Func *) thenode);
+ else
+ elog(WARN, "function declared to return type %s does not retrieve (%s.all)", tname(typ), tname(typ));
+ }
+ else
+ elog(WARN, "function declared to return type %s does not retrieve (%s.all)", tname(typ), tname(typ));
#endif
- /* reach right in there, why don't you? */
- if (tletype != reln->rd_att->attrs[i-1]->atttypid)
- elog(WARN, "function declared to return type %s does not retrieve (%s.all)", tname(typ), tname(typ));
- }
+ /* reach right in there, why don't you? */
+ if (tletype != reln->rd_att->attrs[i - 1]->atttypid)
+ elog(WARN, "function declared to return type %s does not retrieve (%s.all)", tname(typ), tname(typ));
+ }
- heap_close(reln);
+ heap_close(reln);
- /* success */
- return;
+ /* success */
+ return;
}
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index 4527837e9d..19cee246a5 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* setrefs.c--
- * Routines to change varno/attno entries to contain references
+ * Routines to change varno/attno entries to contain references
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.4 1997/06/12 17:26:15 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.5 1997/09/07 04:44:05 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -33,419 +33,468 @@
#include "optimizer/var.h"
#include "optimizer/tlist.h"
-static void set_join_tlist_references(Join *join);
-static void set_tempscan_tlist_references(SeqScan *tempscan);
-static void set_temp_tlist_references(Temp *temp);
-static List *replace_clause_joinvar_refs(Expr *clause,
- List *outer_tlist, List *inner_tlist);
-static List *replace_subclause_joinvar_refs(List *clauses,
- List *outer_tlist, List *inner_tlist);
-static Var *replace_joinvar_refs(Var *var, List *outer_tlist, List *inner_tlist);
-static List *tlist_temp_references(Oid tempid, List *tlist);
-static void replace_result_clause(List *clause, List *subplanTargetList);
-static bool OperandIsInner(Node *opnd, int inner_relid);
-static void replace_agg_clause(Node *expr, List *targetlist);
+static void set_join_tlist_references(Join * join);
+static void set_tempscan_tlist_references(SeqScan * tempscan);
+static void set_temp_tlist_references(Temp * temp);
+static List *
+replace_clause_joinvar_refs(Expr * clause,
+ List * outer_tlist, List * inner_tlist);
+static List *
+replace_subclause_joinvar_refs(List * clauses,
+ List * outer_tlist, List * inner_tlist);
+static Var *replace_joinvar_refs(Var * var, List * outer_tlist, List * inner_tlist);
+static List *tlist_temp_references(Oid tempid, List * tlist);
+static void replace_result_clause(List * clause, List * subplanTargetList);
+static bool OperandIsInner(Node * opnd, int inner_relid);
+static void replace_agg_clause(Node * expr, List * targetlist);
/*****************************************************************************
- *
- * SUBPLAN REFERENCES
- *
+ *
+ * SUBPLAN REFERENCES
+ *
*****************************************************************************/
-/*
+/*
* set-tlist-references--
- * Modifies the target list of nodes in a plan to reference target lists
- * at lower levels.
- *
+ * Modifies the target list of nodes in a plan to reference target lists
+ * at lower levels.
+ *
* 'plan' is the plan whose target list and children's target lists will
- * be modified
- *
+ * be modified
+ *
* Returns nothing of interest, but modifies internal fields of nodes.
- *
+ *
*/
void
-set_tlist_references(Plan *plan)
+set_tlist_references(Plan * plan)
{
- if(plan==NULL)
- return;
-
- if (IsA_Join(plan)) {
- set_join_tlist_references((Join*)plan);
- } else if (IsA(plan,SeqScan) && plan->lefttree &&
- IsA_Temp(plan->lefttree)) {
- set_tempscan_tlist_references((SeqScan*)plan);
- } else if (IsA(plan,Sort)) {
- set_temp_tlist_references ((Temp*)plan);
- } else if (IsA(plan,Result)) {
- set_result_tlist_references((Result*)plan);
- } else if (IsA(plan,Hash)) {
- set_tlist_references(plan->lefttree);
- } else if (IsA(plan,Choose)) {
- List *x;
- foreach (x, ((Choose*)plan)->chooseplanlist) {
- set_tlist_references((Plan*)lfirst(x));
- }
- }
+ if (plan == NULL)
+ return;
+
+ if (IsA_Join(plan))
+ {
+ set_join_tlist_references((Join *) plan);
+ }
+ else if (IsA(plan, SeqScan) && plan->lefttree &&
+ IsA_Temp(plan->lefttree))
+ {
+ set_tempscan_tlist_references((SeqScan *) plan);
+ }
+ else if (IsA(plan, Sort))
+ {
+ set_temp_tlist_references((Temp *) plan);
+ }
+ else if (IsA(plan, Result))
+ {
+ set_result_tlist_references((Result *) plan);
+ }
+ else if (IsA(plan, Hash))
+ {
+ set_tlist_references(plan->lefttree);
+ }
+ else if (IsA(plan, Choose))
+ {
+ List *x;
+
+ foreach(x, ((Choose *) plan)->chooseplanlist)
+ {
+ set_tlist_references((Plan *) lfirst(x));
+ }
+ }
}
-/*
+/*
* set-join-tlist-references--
- * Modifies the target list of a join node by setting the varnos and
- * varattnos to reference the target list of the outer and inner join
- * relations.
- *
- * Creates a target list for a join node to contain references by setting
- * varno values to OUTER or INNER and setting attno values to the
- * result domain number of either the corresponding outer or inner join
- * tuple.
- *
+ * Modifies the target list of a join node by setting the varnos and
+ * varattnos to reference the target list of the outer and inner join
+ * relations.
+ *
+ * Creates a target list for a join node to contain references by setting
+ * varno values to OUTER or INNER and setting attno values to the
+ * result domain number of either the corresponding outer or inner join
+ * tuple.
+ *
* 'join' is a join plan node
- *
+ *
* Returns nothing of interest, but modifies internal fields of nodes.
- *
+ *
*/
static void
-set_join_tlist_references(Join *join)
+set_join_tlist_references(Join * join)
{
- Plan *outer = ((Plan*)join)->lefttree;
- Plan *inner = ((Plan*)join)->righttree;
- List *new_join_targetlist = NIL;
- TargetEntry *temp = (TargetEntry *)NULL;
- List *entry = NIL;
- List *inner_tlist = NULL;
- List *outer_tlist = NULL;
- TargetEntry *xtl = (TargetEntry *)NULL;
- List *qptlist = ((Plan*)join)->targetlist;
-
- foreach(entry, qptlist) {
- List *joinvar;
-
- xtl = (TargetEntry *)lfirst(entry);
- inner_tlist = ((inner==NULL) ? NIL : inner->targetlist);
- outer_tlist = ((outer==NULL) ? NIL : outer->targetlist);
- joinvar = replace_clause_joinvar_refs((Expr*)get_expr(xtl),
- outer_tlist,
- inner_tlist);
-
- temp = MakeTLE(xtl->resdom, (Node*)joinvar);
- new_join_targetlist = lappend(new_join_targetlist,temp);
- }
-
- ((Plan*)join)->targetlist = new_join_targetlist;
- if (outer!=NULL)
- set_tlist_references(outer);
- if (inner!=NULL)
- set_tlist_references(inner);
+ Plan *outer = ((Plan *) join)->lefttree;
+ Plan *inner = ((Plan *) join)->righttree;
+ List *new_join_targetlist = NIL;
+ TargetEntry *temp = (TargetEntry *) NULL;
+ List *entry = NIL;
+ List *inner_tlist = NULL;
+ List *outer_tlist = NULL;
+ TargetEntry *xtl = (TargetEntry *) NULL;
+ List *qptlist = ((Plan *) join)->targetlist;
+
+ foreach(entry, qptlist)
+ {
+ List *joinvar;
+
+ xtl = (TargetEntry *) lfirst(entry);
+ inner_tlist = ((inner == NULL) ? NIL : inner->targetlist);
+ outer_tlist = ((outer == NULL) ? NIL : outer->targetlist);
+ joinvar = replace_clause_joinvar_refs((Expr *) get_expr(xtl),
+ outer_tlist,
+ inner_tlist);
+
+ temp = MakeTLE(xtl->resdom, (Node *) joinvar);
+ new_join_targetlist = lappend(new_join_targetlist, temp);
+ }
+
+ ((Plan *) join)->targetlist = new_join_targetlist;
+ if (outer != NULL)
+ set_tlist_references(outer);
+ if (inner != NULL)
+ set_tlist_references(inner);
}
-/*
+/*
* set-tempscan-tlist-references--
- * Modifies the target list of a node that scans a temp relation (i.e., a
- * sort or hash node) so that the varnos refer to the child temporary.
- *
+ * Modifies the target list of a node that scans a temp relation (i.e., a
+ * sort or hash node) so that the varnos refer to the child temporary.
+ *
* 'tempscan' is a seqscan node
- *
+ *
* Returns nothing of interest, but modifies internal fields of nodes.
- *
+ *
*/
static void
-set_tempscan_tlist_references(SeqScan *tempscan)
+set_tempscan_tlist_references(SeqScan * tempscan)
{
- Temp *temp = (Temp*)((Plan*)tempscan)->lefttree;
+ Temp *temp = (Temp *) ((Plan *) tempscan)->lefttree;
- ((Plan*)tempscan)->targetlist =
- tlist_temp_references(temp->tempid,
- ((Plan*)tempscan)->targetlist);
- set_temp_tlist_references(temp);
+ ((Plan *) tempscan)->targetlist =
+ tlist_temp_references(temp->tempid,
+ ((Plan *) tempscan)->targetlist);
+ set_temp_tlist_references(temp);
}
-/*
+/*
* set-temp-tlist-references--
- * The temp's vars are made consistent with (actually, identical to) the
- * modified version of the target list of the node from which temp node
- * receives its tuples.
- *
+ * The temp's vars are made consistent with (actually, identical to) the
+ * modified version of the target list of the node from which temp node
+ * receives its tuples.
+ *
* 'temp' is a temp (e.g., sort, hash) plan node
- *
+ *
* Returns nothing of interest, but modifies internal fields of nodes.
- *
+ *
*/
static void
-set_temp_tlist_references(Temp *temp)
+set_temp_tlist_references(Temp * temp)
{
- Plan *source = ((Plan*)temp)->lefttree;
-
- if (source!=NULL) {
- set_tlist_references(source);
- ((Plan*)temp)->targetlist =
- copy_vars(((Plan*)temp)->targetlist ,
- (source)->targetlist);
- } else {
- elog(WARN, "calling set_temp_tlist_references with empty lefttree");
- }
+ Plan *source = ((Plan *) temp)->lefttree;
+
+ if (source != NULL)
+ {
+ set_tlist_references(source);
+ ((Plan *) temp)->targetlist =
+ copy_vars(((Plan *) temp)->targetlist,
+ (source)->targetlist);
+ }
+ else
+ {
+ elog(WARN, "calling set_temp_tlist_references with empty lefttree");
+ }
}
-/*
+/*
* join-references--
- * Creates a new set of join clauses by replacing the varno/varattno
- * values of variables in the clauses to reference target list values
- * from the outer and inner join relation target lists.
- *
+ * Creates a new set of join clauses by replacing the varno/varattno
+ * values of variables in the clauses to reference target list values
+ * from the outer and inner join relation target lists.
+ *
* 'clauses' is the list of join clauses
* 'outer-tlist' is the target list of the outer join relation
* 'inner-tlist' is the target list of the inner join relation
- *
+ *
* Returns the new join clauses.
- *
+ *
*/
-List *
-join_references(List *clauses,
- List *outer_tlist,
- List *inner_tlist)
+List *
+join_references(List * clauses,
+ List * outer_tlist,
+ List * inner_tlist)
{
- return (replace_subclause_joinvar_refs(clauses,
- outer_tlist,
- inner_tlist));
+ return (replace_subclause_joinvar_refs(clauses,
+ outer_tlist,
+ inner_tlist));
}
-/*
+/*
* index-outerjoin-references--
- * Given a list of join clauses, replace the operand corresponding to the
- * outer relation in the join with references to the corresponding target
- * list element in 'outer-tlist' (the outer is rather obscurely
- * identified as the side that doesn't contain a var whose varno equals
- * 'inner-relid').
- *
- * As a side effect, the operator is replaced by the regproc id.
- *
+ * Given a list of join clauses, replace the operand corresponding to the
+ * outer relation in the join with references to the corresponding target
+ * list element in 'outer-tlist' (the outer is rather obscurely
+ * identified as the side that doesn't contain a var whose varno equals
+ * 'inner-relid').
+ *
+ * As a side effect, the operator is replaced by the regproc id.
+ *
* 'inner-indxqual' is the list of join clauses (so-called because they
* are used as qualifications for the inner (inbex) scan of a nestloop)
- *
+ *
* Returns the new list of clauses.
- *
+ *
*/
-List *
-index_outerjoin_references(List *inner_indxqual,
- List *outer_tlist,
- Index inner_relid)
+List *
+index_outerjoin_references(List * inner_indxqual,
+ List * outer_tlist,
+ Index inner_relid)
{
- List *t_list = NIL;
- Expr *temp = NULL;
- List *t_clause = NIL;
- Expr *clause = NULL;
+ List *t_list = NIL;
+ Expr *temp = NULL;
+ List *t_clause = NIL;
+ Expr *clause = NULL;
- foreach (t_clause,inner_indxqual) {
- clause = lfirst(t_clause);
- /*
- * if inner scan on the right.
- */
- if (OperandIsInner((Node*)get_rightop(clause), inner_relid)) {
- Var *joinvar = (Var*)
- replace_clause_joinvar_refs((Expr*)get_leftop(clause),
- outer_tlist,
- NIL);
- temp = make_opclause(replace_opid((Oper*)((Expr*)clause)->oper),
- joinvar,
- get_rightop(clause));
- t_list = lappend(t_list,temp);
- } else {
- /* inner scan on left */
- Var *joinvar = (Var*)
- replace_clause_joinvar_refs((Expr*)get_rightop(clause),
- outer_tlist,
- NIL);
- temp = make_opclause(replace_opid((Oper*)((Expr*)clause)->oper),
- get_leftop(clause),
- joinvar);
- t_list = lappend(t_list,temp);
- }
-
- }
- return(t_list);
+ foreach(t_clause, inner_indxqual)
+ {
+ clause = lfirst(t_clause);
+
+ /*
+ * if inner scan on the right.
+ */
+ if (OperandIsInner((Node *) get_rightop(clause), inner_relid))
+ {
+ Var *joinvar = (Var *)
+ replace_clause_joinvar_refs((Expr *) get_leftop(clause),
+ outer_tlist,
+ NIL);
+
+ temp = make_opclause(replace_opid((Oper *) ((Expr *) clause)->oper),
+ joinvar,
+ get_rightop(clause));
+ t_list = lappend(t_list, temp);
+ }
+ else
+ {
+ /* inner scan on left */
+ Var *joinvar = (Var *)
+ replace_clause_joinvar_refs((Expr *) get_rightop(clause),
+ outer_tlist,
+ NIL);
+
+ temp = make_opclause(replace_opid((Oper *) ((Expr *) clause)->oper),
+ get_leftop(clause),
+ joinvar);
+ t_list = lappend(t_list, temp);
+ }
+
+ }
+ return (t_list);
}
-/*
+/*
* replace-clause-joinvar-refs
* replace-subclause-joinvar-refs
* replace-joinvar-refs
- *
- * Replaces all variables within a join clause with a new var node
- * whose varno/varattno fields contain a reference to a target list
- * element from either the outer or inner join relation.
- *
+ *
+ * Replaces all variables within a join clause with a new var node
+ * whose varno/varattno fields contain a reference to a target list
+ * element from either the outer or inner join relation.
+ *
* 'clause' is the join clause
* 'outer-tlist' is the target list of the outer join relation
* 'inner-tlist' is the target list of the inner join relation
- *
+ *
* Returns the new join clause.
- *
+ *
*/
-static List *
-replace_clause_joinvar_refs(Expr *clause,
- List *outer_tlist,
- List *inner_tlist)
+static List *
+replace_clause_joinvar_refs(Expr * clause,
+ List * outer_tlist,
+ List * inner_tlist)
{
- List *temp = NULL;
+ List *temp = NULL;
- if(IsA (clause,Var)) {
- temp = (List*)replace_joinvar_refs((Var*)clause,
- outer_tlist,inner_tlist);
- if(temp)
- return(temp);
- else
- if (clause != NULL)
- return((List*)clause);
- else
- return(NIL);
- } else if (single_node((Node*)clause)) {
- return ((List*)clause);
- } else if (or_clause((Node*)clause)) {
- List *orclause =
- replace_subclause_joinvar_refs(((Expr*)clause)->args,
- outer_tlist,
- inner_tlist);
- return ((List*)make_orclause(orclause));
- } else if (IsA(clause,ArrayRef)) {
- ArrayRef *aref = (ArrayRef *)clause;
-
- temp = replace_subclause_joinvar_refs(aref->refupperindexpr,
- outer_tlist,
- inner_tlist);
- aref->refupperindexpr = (List*)temp;
- temp = replace_subclause_joinvar_refs(aref->reflowerindexpr,
- outer_tlist,
- inner_tlist);
- aref->reflowerindexpr = (List*)temp;
- temp = replace_clause_joinvar_refs((Expr*)aref->refexpr,
- outer_tlist,
- inner_tlist);
- aref->refexpr = (Node*)temp;
+ if (IsA(clause, Var))
+ {
+ temp = (List *) replace_joinvar_refs((Var *) clause,
+ outer_tlist, inner_tlist);
+ if (temp)
+ return (temp);
+ else if (clause != NULL)
+ return ((List *) clause);
+ else
+ return (NIL);
+ }
+ else if (single_node((Node *) clause))
+ {
+ return ((List *) clause);
+ }
+ else if (or_clause((Node *) clause))
+ {
+ List *orclause =
+ replace_subclause_joinvar_refs(((Expr *) clause)->args,
+ outer_tlist,
+ inner_tlist);
- /*
- * no need to set refassgnexpr. we only set that in the
- * target list on replaces, and this is an array reference
- * in the qualification. if we got this far, it's 0x0 in
- * the ArrayRef structure 'clause'.
- */
+ return ((List *) make_orclause(orclause));
+ }
+ else if (IsA(clause, ArrayRef))
+ {
+ ArrayRef *aref = (ArrayRef *) clause;
+
+ temp = replace_subclause_joinvar_refs(aref->refupperindexpr,
+ outer_tlist,
+ inner_tlist);
+ aref->refupperindexpr = (List *) temp;
+ temp = replace_subclause_joinvar_refs(aref->reflowerindexpr,
+ outer_tlist,
+ inner_tlist);
+ aref->reflowerindexpr = (List *) temp;
+ temp = replace_clause_joinvar_refs((Expr *) aref->refexpr,
+ outer_tlist,
+ inner_tlist);
+ aref->refexpr = (Node *) temp;
+
+ /*
+ * no need to set refassgnexpr. we only set that in the target
+ * list on replaces, and this is an array reference in the
+ * qualification. if we got this far, it's 0x0 in the ArrayRef
+ * structure 'clause'.
+ */
+
+ return ((List *) clause);
+ }
+ else if (is_funcclause((Node *) clause))
+ {
+ List *funcclause =
+ replace_subclause_joinvar_refs(((Expr *) clause)->args,
+ outer_tlist,
+ inner_tlist);
+
+ return ((List *) make_funcclause((Func *) ((Expr *) clause)->oper,
+ funcclause));
+ }
+ else if (not_clause((Node *) clause))
+ {
+ List *notclause =
+ replace_clause_joinvar_refs(get_notclausearg(clause),
+ outer_tlist,
+ inner_tlist);
- return((List*)clause);
- } else if (is_funcclause((Node*)clause)) {
- List *funcclause =
- replace_subclause_joinvar_refs(((Expr*)clause)->args,
- outer_tlist,
- inner_tlist);
- return ((List*)make_funcclause((Func*)((Expr*)clause)->oper,
- funcclause));
- } else if (not_clause((Node*)clause)) {
- List *notclause =
- replace_clause_joinvar_refs(get_notclausearg(clause),
- outer_tlist,
- inner_tlist);
- return ((List*)make_notclause((Expr*)notclause));
- } else if (is_opclause((Node*)clause)) {
- Var *leftvar =
- (Var*)replace_clause_joinvar_refs((Expr*)get_leftop(clause),
- outer_tlist,
- inner_tlist);
- Var *rightvar =
- (Var*)replace_clause_joinvar_refs((Expr*)get_rightop(clause),
- outer_tlist,
- inner_tlist);
- return ((List*)make_opclause(replace_opid((Oper*)((Expr*)clause)->oper),
- leftvar,
- rightvar));
- }
- /* shouldn't reach here */
- return NULL;
+ return ((List *) make_notclause((Expr *) notclause));
+ }
+ else if (is_opclause((Node *) clause))
+ {
+ Var *leftvar =
+ (Var *) replace_clause_joinvar_refs((Expr *) get_leftop(clause),
+ outer_tlist,
+ inner_tlist);
+ Var *rightvar =
+ (Var *) replace_clause_joinvar_refs((Expr *) get_rightop(clause),
+ outer_tlist,
+ inner_tlist);
+
+ return ((List *) make_opclause(replace_opid((Oper *) ((Expr *) clause)->oper),
+ leftvar,
+ rightvar));
+ }
+ /* shouldn't reach here */
+ return NULL;
}
-static List *
-replace_subclause_joinvar_refs(List *clauses,
- List *outer_tlist,
- List *inner_tlist)
+static List *
+replace_subclause_joinvar_refs(List * clauses,
+ List * outer_tlist,
+ List * inner_tlist)
{
- List *t_list = NIL;
- List *temp = NIL;
- List *clause = NIL;
-
- foreach (clause,clauses) {
- temp = replace_clause_joinvar_refs(lfirst(clause),
- outer_tlist,
- inner_tlist);
- t_list = lappend(t_list,temp);
- }
- return(t_list);
+ List *t_list = NIL;
+ List *temp = NIL;
+ List *clause = NIL;
+
+ foreach(clause, clauses)
+ {
+ temp = replace_clause_joinvar_refs(lfirst(clause),
+ outer_tlist,
+ inner_tlist);
+ t_list = lappend(t_list, temp);
+ }
+ return (t_list);
}
-static Var *
-replace_joinvar_refs(Var *var, List *outer_tlist, List *inner_tlist)
+static Var *
+replace_joinvar_refs(Var * var, List * outer_tlist, List * inner_tlist)
{
- Resdom *outer_resdom =(Resdom*)NULL;
-
- outer_resdom= tlist_member(var,outer_tlist);
-
- if (outer_resdom!=NULL && IsA (outer_resdom,Resdom) ) {
- return (makeVar (OUTER,
- outer_resdom->resno,
- var->vartype,
- var->varnoold,
- var->varoattno));
- } else {
- Resdom *inner_resdom;
- inner_resdom = tlist_member(var,inner_tlist);
- if ( inner_resdom!=NULL && IsA (inner_resdom,Resdom) ) {
- return (makeVar (INNER,
- inner_resdom->resno,
- var->vartype,
- var->varnoold,
- var->varoattno));
- }
- }
- return (Var*)NULL;
+ Resdom *outer_resdom = (Resdom *) NULL;
+
+ outer_resdom = tlist_member(var, outer_tlist);
+
+ if (outer_resdom != NULL && IsA(outer_resdom, Resdom))
+ {
+ return (makeVar(OUTER,
+ outer_resdom->resno,
+ var->vartype,
+ var->varnoold,
+ var->varoattno));
+ }
+ else
+ {
+ Resdom *inner_resdom;
+
+ inner_resdom = tlist_member(var, inner_tlist);
+ if (inner_resdom != NULL && IsA(inner_resdom, Resdom))
+ {
+ return (makeVar(INNER,
+ inner_resdom->resno,
+ var->vartype,
+ var->varnoold,
+ var->varoattno));
+ }
+ }
+ return (Var *) NULL;
}
-/*
+/*
* tlist-temp-references--
- * Creates a new target list for a node that scans a temp relation,
- * setting the varnos to the id of the temp relation and setting varids
- * if necessary (varids are only needed if this is a targetlist internal
- * to the tree, in which case the targetlist entry always contains a var
- * node, so we can just copy it from the temp).
- *
+ * Creates a new target list for a node that scans a temp relation,
+ * setting the varnos to the id of the temp relation and setting varids
+ * if necessary (varids are only needed if this is a targetlist internal
+ * to the tree, in which case the targetlist entry always contains a var
+ * node, so we can just copy it from the temp).
+ *
* 'tempid' is the id of the temp relation
* 'tlist' is the target list to be modified
- *
+ *
* Returns new target list
- *
+ *
*/
-static List *
-tlist_temp_references(Oid tempid,
- List *tlist)
+static List *
+tlist_temp_references(Oid tempid,
+ List * tlist)
{
- List *t_list = NIL;
- TargetEntry *temp = (TargetEntry *)NULL;
- TargetEntry *xtl = NULL;
- List *entry;
-
- foreach (entry, tlist) {
- AttrNumber oattno;
-
- xtl = lfirst(entry);
- if (IsA(get_expr(xtl), Var))
- oattno = ((Var*)xtl->expr)->varoattno;
- else
- oattno = 0;
-
- temp = MakeTLE(xtl->resdom,
- (Node*)makeVar(tempid,
- xtl->resdom->resno,
- xtl->resdom->restype,
- tempid,
- oattno));
-
- t_list = lappend(t_list,temp);
- }
- return(t_list);
+ List *t_list = NIL;
+ TargetEntry *temp = (TargetEntry *) NULL;
+ TargetEntry *xtl = NULL;
+ List *entry;
+
+ foreach(entry, tlist)
+ {
+ AttrNumber oattno;
+
+ xtl = lfirst(entry);
+ if (IsA(get_expr(xtl), Var))
+ oattno = ((Var *) xtl->expr)->varoattno;
+ else
+ oattno = 0;
+
+ temp = MakeTLE(xtl->resdom,
+ (Node *) makeVar(tempid,
+ xtl->resdom->resno,
+ xtl->resdom->restype,
+ tempid,
+ oattno));
+
+ t_list = lappend(t_list, temp);
+ }
+ return (t_list);
}
/*---------------------------------------------------------
@@ -456,45 +505,49 @@ tlist_temp_references(Oid tempid,
* addresses the tuples returned by its left tree subplan.
*
* NOTE:
- * 1) we ignore the right tree! (in the current implementation
- * it is always nil
- * 2) this routine will probably *NOT* work with nested dot
- * fields....
+ * 1) we ignore the right tree! (in the current implementation
+ * it is always nil
+ * 2) this routine will probably *NOT* work with nested dot
+ * fields....
*/
void
-set_result_tlist_references(Result *resultNode)
+set_result_tlist_references(Result * resultNode)
{
- Plan *subplan;
- List *resultTargetList;
- List *subplanTargetList;
- List *t;
- TargetEntry *entry;
- Expr *expr;
-
- resultTargetList= ((Plan*)resultNode)->targetlist;
-
- /*
- * NOTE: we only consider the left tree subplan.
- * This is usually a seq scan.
- */
- subplan = ((Plan*)resultNode)->lefttree;
- if (subplan != NULL) {
- subplanTargetList = subplan->targetlist;
- } else {
- subplanTargetList = NIL;
- }
-
- /*
- * now for traverse all the entris of the target list.
- * These should be of the form (Resdom_Node Expression).
- * For every expression clause, call "replace_result_clause()"
- * to appropriatelly change all the Var nodes.
- */
- foreach (t, resultTargetList) {
- entry = (TargetEntry *)lfirst(t);
- expr = (Expr*) get_expr(entry);
- replace_result_clause((List*)expr, subplanTargetList);
- }
+ Plan *subplan;
+ List *resultTargetList;
+ List *subplanTargetList;
+ List *t;
+ TargetEntry *entry;
+ Expr *expr;
+
+ resultTargetList = ((Plan *) resultNode)->targetlist;
+
+ /*
+ * NOTE: we only consider the left tree subplan. This is usually a seq
+ * scan.
+ */
+ subplan = ((Plan *) resultNode)->lefttree;
+ if (subplan != NULL)
+ {
+ subplanTargetList = subplan->targetlist;
+ }
+ else
+ {
+ subplanTargetList = NIL;
+ }
+
+ /*
+ * now for traverse all the entris of the target list. These should be
+ * of the form (Resdom_Node Expression). For every expression clause,
+ * call "replace_result_clause()" to appropriatelly change all the Var
+ * nodes.
+ */
+ foreach(t, resultTargetList)
+ {
+ entry = (TargetEntry *) lfirst(t);
+ expr = (Expr *) get_expr(entry);
+ replace_result_clause((List *) expr, subplanTargetList);
+ }
}
/*---------------------------------------------------------
@@ -504,100 +557,121 @@ set_result_tlist_references(Result *resultNode)
* This routine is called from set_result_tlist_references().
* and modifies the expressions of the target list of a Result
* node so that all Var nodes reference the target list of its subplan.
- *
+ *
*/
static void
-replace_result_clause(List *clause,
- List *subplanTargetList) /* target list of the
- subplan */
+replace_result_clause(List * clause,
+ List * subplanTargetList) /* target list of the
+ * subplan */
{
- List *t;
- List *subClause;
- TargetEntry *subplanVar;
+ List *t;
+ List *subClause;
+ TargetEntry *subplanVar;
- if (IsA(clause,Var)) {
- /*
- * Ha! A Var node!
- */
- subplanVar = match_varid((Var*)clause, subplanTargetList);
- /*
- * Change the varno & varattno fields of the
- * var node.
- *
- */
- ((Var*)clause)->varno = (Index)OUTER;
- ((Var*)clause)->varattno = subplanVar->resdom->resno;
- } else if (is_funcclause((Node*)clause)) {
- /*
- * This is a function. Recursively call this routine
- * for its arguments...
- */
- subClause = ((Expr*)clause)->args;
- foreach (t, subClause) {
- replace_result_clause(lfirst(t),subplanTargetList);
- }
- } else if (IsA(clause,ArrayRef)) {
- ArrayRef *aref = (ArrayRef *)clause;
- /*
- * This is an arrayref. Recursively call this routine
- * for its expression and its index expression...
- */
- subClause = aref->refupperindexpr;
- foreach (t, subClause) {
- replace_result_clause(lfirst(t),subplanTargetList);
- }
- subClause = aref->reflowerindexpr;
- foreach (t, subClause) {
- replace_result_clause(lfirst(t),subplanTargetList);
- }
- replace_result_clause((List*)aref->refexpr,
- subplanTargetList);
- replace_result_clause((List*)aref->refassgnexpr,
- subplanTargetList);
- } else if (is_opclause((Node*)clause)) {
- /*
- * This is an operator. Recursively call this routine
- * for both its left and right operands
- */
- subClause = (List*)get_leftop((Expr*)clause);
- replace_result_clause(subClause,subplanTargetList);
- subClause = (List*)get_rightop((Expr*)clause);
- replace_result_clause(subClause,subplanTargetList);
- } else if (IsA(clause,Param) || IsA(clause,Const)) {
- /* do nothing! */
- } else {
- /*
- * Ooops! we can not handle that!
- */
- elog(WARN,"replace_result_clause: Can not handle this tlist!\n");
- }
+ if (IsA(clause, Var))
+ {
+
+ /*
+ * Ha! A Var node!
+ */
+ subplanVar = match_varid((Var *) clause, subplanTargetList);
+
+ /*
+ * Change the varno & varattno fields of the var node.
+ *
+ */
+ ((Var *) clause)->varno = (Index) OUTER;
+ ((Var *) clause)->varattno = subplanVar->resdom->resno;
+ }
+ else if (is_funcclause((Node *) clause))
+ {
+
+ /*
+ * This is a function. Recursively call this routine for its
+ * arguments...
+ */
+ subClause = ((Expr *) clause)->args;
+ foreach(t, subClause)
+ {
+ replace_result_clause(lfirst(t), subplanTargetList);
+ }
+ }
+ else if (IsA(clause, ArrayRef))
+ {
+ ArrayRef *aref = (ArrayRef *) clause;
+
+ /*
+ * This is an arrayref. Recursively call this routine for its
+ * expression and its index expression...
+ */
+ subClause = aref->refupperindexpr;
+ foreach(t, subClause)
+ {
+ replace_result_clause(lfirst(t), subplanTargetList);
+ }
+ subClause = aref->reflowerindexpr;
+ foreach(t, subClause)
+ {
+ replace_result_clause(lfirst(t), subplanTargetList);
+ }
+ replace_result_clause((List *) aref->refexpr,
+ subplanTargetList);
+ replace_result_clause((List *) aref->refassgnexpr,
+ subplanTargetList);
+ }
+ else if (is_opclause((Node *) clause))
+ {
+
+ /*
+ * This is an operator. Recursively call this routine for both its
+ * left and right operands
+ */
+ subClause = (List *) get_leftop((Expr *) clause);
+ replace_result_clause(subClause, subplanTargetList);
+ subClause = (List *) get_rightop((Expr *) clause);
+ replace_result_clause(subClause, subplanTargetList);
+ }
+ else if (IsA(clause, Param) || IsA(clause, Const))
+ {
+ /* do nothing! */
+ }
+ else
+ {
+
+ /*
+ * Ooops! we can not handle that!
+ */
+ elog(WARN, "replace_result_clause: Can not handle this tlist!\n");
+ }
}
static
-bool OperandIsInner(Node *opnd, int inner_relid)
+bool
+OperandIsInner(Node * opnd, int inner_relid)
{
- /*
- * Can be the inner scan if its a varnode or a function and the
- * inner_relid is equal to the varnode's var number or in the
- * case of a function the first argument's var number (all args
- * in a functional index are from the same relation).
- */
- if ( IsA (opnd,Var) &&
- (inner_relid == ((Var*)opnd)->varno) )
+
+ /*
+ * Can be the inner scan if its a varnode or a function and the
+ * inner_relid is equal to the varnode's var number or in the case of
+ * a function the first argument's var number (all args in a
+ * functional index are from the same relation).
+ */
+ if (IsA(opnd, Var) &&
+ (inner_relid == ((Var *) opnd)->varno))
{
- return true;
+ return true;
}
- if (is_funcclause(opnd))
+ if (is_funcclause(opnd))
{
- List *firstArg = lfirst(((Expr*)opnd)->args);
+ List *firstArg = lfirst(((Expr *) opnd)->args);
- if ( IsA (firstArg,Var) &&
- (inner_relid == ((Var*)firstArg)->varno) )
+ if (IsA(firstArg, Var) &&
+ (inner_relid == ((Var *) firstArg)->varno))
{
- return true;
+ return true;
}
}
- return false;
+ return false;
}
/*****************************************************************************
@@ -607,105 +681,125 @@ bool OperandIsInner(Node *opnd, int inner_relid)
/*---------------------------------------------------------
*
* set_agg_tlist_references -
- * changes the target list of an Agg node so that it points to
- * the tuples returned by its left tree subplan.
+ * changes the target list of an Agg node so that it points to
+ * the tuples returned by its left tree subplan.
*
*/
void
-set_agg_tlist_references(Agg *aggNode)
+set_agg_tlist_references(Agg * aggNode)
{
- List *aggTargetList;
- List *subplanTargetList;
- List *tl;
+ List *aggTargetList;
+ List *subplanTargetList;
+ List *tl;
- aggTargetList = aggNode->plan.targetlist;
- subplanTargetList = aggNode->plan.lefttree->targetlist;
+ aggTargetList = aggNode->plan.targetlist;
+ subplanTargetList = aggNode->plan.lefttree->targetlist;
- foreach (tl, aggTargetList) {
- TargetEntry *tle = lfirst(tl);
+ foreach(tl, aggTargetList)
+ {
+ TargetEntry *tle = lfirst(tl);
- replace_agg_clause(tle->expr, subplanTargetList);
- }
+ replace_agg_clause(tle->expr, subplanTargetList);
+ }
}
void
-set_agg_agglist_references(Agg *aggNode)
+set_agg_agglist_references(Agg * aggNode)
{
- List *subplanTargetList;
- Aggreg **aggs;
- int i;
+ List *subplanTargetList;
+ Aggreg **aggs;
+ int i;
- aggs = aggNode->aggs;
- subplanTargetList = aggNode->plan.lefttree->targetlist;
+ aggs = aggNode->aggs;
+ subplanTargetList = aggNode->plan.lefttree->targetlist;
- for (i = 0; i < aggNode->numAgg; i++) {
- replace_agg_clause(aggs[i]->target, subplanTargetList);
- }
+ for (i = 0; i < aggNode->numAgg; i++)
+ {
+ replace_agg_clause(aggs[i]->target, subplanTargetList);
+ }
}
static void
-replace_agg_clause(Node *clause, List *subplanTargetList)
+replace_agg_clause(Node * clause, List * subplanTargetList)
{
- List *t;
- TargetEntry *subplanVar;
+ List *t;
+ TargetEntry *subplanVar;
- if (IsA(clause,Var)) {
- /*
- * Ha! A Var node!
- */
- subplanVar = match_varid((Var*)clause, subplanTargetList);
- /*
- * Change the varno & varattno fields of the
- * var node.
- *
- */
- ((Var*)clause)->varattno = subplanVar->resdom->resno;
- } else if (is_funcclause(clause)) {
- /*
- * This is a function. Recursively call this routine
- * for its arguments...
- */
- foreach (t, ((Expr*)clause)->args) {
- replace_agg_clause(lfirst(t), subplanTargetList);
- }
- } else if (IsA(clause,Aggreg)) {
- replace_agg_clause(((Aggreg*)clause)->target, subplanTargetList);
- } else if (IsA(clause,ArrayRef)) {
- ArrayRef *aref = (ArrayRef *)clause;
+ if (IsA(clause, Var))
+ {
- /*
- * This is an arrayref. Recursively call this routine
- * for its expression and its index expression...
- */
- foreach (t, aref->refupperindexpr) {
- replace_agg_clause(lfirst(t),subplanTargetList);
+ /*
+ * Ha! A Var node!
+ */
+ subplanVar = match_varid((Var *) clause, subplanTargetList);
+
+ /*
+ * Change the varno & varattno fields of the var node.
+ *
+ */
+ ((Var *) clause)->varattno = subplanVar->resdom->resno;
+ }
+ else if (is_funcclause(clause))
+ {
+
+ /*
+ * This is a function. Recursively call this routine for its
+ * arguments...
+ */
+ foreach(t, ((Expr *) clause)->args)
+ {
+ replace_agg_clause(lfirst(t), subplanTargetList);
+ }
}
- foreach (t, aref->reflowerindexpr) {
- replace_agg_clause(lfirst(t),subplanTargetList);
+ else if (IsA(clause, Aggreg))
+ {
+ replace_agg_clause(((Aggreg *) clause)->target, subplanTargetList);
}
- replace_agg_clause(aref->refexpr, subplanTargetList);
- replace_agg_clause(aref->refassgnexpr, subplanTargetList);
- } else if (is_opclause(clause)) {
- /*
- * This is an operator. Recursively call this routine
- * for both its left and right operands
- */
- Node *left = (Node*)get_leftop((Expr*)clause);
- Node *right = (Node*)get_rightop((Expr*)clause);
-
- if ( left != (Node*) NULL )
- replace_agg_clause(left, subplanTargetList);
- if ( right != (Node*) NULL )
- replace_agg_clause(right, subplanTargetList);
- } else if (IsA(clause,Param) || IsA(clause,Const)) {
- /* do nothing! */
- } else {
- /*
- * Ooops! we can not handle that!
- */
- elog(WARN,"replace_agg_clause: Can not handle this tlist!\n");
- }
+ else if (IsA(clause, ArrayRef))
+ {
+ ArrayRef *aref = (ArrayRef *) clause;
-}
+ /*
+ * This is an arrayref. Recursively call this routine for its
+ * expression and its index expression...
+ */
+ foreach(t, aref->refupperindexpr)
+ {
+ replace_agg_clause(lfirst(t), subplanTargetList);
+ }
+ foreach(t, aref->reflowerindexpr)
+ {
+ replace_agg_clause(lfirst(t), subplanTargetList);
+ }
+ replace_agg_clause(aref->refexpr, subplanTargetList);
+ replace_agg_clause(aref->refassgnexpr, subplanTargetList);
+ }
+ else if (is_opclause(clause))
+ {
+
+ /*
+ * This is an operator. Recursively call this routine for both its
+ * left and right operands
+ */
+ Node *left = (Node *) get_leftop((Expr *) clause);
+ Node *right = (Node *) get_rightop((Expr *) clause);
+
+ if (left != (Node *) NULL)
+ replace_agg_clause(left, subplanTargetList);
+ if (right != (Node *) NULL)
+ replace_agg_clause(right, subplanTargetList);
+ }
+ else if (IsA(clause, Param) || IsA(clause, Const))
+ {
+ /* do nothing! */
+ }
+ else
+ {
+ /*
+ * Ooops! we can not handle that!
+ */
+ elog(WARN, "replace_agg_clause: Can not handle this tlist!\n");
+ }
+}