mirror of
https://github.com/postgres/postgres.git
synced 2025-04-22 23:02:54 +03:00
Remove 'restrictinfojoinid' field from RestrictInfo nodes.
The only place it was being used was as temporary storage in indxpath.c, and the logic was wrong: the same restrictinfo node could get chosen to carry the info for two different joins. Right fix is to return a second list of unjoined-relids parallel to the list of clause groups.
This commit is contained in:
parent
ac4913a0dd
commit
8ae29a1d40
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.87 1999/07/24 23:21:06 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.88 1999/07/25 17:53:27 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -1321,7 +1321,6 @@ _copyRestrictInfo(RestrictInfo *from)
|
|||||||
Node_Copy(from, newnode, indexids);
|
Node_Copy(from, newnode, indexids);
|
||||||
Node_Copy(from, newnode, mergejoinorder);
|
Node_Copy(from, newnode, mergejoinorder);
|
||||||
newnode->hashjoinoperator = from->hashjoinoperator;
|
newnode->hashjoinoperator = from->hashjoinoperator;
|
||||||
newnode->restrictinfojoinid = listCopy(from->restrictinfojoinid);
|
|
||||||
|
|
||||||
return newnode;
|
return newnode;
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/nodes/Attic/freefuncs.c,v 1.22 1999/07/17 20:17:06 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/nodes/Attic/freefuncs.c,v 1.23 1999/07/25 17:53:27 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -929,7 +929,6 @@ _freeRestrictInfo(RestrictInfo *node)
|
|||||||
freeObject(node->clause);
|
freeObject(node->clause);
|
||||||
freeObject(node->indexids);
|
freeObject(node->indexids);
|
||||||
freeObject(node->mergejoinorder);
|
freeObject(node->mergejoinorder);
|
||||||
freeList(node->restrictinfojoinid);
|
|
||||||
|
|
||||||
pfree(node);
|
pfree(node);
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.63 1999/07/24 23:21:09 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.64 1999/07/25 17:53:27 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -55,10 +55,11 @@ static bool one_pred_test(Expr *predicate, List *restrictinfo_list);
|
|||||||
static bool one_pred_clause_expr_test(Expr *predicate, Node *clause);
|
static bool one_pred_clause_expr_test(Expr *predicate, Node *clause);
|
||||||
static bool one_pred_clause_test(Expr *predicate, Node *clause);
|
static bool one_pred_clause_test(Expr *predicate, Node *clause);
|
||||||
static bool clause_pred_clause_test(Expr *predicate, Node *clause);
|
static bool clause_pred_clause_test(Expr *predicate, Node *clause);
|
||||||
static List *indexable_joinclauses(RelOptInfo *rel, RelOptInfo *index,
|
static void indexable_joinclauses(RelOptInfo *rel, RelOptInfo *index,
|
||||||
List *joininfo_list, List *restrictinfo_list);
|
List *joininfo_list, List *restrictinfo_list,
|
||||||
static List *index_innerjoin(Query *root, RelOptInfo *rel,
|
List **clausegroups, List **outerrelids);
|
||||||
List *clausegroup_list, RelOptInfo *index);
|
static List *index_innerjoin(Query *root, RelOptInfo *rel, RelOptInfo *index,
|
||||||
|
List *clausegroup_list, List *outerrelids_list);
|
||||||
static List *create_index_path_group(Query *root, RelOptInfo *rel, RelOptInfo *index,
|
static List *create_index_path_group(Query *root, RelOptInfo *rel, RelOptInfo *index,
|
||||||
List *clausegroup_list, bool join);
|
List *clausegroup_list, bool join);
|
||||||
static bool match_index_to_operand(int indexkey, Expr *operand,
|
static bool match_index_to_operand(int indexkey, Expr *operand,
|
||||||
@ -99,6 +100,7 @@ create_index_paths(Query *root,
|
|||||||
RelOptInfo *index = (RelOptInfo *) lfirst(ilist);
|
RelOptInfo *index = (RelOptInfo *) lfirst(ilist);
|
||||||
List *scanclausegroups;
|
List *scanclausegroups;
|
||||||
List *joinclausegroups;
|
List *joinclausegroups;
|
||||||
|
List *joinouterrelids;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this is a partial index, we can only use it if it passes
|
* If this is a partial index, we can only use it if it passes
|
||||||
@ -161,9 +163,10 @@ create_index_paths(Query *root,
|
|||||||
* mergejoin, or if the index can possibly be used for scanning
|
* mergejoin, or if the index can possibly be used for scanning
|
||||||
* the inner relation of a nestloop join.
|
* the inner relation of a nestloop join.
|
||||||
*/
|
*/
|
||||||
joinclausegroups = indexable_joinclauses(rel, index,
|
indexable_joinclauses(rel, index,
|
||||||
joininfo_list,
|
joininfo_list, restrictinfo_list,
|
||||||
restrictinfo_list);
|
&joinclausegroups,
|
||||||
|
&joinouterrelids);
|
||||||
|
|
||||||
if (joinclausegroups != NIL)
|
if (joinclausegroups != NIL)
|
||||||
{
|
{
|
||||||
@ -174,9 +177,9 @@ create_index_paths(Query *root,
|
|||||||
joinclausegroups,
|
joinclausegroups,
|
||||||
true));
|
true));
|
||||||
rel->innerjoin = nconc(rel->innerjoin,
|
rel->innerjoin = nconc(rel->innerjoin,
|
||||||
index_innerjoin(root, rel,
|
index_innerjoin(root, rel, index,
|
||||||
joinclausegroups,
|
joinclausegroups,
|
||||||
index));
|
joinouterrelids));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -326,19 +329,23 @@ match_index_orclause(RelOptInfo *rel,
|
|||||||
* 'index' is a index on 'rel'.
|
* 'index' is a index on 'rel'.
|
||||||
* 'indexkeys' are the index keys to be matched.
|
* 'indexkeys' are the index keys to be matched.
|
||||||
* 'classes' are the classes of the index operators on those keys.
|
* 'classes' are the classes of the index operators on those keys.
|
||||||
* 'clauses' is the list of available restriction clauses for 'rel'.
|
* 'restrictinfo_list' is the list of available restriction clauses for 'rel'.
|
||||||
*
|
*
|
||||||
* Returns NIL if no clauses can be used with this index.
|
* Returns NIL if no clauses can be used with this index.
|
||||||
* Otherwise, a list containing a single sublist is returned (indicating
|
* Otherwise, a list containing a single sublist is returned (indicating
|
||||||
* to create_index_path_group() that a single IndexPath should be created).
|
* to create_index_path_group() that a single IndexPath should be created).
|
||||||
* The sublist is ordered by index key, and contains sublists of clauses
|
* The sublist contains the RestrictInfo nodes for all clauses that can be
|
||||||
* that can be used with that index key.
|
* used with this index.
|
||||||
|
*
|
||||||
|
* The sublist is ordered by index key (but as far as I can tell, this is
|
||||||
|
* an implementation artifact of this routine, and is not depended on by
|
||||||
|
* any user of the returned list --- tgl 7/99).
|
||||||
*
|
*
|
||||||
* Note that in a multi-key index, we stop if we find a key that cannot be
|
* Note that in a multi-key index, we stop if we find a key that cannot be
|
||||||
* used with any clause. For example, given an index on (A,B,C), we might
|
* used with any clause. For example, given an index on (A,B,C), we might
|
||||||
* return (((C1 C2) (C3 C4))) if we find that clauses C1 and C2 use column A,
|
* return ((C1 C2 C3 C4)) if we find that clauses C1 and C2 use column A,
|
||||||
* clauses C3 and C4 use column B, and no clauses use column C. But if no
|
* clauses C3 and C4 use column B, and no clauses use column C. But if no
|
||||||
* clauses match B we will return (((C1 C2))), whether or not there are
|
* clauses match B we will return ((C1 C2)), whether or not there are
|
||||||
* clauses matching column C, because the executor couldn't use them anyway.
|
* clauses matching column C, because the executor couldn't use them anyway.
|
||||||
*/
|
*/
|
||||||
static List *
|
static List *
|
||||||
@ -1108,21 +1115,35 @@ clause_pred_clause_test(Expr *predicate, Node *clause)
|
|||||||
* Finds all groups of join clauses from among 'joininfo_list' that can
|
* Finds all groups of join clauses from among 'joininfo_list' that can
|
||||||
* be used in conjunction with 'index'.
|
* be used in conjunction with 'index'.
|
||||||
*
|
*
|
||||||
* The first clause in the group is marked as having the other relation
|
* Each clause group comes from a single joininfo node plus the current
|
||||||
* in the join clause as its outer join relation.
|
* rel's restrictinfo list. Therefore, every clause in the group references
|
||||||
|
* the current rel plus the same set of other rels (except for the restrict
|
||||||
|
* clauses, which only reference the current rel). Therefore, this set
|
||||||
|
* of clauses could be used as an indexqual if the relation is scanned
|
||||||
|
* as the inner side of a nestloop join when the outer side contains
|
||||||
|
* (at least) all those "other rels".
|
||||||
*
|
*
|
||||||
* Returns a list of these clause groups.
|
* XXX Actually, given that we are considering a join that requires an
|
||||||
|
* outer rel set (A,B,C), we should use all qual clauses that reference
|
||||||
|
* any subset of these rels, not just the full set or none. This is
|
||||||
|
* doable with a doubly nested loop over joininfo_list; is it worth it?
|
||||||
*
|
*
|
||||||
* Added: restrictinfo_list - list of restriction RestrictInfos. It's to
|
* Returns two parallel lists of the same length: the clause groups,
|
||||||
* support multi-column indices in joins and for cases
|
* and the required outer rel set for each one.
|
||||||
* when a key is in both join & restriction clauses. - vadim 03/18/97
|
|
||||||
*
|
*
|
||||||
|
* 'rel' is the relation for which 'index' is defined
|
||||||
|
* 'joininfo_list' is the list of JoinInfo nodes for 'rel'
|
||||||
|
* 'restrictinfo_list' is the list of restriction clauses for 'rel'
|
||||||
|
* '*clausegroups' receives a list of clause sublists
|
||||||
|
* '*outerrelids' receives a list of relid lists
|
||||||
*/
|
*/
|
||||||
static List *
|
static void
|
||||||
indexable_joinclauses(RelOptInfo *rel, RelOptInfo *index,
|
indexable_joinclauses(RelOptInfo *rel, RelOptInfo *index,
|
||||||
List *joininfo_list, List *restrictinfo_list)
|
List *joininfo_list, List *restrictinfo_list,
|
||||||
|
List **clausegroups, List **outerrelids)
|
||||||
{
|
{
|
||||||
List *cg_list = NIL;
|
List *cg_list = NIL;
|
||||||
|
List *relid_list = NIL;
|
||||||
List *i;
|
List *i;
|
||||||
|
|
||||||
foreach(i, joininfo_list)
|
foreach(i, joininfo_list)
|
||||||
@ -1139,15 +1160,32 @@ indexable_joinclauses(RelOptInfo *rel, RelOptInfo *index,
|
|||||||
joininfo->jinfo_restrictinfo,
|
joininfo->jinfo_restrictinfo,
|
||||||
restrictinfo_list);
|
restrictinfo_list);
|
||||||
|
|
||||||
|
/*----------
|
||||||
|
* This code knows that group_clauses_by_ikey_for_joins() returns
|
||||||
|
* either NIL or a list containing a single sublist of clauses.
|
||||||
|
* The line
|
||||||
|
* cg_list = nconc(cg_list, clausegroups);
|
||||||
|
* is better read as
|
||||||
|
* cg_list = lappend(cg_list, lfirst(clausegroups));
|
||||||
|
* That is, we are appending the only sublist returned by
|
||||||
|
* group_clauses_by_ikey_for_joins() to the list of clause sublists
|
||||||
|
* that this routine will return. By using nconc() we recycle
|
||||||
|
* a cons cell that would be wasted ... whoever wrote this code
|
||||||
|
* was too clever by half...
|
||||||
|
*----------
|
||||||
|
*/
|
||||||
if (clausegroups != NIL)
|
if (clausegroups != NIL)
|
||||||
{
|
{
|
||||||
List *clauses = lfirst(clausegroups);
|
|
||||||
|
|
||||||
((RestrictInfo *) lfirst(clauses))->restrictinfojoinid = joininfo->unjoined_relids;
|
|
||||||
cg_list = nconc(cg_list, clausegroups);
|
cg_list = nconc(cg_list, clausegroups);
|
||||||
|
relid_list = lappend(relid_list, joininfo->unjoined_relids);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return cg_list;
|
|
||||||
|
/* Make sure above clever code didn't screw up */
|
||||||
|
Assert(length(cg_list) == length(relid_list));
|
||||||
|
|
||||||
|
*clausegroups = cg_list;
|
||||||
|
*outerrelids = relid_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@ -1159,15 +1197,17 @@ indexable_joinclauses(RelOptInfo *rel, RelOptInfo *index,
|
|||||||
* Creates index path nodes corresponding to paths to be used as inner
|
* Creates index path nodes corresponding to paths to be used as inner
|
||||||
* relations in nestloop joins.
|
* relations in nestloop joins.
|
||||||
*
|
*
|
||||||
* 'clausegroup-list' is a list of list of restrictinfo nodes which can use
|
* 'rel' is the relation for which 'index' is defined
|
||||||
|
* 'clausegroup_list' is a list of lists of restrictinfo nodes which can use
|
||||||
* 'index' on their inner relation.
|
* 'index' on their inner relation.
|
||||||
|
* 'outerrelids_list' is a list of the required outer rels for each group
|
||||||
|
* of join clauses.
|
||||||
*
|
*
|
||||||
* Returns a list of index pathnodes.
|
* Returns a list of index pathnodes.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
static List *
|
static List *
|
||||||
index_innerjoin(Query *root, RelOptInfo *rel, List *clausegroup_list,
|
index_innerjoin(Query *root, RelOptInfo *rel, RelOptInfo *index,
|
||||||
RelOptInfo *index)
|
List *clausegroup_list, List *outerrelids_list)
|
||||||
{
|
{
|
||||||
List *path_list = NIL;
|
List *path_list = NIL;
|
||||||
List *i;
|
List *i;
|
||||||
@ -1211,7 +1251,8 @@ index_innerjoin(Query *root, RelOptInfo *rel, List *clausegroup_list,
|
|||||||
pathnode->indexkeys = index->indexkeys;
|
pathnode->indexkeys = index->indexkeys;
|
||||||
pathnode->indexqual = lcons(get_actual_clauses(clausegroup), NIL);
|
pathnode->indexqual = lcons(get_actual_clauses(clausegroup), NIL);
|
||||||
|
|
||||||
pathnode->path.joinid = ((RestrictInfo *) lfirst(clausegroup))->restrictinfojoinid;
|
/* joinid saves the rels needed on the outer side of the join */
|
||||||
|
pathnode->path.joinid = lfirst(outerrelids_list);
|
||||||
|
|
||||||
pathnode->path.path_cost = cost_index((Oid) lfirsti(index->relids),
|
pathnode->path.path_cost = cost_index((Oid) lfirsti(index->relids),
|
||||||
(int) temp_pages,
|
(int) temp_pages,
|
||||||
@ -1235,6 +1276,7 @@ index_innerjoin(Query *root, RelOptInfo *rel, List *clausegroup_list,
|
|||||||
((Path *) pathnode)->path_cost += xfunc_get_path_cost((Path *) pathnode);
|
((Path *) pathnode)->path_cost += xfunc_get_path_cost((Path *) pathnode);
|
||||||
#endif
|
#endif
|
||||||
path_list = lappend(path_list, pathnode);
|
path_list = lappend(path_list, pathnode);
|
||||||
|
outerrelids_list = lnext(outerrelids_list);
|
||||||
}
|
}
|
||||||
return path_list;
|
return path_list;
|
||||||
}
|
}
|
||||||
@ -1245,7 +1287,7 @@ index_innerjoin(Query *root, RelOptInfo *rel, List *clausegroup_list,
|
|||||||
* (restriction or join) that can be used in conjunction with an index.
|
* (restriction or join) that can be used in conjunction with an index.
|
||||||
*
|
*
|
||||||
* 'rel' is the relation for which 'index' is defined
|
* 'rel' is the relation for which 'index' is defined
|
||||||
* 'clausegroup-list' is the list of clause groups (lists of restrictinfo
|
* 'clausegroup_list' is the list of clause groups (lists of restrictinfo
|
||||||
* nodes) grouped by mergejoinorder
|
* nodes) grouped by mergejoinorder
|
||||||
* 'join' is a flag indicating whether or not the clauses are join
|
* 'join' is a flag indicating whether or not the clauses are join
|
||||||
* clauses
|
* clauses
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 1994, Regents of the University of California
|
* Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: relation.h,v 1.35 1999/07/24 23:21:04 tgl Exp $
|
* $Id: relation.h,v 1.36 1999/07/25 17:53:26 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -242,7 +242,6 @@ typedef struct RestrictInfo
|
|||||||
|
|
||||||
/* hashjoin only */
|
/* hashjoin only */
|
||||||
Oid hashjoinoperator;
|
Oid hashjoinoperator;
|
||||||
Relids restrictinfojoinid;
|
|
||||||
} RestrictInfo;
|
} RestrictInfo;
|
||||||
|
|
||||||
typedef struct JoinMethod
|
typedef struct JoinMethod
|
||||||
|
Loading…
x
Reference in New Issue
Block a user