aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/plan
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2001-05-20 20:28:20 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2001-05-20 20:28:20 +0000
commitbe03eb25f34c9c95c400504ef76c8abe0081d09f (patch)
treeca3b081710826485bdaaad375b80e82f5a7fd611 /src/backend/optimizer/plan
parent5d53389cfe5ecacadda12f3a777a642605278e49 (diff)
downloadpostgresql-be03eb25f34c9c95c400504ef76c8abe0081d09f.tar.gz
postgresql-be03eb25f34c9c95c400504ef76c8abe0081d09f.zip
Modify optimizer data structures so that IndexOptInfo lists built for
create_index_paths are not immediately discarded, but are available for subsequent planner work. This allows avoiding redundant syscache lookups in several places. Change interface to operator selectivity estimation procedures to allow faster and more flexible estimation. Initdb forced due to change of pg_proc entries for selectivity functions!
Diffstat (limited to 'src/backend/optimizer/plan')
-rw-r--r--src/backend/optimizer/plan/createplan.c133
-rw-r--r--src/backend/optimizer/plan/initsplan.c26
-rw-r--r--src/backend/optimizer/plan/planmain.c3
-rw-r--r--src/backend/optimizer/plan/planner.c5
4 files changed, 67 insertions, 100 deletions
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 2d264c46881..81e7fec0427 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.105 2001/05/07 00:43:20 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.106 2001/05/20 20:28:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -18,7 +18,6 @@
#include <sys/types.h>
-#include "catalog/pg_index.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
@@ -27,6 +26,7 @@
#include "optimizer/planmain.h"
#include "optimizer/restrictinfo.h"
#include "optimizer/tlist.h"
+#include "optimizer/var.h"
#include "parser/parse_expr.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
@@ -56,11 +56,11 @@ static HashJoin *create_hashjoin_plan(HashPath *best_path, List *tlist,
Plan *outer_plan, List *outer_tlist,
Plan *inner_plan, List *inner_tlist);
static List *fix_indxqual_references(List *indexquals, IndexPath *index_path);
-static List *fix_indxqual_sublist(List *indexqual, int baserelid, Oid relam,
- Form_pg_index index);
+static List *fix_indxqual_sublist(List *indexqual, int baserelid,
+ IndexOptInfo *index);
static Node *fix_indxqual_operand(Node *node, int baserelid,
- Form_pg_index index,
- Oid *opclass);
+ IndexOptInfo *index,
+ Oid *opclass);
static List *switch_outer(List *clauses);
static void copy_path_costsize(Plan *dest, Path *src);
static void copy_plan_costsize(Plan *dest, Plan *src);
@@ -365,7 +365,7 @@ create_seqscan_plan(Path *best_path, List *tlist, List *scan_clauses)
* The indexqual of the path contains a sublist of implicitly-ANDed qual
* conditions for each scan of the index(es); if there is more than one
* scan then the retrieved tuple sets are ORed together. The indexqual
- * and indexid lists must have the same length, ie, the number of scans
+ * and indexinfo lists must have the same length, ie, the number of scans
* that will occur. Note it is possible for a qual condition sublist
* to be empty --- then no index restrictions will be applied during that
* scan.
@@ -380,9 +380,10 @@ create_indexscan_plan(Query *root,
Index baserelid;
List *qpqual;
List *fixed_indxqual;
- List *ixid;
+ List *indexids;
+ List *ixinfo;
IndexScan *scan_plan;
- bool lossy = false;
+ bool lossy;
/* there should be exactly one base rel involved... */
Assert(length(best_path->path.parent->relids) == 1);
@@ -390,25 +391,18 @@ create_indexscan_plan(Query *root,
baserelid = lfirsti(best_path->path.parent->relids);
- /* check to see if any of the indices are lossy */
- foreach(ixid, best_path->indexid)
+ /*
+ * Build list of index OIDs, and check to see if any of the indices
+ * are lossy.
+ */
+ indexids = NIL;
+ lossy = false;
+ foreach(ixinfo, best_path->indexinfo)
{
- HeapTuple indexTuple;
- Form_pg_index index;
-
- indexTuple = SearchSysCache(INDEXRELID,
- ObjectIdGetDatum(lfirsti(ixid)),
- 0, 0, 0);
- if (!HeapTupleIsValid(indexTuple))
- elog(ERROR, "create_plan: index %u not found", lfirsti(ixid));
- index = (Form_pg_index) GETSTRUCT(indexTuple);
- if (index->indislossy)
- {
- lossy = true;
- ReleaseSysCache(indexTuple);
- break;
- }
- ReleaseSysCache(indexTuple);
+ IndexOptInfo *index = (IndexOptInfo *) lfirst(ixinfo);
+
+ indexids = lappendi(indexids, index->indexoid);
+ lossy |= index->lossy;
}
/*
@@ -471,7 +465,7 @@ create_indexscan_plan(Query *root,
scan_plan = make_indexscan(tlist,
qpqual,
baserelid,
- best_path->indexid,
+ indexids,
fixed_indxqual,
indxqual,
best_path->indexscandir);
@@ -895,45 +889,19 @@ fix_indxqual_references(List *indexquals, IndexPath *index_path)
{
List *fixed_quals = NIL;
int baserelid = lfirsti(index_path->path.parent->relids);
- List *indexids = index_path->indexid;
+ List *ixinfo = index_path->indexinfo;
List *i;
foreach(i, indexquals)
{
List *indexqual = lfirst(i);
- Oid indexid = lfirsti(indexids);
- HeapTuple indexTuple;
- Oid relam;
- Form_pg_index index;
-
- /* Get the relam from the index's pg_class entry */
- indexTuple = SearchSysCache(RELOID,
- ObjectIdGetDatum(indexid),
- 0, 0, 0);
- if (!HeapTupleIsValid(indexTuple))
- elog(ERROR, "fix_indxqual_references: index %u not found in pg_class",
- indexid);
- relam = ((Form_pg_class) GETSTRUCT(indexTuple))->relam;
- ReleaseSysCache(indexTuple);
-
- /* Need the index's pg_index entry for other stuff */
- indexTuple = SearchSysCache(INDEXRELID,
- ObjectIdGetDatum(indexid),
- 0, 0, 0);
- if (!HeapTupleIsValid(indexTuple))
- elog(ERROR, "fix_indxqual_references: index %u not found in pg_index",
- indexid);
- index = (Form_pg_index) GETSTRUCT(indexTuple);
+ IndexOptInfo *index = (IndexOptInfo *) lfirst(ixinfo);
fixed_quals = lappend(fixed_quals,
fix_indxqual_sublist(indexqual,
baserelid,
- relam,
index));
-
- ReleaseSysCache(indexTuple);
-
- indexids = lnext(indexids);
+ ixinfo = lnext(ixinfo);
}
return fixed_quals;
}
@@ -946,8 +914,7 @@ fix_indxqual_references(List *indexquals, IndexPath *index_path)
* of the clause.) Also change the operator if necessary.
*/
static List *
-fix_indxqual_sublist(List *indexqual, int baserelid, Oid relam,
- Form_pg_index index)
+fix_indxqual_sublist(List *indexqual, int baserelid, IndexOptInfo *index)
{
List *fixed_qual = NIL;
List *i;
@@ -955,27 +922,15 @@ fix_indxqual_sublist(List *indexqual, int baserelid, Oid relam,
foreach(i, indexqual)
{
Expr *clause = (Expr *) lfirst(i);
- int relid;
- AttrNumber attno;
- Datum constval;
- int flag;
Expr *newclause;
+ List *leftvarnos;
Oid opclass,
newopno;
- if (!is_opclause((Node *) clause) ||
- length(clause->args) != 2)
+ if (!is_opclause((Node *) clause) || length(clause->args) != 2)
elog(ERROR, "fix_indxqual_sublist: indexqual clause is not binary opclause");
/*
- * Which side is the indexkey on?
- *
- * get_relattval sets flag&SEL_RIGHT if the indexkey is on the LEFT.
- */
- get_relattval((Node *) clause, baserelid,
- &relid, &attno, &constval, &flag);
-
- /*
* Make a copy that will become the fixed clause.
*
* We used to try to do a shallow copy here, but that fails if there
@@ -984,9 +939,15 @@ fix_indxqual_sublist(List *indexqual, int baserelid, Oid relam,
*/
newclause = (Expr *) copyObject((Node *) clause);
- /* If the indexkey is on the right, commute the clause. */
- if ((flag & SEL_RIGHT) == 0)
+ /*
+ * Check to see if the indexkey is on the right; if so, commute
+ * the clause. The indexkey should be the side that refers to
+ * (only) the base relation.
+ */
+ leftvarnos = pull_varnos((Node *) lfirst(newclause->args));
+ if (length(leftvarnos) != 1 || lfirsti(leftvarnos) != baserelid)
CommuteClause(newclause);
+ freeList(leftvarnos);
/*
* Now, determine which index attribute this is, change the
@@ -1002,7 +963,7 @@ fix_indxqual_sublist(List *indexqual, int baserelid, Oid relam,
* is merely binary-compatible with the index. This shouldn't
* fail, since indxpath.c found it before...
*/
- newopno = indexable_operator(newclause, opclass, relam, true);
+ newopno = indexable_operator(newclause, opclass, index->relam, true);
if (newopno == InvalidOid)
elog(ERROR, "fix_indxqual_sublist: failed to find substitute op");
((Oper *) newclause->oper)->opno = newopno;
@@ -1013,7 +974,7 @@ fix_indxqual_sublist(List *indexqual, int baserelid, Oid relam,
}
static Node *
-fix_indxqual_operand(Node *node, int baserelid, Form_pg_index index,
+fix_indxqual_operand(Node *node, int baserelid, IndexOptInfo *index,
Oid *opclass)
{
@@ -1033,27 +994,29 @@ fix_indxqual_operand(Node *node, int baserelid, Form_pg_index index,
if (IsA(node, Var))
{
/* If it's a var, find which index key position it occupies */
+ Assert(index->indproc == InvalidOid);
+
if (((Var *) node)->varno == baserelid)
{
int varatt = ((Var *) node)->varattno;
int pos;
- for (pos = 0; pos < INDEX_MAX_KEYS; pos++)
+ for (pos = 0; pos < index->nkeys; pos++)
{
- if (index->indkey[pos] == varatt)
+ if (index->indexkeys[pos] == varatt)
{
Node *newnode = copyObject(node);
((Var *) newnode)->varattno = pos + 1;
/* return the correct opclass, too */
- *opclass = index->indclass[pos];
+ *opclass = index->classlist[pos];
return newnode;
}
}
}
/*
- * Oops, this Var isn't the indexkey!
+ * Oops, this Var isn't an indexkey!
*/
elog(ERROR, "fix_indxqual_operand: var is not index attribute");
}
@@ -1063,11 +1026,11 @@ fix_indxqual_operand(Node *node, int baserelid, Form_pg_index index,
* Since we currently only support single-column functional indexes,
* the returned varattno must be 1.
*/
+ Assert(index->indproc != InvalidOid);
+ Assert(is_funcclause(node)); /* not a very thorough check, but easy */
- Assert(is_funcclause(node));/* not a very thorough check, but easy */
-
- /* indclass[0] is the only class of a functional index */
- *opclass = index->indclass[0];
+ /* classlist[0] is the only class of a functional index */
+ *opclass = index->classlist[0];
return (Node *) makeVar(baserelid, 1, exprType(node), -1, 0);
}
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index c62fd5ecd7d..3b3c761bca6 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.61 2001/05/14 20:25:00 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.62 2001/05/20 20:28:19 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -73,8 +73,8 @@ build_base_rel_tlists(Query *root, List *tlist)
/*
* add_vars_to_targetlist
* For each variable appearing in the list, add it to the relation's
- * targetlist if not already present. Rel nodes will also be created
- * if not already present.
+ * targetlist if not already present. Corresponding base rel nodes
+ * will be created if not already present.
*/
static void
add_vars_to_targetlist(Query *root, List *vars)
@@ -84,7 +84,7 @@ add_vars_to_targetlist(Query *root, List *vars)
foreach(temp, vars)
{
Var *var = (Var *) lfirst(temp);
- RelOptInfo *rel = get_base_rel(root, var->varno);
+ RelOptInfo *rel = build_base_rel(root, var->varno);
add_var_to_tlist(rel, var);
}
@@ -120,8 +120,8 @@ add_missing_rels_to_query(Query *root, Node *jtnode)
{
int varno = ((RangeTblRef *) jtnode)->rtindex;
- /* This call to get_base_rel does the primary work... */
- RelOptInfo *rel = get_base_rel(root, varno);
+ /* This call to build_base_rel does the primary work... */
+ RelOptInfo *rel = build_base_rel(root, varno);
result = makeList1(rel);
}
@@ -299,7 +299,7 @@ mark_baserels_for_outer_join(Query *root, Relids rels, Relids outerrels)
foreach(relid, rels)
{
int relno = lfirsti(relid);
- RelOptInfo *rel = get_base_rel(root, relno);
+ RelOptInfo *rel = build_base_rel(root, relno);
/*
* Since we do this bottom-up, any outer-rels previously marked
@@ -422,7 +422,7 @@ distribute_qual_to_rels(Query *root, Node *clause,
can_be_equijoin = true;
foreach(relid, relids)
{
- RelOptInfo *rel = get_base_rel(root, lfirsti(relid));
+ RelOptInfo *rel = build_base_rel(root, lfirsti(relid));
if (rel->outerjoinset &&
!is_subseti(rel->outerjoinset, relids))
@@ -454,12 +454,11 @@ distribute_qual_to_rels(Query *root, Node *clause,
if (length(relids) == 1)
{
-
/*
* There is only one relation participating in 'clause', so
* 'clause' is a restriction clause for that relation.
*/
- RelOptInfo *rel = get_base_rel(root, lfirsti(relids));
+ RelOptInfo *rel = build_base_rel(root, lfirsti(relids));
rel->baserestrictinfo = lappend(rel->baserestrictinfo,
restrictinfo);
@@ -564,7 +563,7 @@ add_join_info_to_rels(Query *root, RestrictInfo *restrictinfo,
* Find or make the joininfo node for this combination of rels,
* and add the restrictinfo node to it.
*/
- joininfo = find_joininfo_node(get_base_rel(root, cur_relid),
+ joininfo = find_joininfo_node(build_base_rel(root, cur_relid),
unjoined_relids);
joininfo->jinfo_restrictinfo = lappend(joininfo->jinfo_restrictinfo,
restrictinfo);
@@ -609,8 +608,11 @@ process_implied_equality(Query *root, Node *item1, Node *item2,
* If both vars belong to same rel, we need to look at that rel's
* baserestrictinfo list. If different rels, each will have a
* joininfo node for the other, and we can scan either list.
+ *
+ * All baserel entries should already exist at this point, so use
+ * find_base_rel not build_base_rel.
*/
- rel1 = get_base_rel(root, irel1);
+ rel1 = find_base_rel(root, irel1);
if (irel1 == irel2)
restrictlist = rel1->baserestrictinfo;
else
diff --git a/src/backend/optimizer/plan/planmain.c b/src/backend/optimizer/plan/planmain.c
index b2b362e84a5..2f52e694d13 100644
--- a/src/backend/optimizer/plan/planmain.c
+++ b/src/backend/optimizer/plan/planmain.c
@@ -14,7 +14,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.64 2001/03/22 03:59:37 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.65 2001/05/20 20:28:19 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -194,6 +194,7 @@ subplanner(Query *root,
* construction.
*/
root->base_rel_list = NIL;
+ root->other_rel_list = NIL;
root->join_rel_list = NIL;
root->equi_key_list = NIL;
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 0aba4808c16..fbed3d6d092 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.106 2001/05/07 00:43:21 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.107 2001/05/20 20:28:19 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -206,7 +206,8 @@ subquery_planner(Query *parse, double tuple_fraction)
* grouping_planner.
*/
if (parse->resultRelation &&
- (lst = expand_inherted_rtentry(parse, parse->resultRelation)) != NIL)
+ (lst = expand_inherted_rtentry(parse, parse->resultRelation, false))
+ != NIL)
plan = inheritance_planner(parse, lst);
else
plan = grouping_planner(parse, tuple_fraction);