aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/plan/createplan.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/plan/createplan.c')
-rw-r--r--src/backend/optimizer/plan/createplan.c132
1 files changed, 68 insertions, 64 deletions
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 64213cde7b1..281e3685160 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.69 1999/08/10 02:58:56 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.70 1999/08/12 04:32:53 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -49,10 +49,10 @@ 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 List *fix_indxqual_references(List *indexquals, IndexPath *index_path);
-static List *fix_one_indxqual_sublist(List *indexqual, IndexPath *index_path,
- Form_pg_index index);
-static Node *fix_one_indxqual_operand(Node *node, IndexPath *index_path,
- Form_pg_index index);
+static List *fix_indxqual_sublist(List *indexqual, IndexPath *index_path,
+ Form_pg_index index);
+static Node *fix_indxqual_operand(Node *node, IndexPath *index_path,
+ Form_pg_index index);
static Noname *make_noname(List *tlist, List *pathkeys, Oid *operators,
Plan *plan_node, int nonametype);
static IndexScan *make_indexscan(List *qptlist, List *qpqual, Index scanrelid,
@@ -345,8 +345,8 @@ create_indexscan_node(IndexPath *best_path,
/*
* The qpqual list must contain 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
+ * predicates in the indxqual are checked fully by the index, while
+ * for lossy indices the indxqual predicates need to be double-checked
* after the index fetches the best-guess tuples.
*
* Since the indexquals were generated from the restriction clauses
@@ -390,14 +390,17 @@ create_indexscan_node(IndexPath *best_path,
else
qpqual = NIL;
+ /* The executor needs a copy with the indexkey on the left of each clause
+ * and with index attrs substituted for table ones.
+ */
+ fixed_indxqual = fix_indxqual_references(indxqual, best_path);
+
/*
- * Fix opids in the completed indxqual.
+ * Fix opids in the completed indxquals.
* XXX this ought to only happen at final exit from the planner...
*/
indxqual = fix_opids(indxqual);
-
- /* The executor needs a copy with index attrs substituted for table ones */
- fixed_indxqual = fix_indxqual_references(indxqual, best_path);
+ fixed_indxqual = fix_opids(fixed_indxqual);
scan_node = make_indexscan(tlist,
qpqual,
@@ -445,11 +448,6 @@ create_nestloop_node(NestPath *best_path,
* checked as qpquals in the indexscan. We can still remove them
* from the nestloop's qpquals, but we gotta update the outer-rel
* vars in the indexscan's qpquals too...
- *
- * XXX as of 8/99, removal of redundant joinclauses doesn't work
- * all the time, since it will fail to recognize clauses that have
- * been commuted in the indexqual. I hope to make this problem go
- * away soon by not commuting indexqual clauses --- tgl.
*/
IndexScan *innerscan = (IndexScan *) inner_node;
List *indxqualorig = innerscan->indxqualorig;
@@ -459,7 +457,8 @@ create_nestloop_node(NestPath *best_path,
{
/* Remove redundant tests from my clauses, if possible.
* Note we must compare against indxqualorig not the "fixed"
- * indxqual (which has index attnos instead of relation attnos).
+ * indxqual (which has index attnos instead of relation attnos,
+ * and may have been commuted as well).
*/
if (length(indxqualorig) == 1) /* single indexscan? */
clauses = set_difference(clauses, lfirst(indxqualorig));
@@ -471,6 +470,7 @@ create_nestloop_node(NestPath *best_path,
innerscan->indxqual = join_references(innerscan->indxqual,
outer_tlist,
NIL);
+ /* fix the inner qpqual too, if it has join clauses */
if (NumRelids((Node *) inner_node->qual) > 1)
inner_node->qual = join_references(inner_node->qual,
outer_tlist,
@@ -638,8 +638,10 @@ create_hashjoin_node(HashPath *best_path,
/*
* fix_indxqual_references
- * Adjust indexqual clauses to refer to index attributes instead of the
- * attributes of the original relation.
+ * Adjust indexqual clauses to refer to index attributes instead of the
+ * attributes of the original relation. Also, commute clauses if needed
+ * to put the indexkey on the left. (Someday the executor might not need
+ * that, but for now it does.)
*
* This code used to be entirely bogus for multi-index scans. Now it keeps
* track of which index applies to each subgroup of index qual clauses...
@@ -671,9 +673,9 @@ fix_indxqual_references(List *indexquals, IndexPath *index_path)
index = (Form_pg_index) GETSTRUCT(indexTuple);
fixed_quals = lappend(fixed_quals,
- fix_one_indxqual_sublist(indexqual,
- index_path,
- index));
+ fix_indxqual_sublist(indexqual,
+ index_path,
+ index));
indexids = lnext(indexids);
}
@@ -683,41 +685,52 @@ fix_indxqual_references(List *indexquals, IndexPath *index_path)
/*
* Fix the sublist of indexquals to be used in a particular scan.
*
- * All that we need to do is change the left or right operand of the top-level
- * operator of each qual clause. Those are the only places that the index
- * attribute can appear in a valid indexqual. The other side of the indexqual
- * might be a complex function of joined rels; we do not need or want to
- * alter such an expression.
+ * For each qual clause, commute if needed to put the indexkey operand on the
+ * left, and then change its varno. We do not need to change the other side
+ * of the clause.
*/
static List *
-fix_one_indxqual_sublist(List *indexqual, IndexPath *index_path,
- Form_pg_index index)
+fix_indxqual_sublist(List *indexqual, IndexPath *index_path,
+ Form_pg_index index)
{
List *fixed_qual = NIL;
List *i;
foreach(i, indexqual)
{
- Node *clause = lfirst(i);
- List *args;
+ Expr *clause = (Expr *) lfirst(i);
+ int relid;
+ AttrNumber attno;
+ Datum constval;
+ int flag;
Expr *newclause;
- if (!is_opclause(clause))
- elog(ERROR, "fix_one_indxqual_sublist: indexqual clause is not opclause");
+ 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,
+ lfirsti(index_path->path.parent->relids),
+ &relid, &attno, &constval, &flag);
+
+ /* Copy enough structure to allow commuting and replacing an operand
+ * without changing original clause.
+ */
+ newclause = make_clause(clause->opType, clause->oper,
+ listCopy(clause->args));
- /* Copy enough structure to allow replacing left or right operand */
- args = listCopy(((Expr *) clause)->args);
- newclause = make_clause(((Expr *) clause)->opType,
- ((Expr *) clause)->oper,
- args);
+ /* If the indexkey is on the right, commute the clause. */
+ if ((flag & SEL_RIGHT) == 0)
+ CommuteClause(newclause);
- lfirst(args) = fix_one_indxqual_operand(lfirst(args),
- index_path,
- index);
- if (lnext(args))
- lfirst(lnext(args)) = fix_one_indxqual_operand(lfirst(lnext(args)),
- index_path,
- index);
+ /* Now, change the indexkey operand as needed. */
+ lfirst(newclause->args) = fix_indxqual_operand(lfirst(newclause->args),
+ index_path,
+ index);
fixed_qual = lappend(fixed_qual, newclause);
}
@@ -725,11 +738,9 @@ fix_one_indxqual_sublist(List *indexqual, IndexPath *index_path,
}
static Node *
-fix_one_indxqual_operand(Node *node, IndexPath *index_path,
- Form_pg_index index)
+fix_indxqual_operand(Node *node, IndexPath *index_path,
+ Form_pg_index index)
{
- if (node == NULL)
- return NULL;
if (IsA(node, Var))
{
if (((Var *) node)->varno == lfirsti(index_path->path.parent->relids))
@@ -746,22 +757,17 @@ fix_one_indxqual_operand(Node *node, IndexPath *index_path,
return newnode;
}
}
- /*
- * We should never see a reference to an attribute of the indexed
- * relation that is not one of the indexed attributes.
- */
- elog(ERROR, "fix_one_indxqual_operand: failed to find index pos of index attribute");
}
/*
- * The Var is not part of the indexed relation, leave it alone.
- * This would normally only occur when looking at the other side
- * of a join indexqual.
+ * Oops, this Var isn't the indexkey!
*/
- return node;
+ elog(ERROR, "fix_indxqual_operand: var is not index attribute");
}
/*
- * Note: currently, there is no need for us to do anything here for
+ * Else, it must be a func expression representing a functional index.
+ *
+ * Currently, there is no need for us to do anything here for
* functional indexes. If nodeIndexscan.c sees a func clause as the left
* or right-hand toplevel operand of an indexqual, it assumes that that is
* a reference to the functional index's value and makes the appropriate
@@ -789,7 +795,7 @@ switch_outer(List *clauses)
foreach(i, clauses)
{
- Expr *clause = lfirst(i);
+ Expr *clause = (Expr *) lfirst(i);
Node *op;
Assert(is_opclause((Node *) clause));
@@ -808,11 +814,9 @@ switch_outer(List *clauses)
Expr *temp;
temp = make_clause(clause->opType, clause->oper,
- lcons(get_leftop(clause),
- lcons(get_rightop(clause),
- NIL)));
+ listCopy(clause->args));
/* Commute it --- note this modifies the temp node in-place. */
- CommuteClause((Node *) temp);
+ CommuteClause(temp);
t_list = lappend(t_list, temp);
}
else