diff options
Diffstat (limited to 'src/backend/optimizer/plan')
| -rw-r--r-- | src/backend/optimizer/plan/createplan.c | 2005 | ||||
| -rw-r--r-- | src/backend/optimizer/plan/initsplan.c | 579 | ||||
| -rw-r--r-- | src/backend/optimizer/plan/planmain.c | 952 | ||||
| -rw-r--r-- | src/backend/optimizer/plan/planner.c | 635 | ||||
| -rw-r--r-- | src/backend/optimizer/plan/setrefs.c | 1148 |
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"); + } +} |
