aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/plan/createplan.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>1999-08-12 04:32:54 +0000
committerTom Lane <tgl@sss.pgh.pa.us>1999-08-12 04:32:54 +0000
commit8f9f6e51a8ad47da466a62be66474ef5358403c0 (patch)
treecb7c1f434efcf5cc79dd711496e5c0ab12444127 /src/backend/optimizer/plan/createplan.c
parentaae034d28c98eee5fbd37d27234d3e825c53b91e (diff)
downloadpostgresql-8f9f6e51a8ad47da466a62be66474ef5358403c0.tar.gz
postgresql-8f9f6e51a8ad47da466a62be66474ef5358403c0.zip
Clean up optimizer's handling of indexscan quals that need to be
commuted (ie, the index var appears on the right). These are now handled the same way as merge and hash join quals that need to be commuted: the actual reversing of the clause only happens if we actually choose the path and generate a plan from it. Furthermore, the clause is only reversed in the 'indexqual' field of the plan, not in the 'indxqualorig' field. This allows the clause to still be recognized and removed from qpquals of upper level join plans. Also, simplify and generalize match_clause_to_indexkey; now it recognizes binary-compatible indexes for join as well as restriction clauses.
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