1996-07-09 08:22:35 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
1999-02-14 00:22:53 +01:00
|
|
|
* joininfo.c
|
1997-09-07 07:04:48 +02:00
|
|
|
* JoinInfo node manipulation routines
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2002-06-20 22:29:54 +02:00
|
|
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
2000-01-26 06:58:53 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2003-02-08 21:20:55 +01:00
|
|
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/joininfo.c,v 1.34 2003/02/08 20:20:55 tgl Exp $
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
#include "postgres.h"
|
|
|
|
|
1999-07-16 07:00:38 +02:00
|
|
|
#include "optimizer/joininfo.h"
|
2003-01-24 04:58:44 +01:00
|
|
|
#include "optimizer/pathnode.h"
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/*
|
2003-01-20 19:55:07 +01:00
|
|
|
* find_joininfo_node
|
|
|
|
* Find the joininfo node within a relation entry corresponding
|
|
|
|
* to a join between 'this_rel' and the relations in 'join_relids'.
|
|
|
|
* If there is no such node, return NULL.
|
1997-09-07 07:04:48 +02:00
|
|
|
*
|
2003-01-20 19:55:07 +01:00
|
|
|
* Returns a joininfo node, or NULL.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2003-01-20 19:55:07 +01:00
|
|
|
JoinInfo *
|
|
|
|
find_joininfo_node(RelOptInfo *this_rel, Relids join_relids)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1999-05-25 18:15:34 +02:00
|
|
|
List *i;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2003-01-20 19:55:07 +01:00
|
|
|
foreach(i, this_rel->joininfo)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
1999-05-25 18:15:34 +02:00
|
|
|
JoinInfo *joininfo = (JoinInfo *) lfirst(i);
|
1999-02-18 01:49:48 +01:00
|
|
|
|
2003-02-08 21:20:55 +01:00
|
|
|
if (bms_equal(join_relids, joininfo->unjoined_relids))
|
1999-02-18 01:49:48 +01:00
|
|
|
return joininfo;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1999-02-18 01:49:48 +01:00
|
|
|
return NULL;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/*
|
2003-01-20 19:55:07 +01:00
|
|
|
* make_joininfo_node
|
1997-09-07 07:04:48 +02:00
|
|
|
* Find the joininfo node within a relation entry corresponding
|
1999-08-16 04:17:58 +02:00
|
|
|
* to a join between 'this_rel' and the relations in 'join_relids'.
|
|
|
|
* A new node is created and added to the relation entry's joininfo
|
1997-09-07 07:04:48 +02:00
|
|
|
* field if the desired one can't be found.
|
|
|
|
*
|
1996-07-09 08:22:35 +02:00
|
|
|
* Returns a joininfo node.
|
|
|
|
*/
|
2001-10-25 07:50:21 +02:00
|
|
|
JoinInfo *
|
2003-01-20 19:55:07 +01:00
|
|
|
make_joininfo_node(RelOptInfo *this_rel, Relids join_relids)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2003-01-20 19:55:07 +01:00
|
|
|
JoinInfo *joininfo = find_joininfo_node(this_rel, join_relids);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
if (joininfo == NULL)
|
|
|
|
{
|
1998-09-01 05:29:17 +02:00
|
|
|
joininfo = makeNode(JoinInfo);
|
1999-02-18 01:49:48 +01:00
|
|
|
joininfo->unjoined_relids = join_relids;
|
1999-02-03 21:15:53 +01:00
|
|
|
joininfo->jinfo_restrictinfo = NIL;
|
1997-09-07 07:04:48 +02:00
|
|
|
this_rel->joininfo = lcons(joininfo, this_rel->joininfo);
|
|
|
|
}
|
1998-09-01 05:29:17 +02:00
|
|
|
return joininfo;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
2003-01-24 04:58:44 +01:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* add_join_clause_to_rels
|
|
|
|
* For every relation participating in a join clause, add 'restrictinfo' to
|
|
|
|
* the appropriate joininfo list (creating a new list and adding it to the
|
|
|
|
* appropriate rel node if necessary).
|
|
|
|
*
|
|
|
|
* Note that the same copy of the restrictinfo node is linked to by all the
|
|
|
|
* lists it is in. This allows us to exploit caching of information about
|
|
|
|
* the restriction clause (but we must be careful that the information does
|
|
|
|
* not depend on context).
|
|
|
|
*
|
|
|
|
* 'restrictinfo' describes the join clause
|
|
|
|
* 'join_relids' is the list of relations participating in the join clause
|
|
|
|
* (there must be more than one)
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
add_join_clause_to_rels(Query *root,
|
|
|
|
RestrictInfo *restrictinfo,
|
|
|
|
Relids join_relids)
|
|
|
|
{
|
2003-02-08 21:20:55 +01:00
|
|
|
Relids tmprelids;
|
|
|
|
int cur_relid;
|
2003-01-24 04:58:44 +01:00
|
|
|
|
|
|
|
/* For every relid, find the joininfo, and add the proper join entries */
|
2003-02-08 21:20:55 +01:00
|
|
|
tmprelids = bms_copy(join_relids);
|
|
|
|
while ((cur_relid = bms_first_member(tmprelids)) >= 0)
|
2003-01-24 04:58:44 +01:00
|
|
|
{
|
2003-02-08 21:20:55 +01:00
|
|
|
Relids unjoined_relids;
|
2003-01-24 04:58:44 +01:00
|
|
|
JoinInfo *joininfo;
|
|
|
|
|
|
|
|
/* Get the relids not equal to the current relid */
|
2003-02-08 21:20:55 +01:00
|
|
|
unjoined_relids = bms_copy(join_relids);
|
|
|
|
unjoined_relids = bms_del_member(unjoined_relids, cur_relid);
|
|
|
|
Assert(!bms_is_empty(unjoined_relids));
|
2003-01-24 04:58:44 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Find or make the joininfo node for this combination of rels,
|
|
|
|
* and add the restrictinfo node to it.
|
|
|
|
*/
|
|
|
|
joininfo = make_joininfo_node(find_base_rel(root, cur_relid),
|
|
|
|
unjoined_relids);
|
|
|
|
joininfo->jinfo_restrictinfo = lappend(joininfo->jinfo_restrictinfo,
|
|
|
|
restrictinfo);
|
|
|
|
/*
|
2003-02-08 21:20:55 +01:00
|
|
|
* Can't bms_free(unjoined_relids) because new joininfo node may
|
|
|
|
* link to it. We could avoid leaking memory by doing bms_copy()
|
2003-01-24 04:58:44 +01:00
|
|
|
* in make_joininfo_node, but for now speed seems better.
|
|
|
|
*/
|
|
|
|
}
|
2003-02-08 21:20:55 +01:00
|
|
|
bms_free(tmprelids);
|
2003-01-24 04:58:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* remove_join_clause_from_rels
|
|
|
|
* Delete 'restrictinfo' from all the joininfo lists it is in
|
|
|
|
*
|
|
|
|
* This reverses the effect of add_join_clause_to_rels. It's used when we
|
|
|
|
* discover that a join clause is redundant.
|
|
|
|
*
|
|
|
|
* 'restrictinfo' describes the join clause
|
|
|
|
* 'join_relids' is the list of relations participating in the join clause
|
|
|
|
* (there must be more than one)
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
remove_join_clause_from_rels(Query *root,
|
|
|
|
RestrictInfo *restrictinfo,
|
|
|
|
Relids join_relids)
|
|
|
|
{
|
2003-02-08 21:20:55 +01:00
|
|
|
Relids tmprelids;
|
|
|
|
int cur_relid;
|
2003-01-24 04:58:44 +01:00
|
|
|
|
|
|
|
/* For every relid, find the joininfo */
|
2003-02-08 21:20:55 +01:00
|
|
|
tmprelids = bms_copy(join_relids);
|
|
|
|
while ((cur_relid = bms_first_member(tmprelids)) >= 0)
|
2003-01-24 04:58:44 +01:00
|
|
|
{
|
2003-02-08 21:20:55 +01:00
|
|
|
Relids unjoined_relids;
|
2003-01-24 04:58:44 +01:00
|
|
|
JoinInfo *joininfo;
|
|
|
|
|
|
|
|
/* Get the relids not equal to the current relid */
|
2003-02-08 21:20:55 +01:00
|
|
|
unjoined_relids = bms_copy(join_relids);
|
|
|
|
unjoined_relids = bms_del_member(unjoined_relids, cur_relid);
|
|
|
|
Assert(!bms_is_empty(unjoined_relids));
|
2003-01-24 04:58:44 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Find the joininfo node for this combination of rels; it should
|
|
|
|
* exist already, if add_join_clause_to_rels was called.
|
|
|
|
*/
|
|
|
|
joininfo = find_joininfo_node(find_base_rel(root, cur_relid),
|
|
|
|
unjoined_relids);
|
|
|
|
Assert(joininfo);
|
|
|
|
/*
|
|
|
|
* Remove the restrictinfo from the list. Pointer comparison
|
|
|
|
* is sufficient.
|
|
|
|
*/
|
|
|
|
Assert(ptrMember(restrictinfo, joininfo->jinfo_restrictinfo));
|
|
|
|
joininfo->jinfo_restrictinfo = lremove(restrictinfo,
|
|
|
|
joininfo->jinfo_restrictinfo);
|
2003-02-08 21:20:55 +01:00
|
|
|
bms_free(unjoined_relids);
|
2003-01-24 04:58:44 +01:00
|
|
|
}
|
2003-02-08 21:20:55 +01:00
|
|
|
bms_free(tmprelids);
|
2003-01-24 04:58:44 +01:00
|
|
|
}
|