/*------------------------------------------------------------------------- * * joininfo.c * JoinInfo node manipulation routines * * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $PostgreSQL: pgsql/src/backend/optimizer/util/joininfo.c,v 1.37 2003/11/29 19:51:51 pgsql Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" #include "optimizer/joininfo.h" #include "optimizer/pathnode.h" /* * 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. * * Returns a joininfo node, or NULL. */ JoinInfo * find_joininfo_node(RelOptInfo *this_rel, Relids join_relids) { List *i; foreach(i, this_rel->joininfo) { JoinInfo *joininfo = (JoinInfo *) lfirst(i); if (bms_equal(join_relids, joininfo->unjoined_relids)) return joininfo; } return NULL; } /* * make_joininfo_node * Find the joininfo node within a relation entry corresponding * 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 * field if the desired one can't be found. * * Returns a joininfo node. */ JoinInfo * make_joininfo_node(RelOptInfo *this_rel, Relids join_relids) { JoinInfo *joininfo = find_joininfo_node(this_rel, join_relids); if (joininfo == NULL) { joininfo = makeNode(JoinInfo); joininfo->unjoined_relids = join_relids; joininfo->jinfo_restrictinfo = NIL; this_rel->joininfo = lcons(joininfo, this_rel->joininfo); } return joininfo; } /* * 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) { Relids tmprelids; int cur_relid; /* For every relid, find the joininfo, and add the proper join entries */ tmprelids = bms_copy(join_relids); while ((cur_relid = bms_first_member(tmprelids)) >= 0) { Relids unjoined_relids; JoinInfo *joininfo; /* Get the relids not equal to the current relid */ unjoined_relids = bms_copy(join_relids); unjoined_relids = bms_del_member(unjoined_relids, cur_relid); Assert(!bms_is_empty(unjoined_relids)); /* * 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); /* * Can't bms_free(unjoined_relids) because new joininfo node may * link to it. We could avoid leaking memory by doing bms_copy() * in make_joininfo_node, but for now speed seems better. */ } bms_free(tmprelids); } /* * 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) { Relids tmprelids; int cur_relid; /* For every relid, find the joininfo */ tmprelids = bms_copy(join_relids); while ((cur_relid = bms_first_member(tmprelids)) >= 0) { Relids unjoined_relids; JoinInfo *joininfo; /* Get the relids not equal to the current relid */ unjoined_relids = bms_copy(join_relids); unjoined_relids = bms_del_member(unjoined_relids, cur_relid); Assert(!bms_is_empty(unjoined_relids)); /* * 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); bms_free(unjoined_relids); } bms_free(tmprelids); }