diff options
author | Marc G. Fournier <scrappy@hub.org> | 1996-07-09 06:22:35 +0000 |
---|---|---|
committer | Marc G. Fournier <scrappy@hub.org> | 1996-07-09 06:22:35 +0000 |
commit | d31084e9d1118b25fd16580d9d8c2924b5740dff (patch) | |
tree | 3179e66307d54df9c7b966543550e601eb55e668 /src/backend/optimizer/plan/initsplan.c | |
download | postgresql-PG95-1_01.tar.gz postgresql-PG95-1_01.zip |
Postgres95 1.01 Distribution - Virgin SourcesPG95-1_01
Diffstat (limited to 'src/backend/optimizer/plan/initsplan.c')
-rw-r--r-- | src/backend/optimizer/plan/initsplan.c | 391 |
1 files changed, 391 insertions, 0 deletions
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c new file mode 100644 index 00000000000..fc80402a050 --- /dev/null +++ b/src/backend/optimizer/plan/initsplan.c @@ -0,0 +1,391 @@ +/*------------------------------------------------------------------------- + * + * initsplan.c-- + * 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.1.1.1 1996/07/09 06:21:37 scrappy Exp $ + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "nodes/pg_list.h" +#include "nodes/plannodes.h" +#include "nodes/parsenodes.h" +#include "nodes/relation.h" +#include "nodes/makefuncs.h" + +#include "utils/lsyscache.h" +#include "utils/palloc.h" + +#include "optimizer/internal.h" +#include "optimizer/planmain.h" +#include "optimizer/joininfo.h" +#include "optimizer/pathnode.h" +#include "optimizer/tlist.h" +#include "optimizer/var.h" +#include "optimizer/clauses.h" +#include "optimizer/cost.h" + +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 MergeOrder *mergesortop(Expr *clause); +static Oid hashjoinop(Expr *clause); + + +/***************************************************************************** + * + * 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. + */ +void +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); + } +} + +/* + * 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. + */ +void +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); + } + pfree(relids); + varno++; + } + + return; +} + +/***************************************************************************** + * + * 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. + */ +void +initialize_base_rels_jinfo(Query *root, List *clauses) +{ + List *clause; + + 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. + */ +static void +add_clause_to_rels(Query *root, List *clause) +{ + List *relids; + List *vars; + CInfo *clauseinfo = makeNode(CInfo); + + /* + * 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; + + + + 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)) + { + /* + * 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 { + /* + * '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). + * + * '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) +{ + List *join_relid; + + foreach (join_relid, join_relids) { + JInfo *joininfo = + find_joininfo_node(get_base_rel(root, lfirsti(join_relid)), + intLispRemove((int)lfirst(join_relid), + join_relids)); + joininfo->jinfoclauseinfo = + lcons(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. + */ +static void +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); + } +} + +/***************************************************************************** + * + * 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. + */ +void +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; + } + } + } + } + } +} + +/* + * 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. + */ +static MergeOrder * +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); +} + +/* + * 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. + */ +static Oid +hashjoinop(Expr *clause) +{ + return(op_hashjoinable(((Oper*)clause->oper)->opno, + (get_leftop(clause))->vartype, + (get_rightop(clause))->vartype)); +} |