Commit c15a4c2a authored by Tom Lane's avatar Tom Lane

Replace planner's representation of relation sets, per pghackers discussion.

Instead of Lists of integers, we now store variable-length bitmap sets.
This should be faster as well as less error-prone.
parent 893678ed
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/Attic/indexcost.sgml,v 2.15 2003/01/28 22:13:24 tgl Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/Attic/indexcost.sgml,v 2.16 2003/02/08 20:20:53 tgl Exp $
-->
<chapter id="indexcost">
......@@ -205,8 +205,7 @@ amcostestimate (Query *root,
<programlisting>
*indexSelectivity = clauselist_selectivity(root, indexQuals,
lfirsti(rel->relids),
JOIN_INNER);
rel->relid, JOIN_INNER);
</programlisting>
</para>
</step>
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994-5, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.100 2003/02/02 23:46:38 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.101 2003/02/08 20:20:53 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -775,12 +775,15 @@ show_scan_qual(List *qual, bool is_or_qual, const char *qlabel,
*/
if (outer_plan)
{
if (intMember(OUTER, pull_varnos(node)))
Relids varnos = pull_varnos(node);
if (bms_is_member(OUTER, varnos))
outercontext = deparse_context_for_subplan("outer",
outer_plan->targetlist,
es->rtable);
else
outercontext = NULL;
bms_free(varnos);
}
else
outercontext = NULL;
......@@ -857,6 +860,7 @@ show_sort_keys(List *tlist, int nkeys, const char *qlabel,
int keyno;
List *tl;
char *exprstr;
Relids varnos;
int i;
if (nkeys <= 0)
......@@ -874,7 +878,8 @@ show_sort_keys(List *tlist, int nkeys, const char *qlabel,
* there are Vars with zero varno, use the tlist itself to determine
* their names.
*/
if (intMember(0, pull_varnos((Node *) tlist)))
varnos = pull_varnos((Node *) tlist);
if (bms_is_member(0, varnos))
{
Node *outercontext;
......@@ -893,6 +898,7 @@ show_sort_keys(List *tlist, int nkeys, const char *qlabel,
es->rtable);
useprefix = length(es->rtable) > 1;
}
bms_free(varnos);
for (keyno = 1; keyno <= nkeys; keyno++)
{
......
......@@ -4,7 +4,7 @@
# Makefile for backend/nodes
#
# IDENTIFICATION
# $Header: /cvsroot/pgsql/src/backend/nodes/Makefile,v 1.13 2000/08/31 16:10:06 petere Exp $
# $Header: /cvsroot/pgsql/src/backend/nodes/Makefile,v 1.14 2003/02/08 20:20:53 tgl Exp $
#
#-------------------------------------------------------------------------
......@@ -12,7 +12,7 @@ subdir = src/backend/nodes
top_builddir = ../../..
include $(top_builddir)/src/Makefile.global
OBJS = nodeFuncs.o nodes.o list.o \
OBJS = nodeFuncs.o nodes.o list.o bitmapset.o \
copyfuncs.o equalfuncs.o makefuncs.o \
outfuncs.o readfuncs.o print.o read.o
......
This diff is collapsed.
......@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.239 2003/02/03 21:15:43 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.240 2003/02/08 20:20:53 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -47,6 +47,10 @@
#define COPY_INTLIST_FIELD(fldname) \
(newnode->fldname = listCopy(from->fldname))
/* Copy a field that is a pointer to a Bitmapset */
#define COPY_BITMAPSET_FIELD(fldname) \
(newnode->fldname = bms_copy(from->fldname))
/* Copy a field that is a pointer to a C string, or perhaps NULL */
#define COPY_STRING_FIELD(fldname) \
(newnode->fldname = from->fldname ? pstrdup(from->fldname) : (char *) NULL)
......@@ -1058,8 +1062,8 @@ _copyRestrictInfo(RestrictInfo *from)
COPY_NODE_FIELD(subclauseindices); /* XXX probably bad */
COPY_SCALAR_FIELD(eval_cost);
COPY_SCALAR_FIELD(this_selec);
COPY_INTLIST_FIELD(left_relids);
COPY_INTLIST_FIELD(right_relids);
COPY_BITMAPSET_FIELD(left_relids);
COPY_BITMAPSET_FIELD(right_relids);
COPY_SCALAR_FIELD(mergejoinoperator);
COPY_SCALAR_FIELD(left_sortop);
COPY_SCALAR_FIELD(right_sortop);
......@@ -1088,7 +1092,7 @@ _copyJoinInfo(JoinInfo *from)
{
JoinInfo *newnode = makeNode(JoinInfo);
COPY_INTLIST_FIELD(unjoined_relids);
COPY_BITMAPSET_FIELD(unjoined_relids);
COPY_NODE_FIELD(jinfo_restrictinfo);
return newnode;
......@@ -1102,8 +1106,8 @@ _copyInClauseInfo(InClauseInfo *from)
{
InClauseInfo *newnode = makeNode(InClauseInfo);
COPY_INTLIST_FIELD(lefthand);
COPY_INTLIST_FIELD(righthand);
COPY_BITMAPSET_FIELD(lefthand);
COPY_BITMAPSET_FIELD(righthand);
COPY_NODE_FIELD(sub_targetlist);
return newnode;
......
......@@ -18,7 +18,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.183 2003/02/03 21:15:44 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.184 2003/02/08 20:20:53 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -59,6 +59,13 @@
return false; \
} while (0)
/* Compare a field that is a pointer to a Bitmapset */
#define COMPARE_BITMAPSET_FIELD(fldname) \
do { \
if (!bms_equal(a->fldname, b->fldname)) \
return false; \
} while (0)
/* Compare a field that is a pointer to a C string, or perhaps NULL */
#define COMPARE_STRING_FIELD(fldname) \
do { \
......@@ -486,7 +493,7 @@ _equalRestrictInfo(RestrictInfo *a, RestrictInfo *b)
static bool
_equalJoinInfo(JoinInfo *a, JoinInfo *b)
{
COMPARE_INTLIST_FIELD(unjoined_relids);
COMPARE_BITMAPSET_FIELD(unjoined_relids);
COMPARE_NODE_FIELD(jinfo_restrictinfo);
return true;
......@@ -495,8 +502,8 @@ _equalJoinInfo(JoinInfo *a, JoinInfo *b)
static bool
_equalInClauseInfo(InClauseInfo *a, InClauseInfo *b)
{
COMPARE_INTLIST_FIELD(lefthand);
COMPARE_INTLIST_FIELD(righthand);
COMPARE_BITMAPSET_FIELD(lefthand);
COMPARE_BITMAPSET_FIELD(righthand);
COMPARE_NODE_FIELD(sub_targetlist);
return true;
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/list.c,v 1.46 2003/01/27 20:51:49 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/list.c,v 1.47 2003/02/08 20:20:54 tgl Exp $
*
* NOTES
* XXX a few of the following functions are duplicated to handle
......@@ -248,21 +248,6 @@ llast(List *l)
return lfirst(l);
}
/*
* llasti
*
* As above, but for integer lists
*/
int
llasti(List *l)
{
if (l == NIL)
elog(ERROR, "llasti: empty list");
while (lnext(l) != NIL)
l = lnext(l);
return lfirsti(l);
}
/*
* freeList
*
......@@ -304,35 +289,6 @@ equali(List *list1, List *list2)
return true;
}
/*
* sameseti
*
* Returns t if two integer lists contain the same elements
* (but unlike equali(), they need not be in the same order)
*
* Caution: this routine could be fooled if list1 contains
* duplicate elements. It is intended to be used on lists
* containing only nonduplicate elements, eg Relids lists.
*/
bool
sameseti(List *list1, List *list2)
{
List *temp;
if (list1 == NIL)
return list2 == NIL;
if (list2 == NIL)
return false;
if (length(list1) != length(list2))
return false;
foreach(temp, list1)
{
if (!intMember(lfirsti(temp), list2))
return false;
}
return true;
}
/*
* Generate the union of two lists,
* ie, l1 plus all members of l2 that are not already in l1.
......@@ -397,7 +353,6 @@ set_ptrUnion(List *l1, List *l2)
* The result is a fresh List, but it points to the same member nodes
* as were in the inputs.
*/
#ifdef NOT_USED
List *
set_intersect(List *l1, List *l2)
{
......@@ -411,7 +366,6 @@ set_intersect(List *l1, List *l2)
}
return retval;
}
#endif
List *
set_intersecti(List *l1, List *l2)
......@@ -664,6 +618,7 @@ set_ptrDifference(List *l1, List *l2)
/*
* Reverse a list, non-destructively
*/
#ifdef NOT_USED
List *
lreverse(List *l)
{
......@@ -674,39 +629,4 @@ lreverse(List *l)
result = lcons(lfirst(i), result);
return result;
}
/*
* Return t if two integer lists have any members in common.
*/
bool
overlap_setsi(List *list1, List *list2)
{
List *x;
foreach(x, list1)
{
int e = lfirsti(x);
if (intMember(e, list2))
return true;
}
return false;
}
/*
* Return t if all members of integer list list1 appear in list2.
*/
bool
is_subseti(List *list1, List *list2)
{
List *x;
foreach(x, list1)
{
int e = lfirsti(x);
if (!intMember(e, list2))
return false;
}
return true;
}
#endif
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.195 2003/02/03 21:15:44 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.196 2003/02/08 20:20:54 tgl Exp $
*
* NOTES
* Every node type that can appear in stored rules' parsetrees *must*
......@@ -96,6 +96,11 @@
(appendStringInfo(str, " :" CppAsString(fldname) " "), \
_outOidList(str, node->fldname))
/* Write a bitmapset field */
#define WRITE_BITMAPSET_FIELD(fldname) \
(appendStringInfo(str, " :" CppAsString(fldname) " "), \
_outBitmapset(str, node->fldname))
#define booltostr(x) ((x) ? "true" : "false")
......@@ -172,6 +177,29 @@ _outOidList(StringInfo str, List *list)
appendStringInfoChar(str, ')');
}
/*
* _outBitmapset -
* converts a bitmap set of integers
*
* Note: for historical reasons, the output is formatted exactly like
* an integer List would be.
*/
static void
_outBitmapset(StringInfo str, Bitmapset *bms)
{
Bitmapset *tmpset;
int x;
appendStringInfoChar(str, '(');
tmpset = bms_copy(bms);
while ((x = bms_first_member(tmpset)) >= 0)
{
appendStringInfo(str, " %d", x);
}
bms_free(tmpset);
appendStringInfoChar(str, ')');
}
/*
* Print the value of a Datum given its type.
*/
......@@ -963,8 +991,8 @@ _outRestrictInfo(StringInfo str, RestrictInfo *node)
WRITE_NODE_FIELD(clause);
WRITE_BOOL_FIELD(ispusheddown);
WRITE_NODE_FIELD(subclauseindices);
WRITE_INTLIST_FIELD(left_relids);
WRITE_INTLIST_FIELD(right_relids);
WRITE_BITMAPSET_FIELD(left_relids);
WRITE_BITMAPSET_FIELD(right_relids);
WRITE_OID_FIELD(mergejoinoperator);
WRITE_OID_FIELD(left_sortop);
WRITE_OID_FIELD(right_sortop);
......@@ -976,7 +1004,7 @@ _outJoinInfo(StringInfo str, JoinInfo *node)
{
WRITE_NODE_TYPE("JOININFO");
WRITE_INTLIST_FIELD(unjoined_relids);
WRITE_BITMAPSET_FIELD(unjoined_relids);
WRITE_NODE_FIELD(jinfo_restrictinfo);
}
......@@ -985,8 +1013,8 @@ _outInClauseInfo(StringInfo str, InClauseInfo *node)
{
WRITE_NODE_TYPE("INCLAUSEINFO");
WRITE_INTLIST_FIELD(lefthand);
WRITE_INTLIST_FIELD(righthand);
WRITE_BITMAPSET_FIELD(lefthand);
WRITE_BITMAPSET_FIELD(righthand);
WRITE_NODE_FIELD(sub_targetlist);
}
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.95 2003/01/25 23:10:27 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.96 2003/02/08 20:20:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -79,7 +79,7 @@ make_one_rel(Query *root)
/*
* The result should join all the query's base rels.
*/
Assert(length(rel->relids) == length(root->base_rel_list));
Assert(bms_num_members(rel->relids) == length(root->base_rel_list));
return rel;
}
......@@ -98,12 +98,11 @@ set_base_rel_pathlists(Query *root)
foreach(rellist, root->base_rel_list)
{
RelOptInfo *rel = (RelOptInfo *) lfirst(rellist);
Index rti;
Index rti = rel->relid;
RangeTblEntry *rte;
List *inheritlist;
Assert(length(rel->relids) == 1); /* better be base rel */
rti = lfirsti(rel->relids);
Assert(rti > 0); /* better be base rel */
rte = rt_fetch(rti, root->rtable);
if (rel->rtekind == RTE_SUBQUERY)
......@@ -696,14 +695,19 @@ recurse_push_qual(Node *setOp, Query *topquery,
static void
print_relids(Relids relids)
{
List *l;
Relids tmprelids;
int x;
bool first = true;
foreach(l, relids)
tmprelids = bms_copy(relids);
while ((x = bms_first_member(tmprelids)) >= 0)
{
printf("%d", lfirsti(l));
if (lnext(l))
if (!first)
printf(" ");
printf("%d", x);
first = false;
}
bms_free(tmprelids);
}
static void
......
......@@ -49,7 +49,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.104 2003/01/28 22:13:33 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.105 2003/02/08 20:20:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -124,7 +124,7 @@ cost_seqscan(Path *path, Query *root,
Cost cpu_per_tuple;
/* Should only be applied to base relations */
Assert(length(baserel->relids) == 1);
Assert(baserel->relid > 0);
Assert(baserel->rtekind == RTE_RELATION);
if (!enable_seqscan)
......@@ -241,7 +241,7 @@ cost_index(Path *path, Query *root,
/* Should only be applied to base relations */
Assert(IsA(baserel, RelOptInfo) &&
IsA(index, IndexOptInfo));
Assert(length(baserel->relids) == 1);
Assert(baserel->relid > 0);
Assert(baserel->rtekind == RTE_RELATION);
if (!enable_indexscan)
......@@ -397,7 +397,7 @@ cost_tidscan(Path *path, Query *root,
int ntuples = length(tideval);
/* Should only be applied to base relations */
Assert(length(baserel->relids) == 1);
Assert(baserel->relid > 0);
Assert(baserel->rtekind == RTE_RELATION);
if (!enable_tidscan)
......@@ -427,7 +427,7 @@ cost_functionscan(Path *path, Query *root, RelOptInfo *baserel)
Cost cpu_per_tuple;
/* Should only be applied to base relations that are functions */
Assert(length(baserel->relids) == 1);
Assert(baserel->relid > 0);
Assert(baserel->rtekind == RTE_FUNCTION);
/*
......@@ -886,7 +886,7 @@ cost_mergejoin(MergePath *path, Query *root)
&firstclause->left_mergescansel,
&firstclause->right_mergescansel);
if (is_subseti(firstclause->left_relids, outer_path->parent->relids))
if (bms_is_subset(firstclause->left_relids, outer_path->parent->relids))
{
/* left side of clause is outer */
outerscansel = firstclause->left_mergescansel;
......@@ -1116,8 +1116,8 @@ cost_hashjoin(HashPath *path, Query *root)
* planning a large query, we cache the bucketsize estimate in the
* RestrictInfo node to avoid repeated lookups of statistics.
*/
if (is_subseti(restrictinfo->right_relids,
inner_path->parent->relids))
if (bms_is_subset(restrictinfo->right_relids,
inner_path->parent->relids))
{
/* righthand side is inner */
thisbucketsize = restrictinfo->right_bucketsize;
......@@ -1133,8 +1133,8 @@ cost_hashjoin(HashPath *path, Query *root)
}
else
{
Assert(is_subseti(restrictinfo->left_relids,
inner_path->parent->relids));
Assert(bms_is_subset(restrictinfo->left_relids,
inner_path->parent->relids));
/* lefthand side is inner */
thisbucketsize = restrictinfo->left_bucketsize;
if (thisbucketsize < 0)
......@@ -1635,12 +1635,12 @@ set_baserel_size_estimates(Query *root, RelOptInfo *rel)
double temp;
/* Should only be applied to base relations */
Assert(length(rel->relids) == 1);
Assert(rel->relid > 0);
temp = rel->tuples *
restrictlist_selectivity(root,
rel->baserestrictinfo,
lfirsti(rel->relids),
rel->relid,
JOIN_INNER);
/*
......@@ -1803,7 +1803,7 @@ set_function_size_estimates(Query *root, RelOptInfo *rel)
double temp;
/* Should only be applied to base relations that are functions */
Assert(length(rel->relids) == 1);
Assert(rel->relid > 0);
Assert(rel->rtekind == RTE_FUNCTION);
/*
......@@ -1818,7 +1818,7 @@ set_function_size_estimates(Query *root, RelOptInfo *rel)
temp = rel->tuples *
restrictlist_selectivity(root,
rel->baserestrictinfo,
lfirsti(rel->relids),
rel->relid,
JOIN_INNER);
/*
......
......@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.134 2003/01/28 22:13:33 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.135 2003/02/08 20:20:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -133,7 +133,7 @@ create_index_paths(Query *root, RelOptInfo *rel)
{
List *restrictinfo_list = rel->baserestrictinfo;
List *joininfo_list = rel->joininfo;
Relids all_join_outerrelids = NIL;
Relids all_join_outerrelids = NULL;
List *ilist;
foreach(ilist, rel->indexlist)
......@@ -151,7 +151,7 @@ create_index_paths(Query *root, RelOptInfo *rel)
*/
if (index->indpred != NIL)
if (!pred_test(index->indpred, restrictinfo_list, joininfo_list,
lfirsti(rel->relids)))
rel->relid))
continue;
/*
......@@ -227,15 +227,15 @@ create_index_paths(Query *root, RelOptInfo *rel)
/*
* 6. Examine join clauses to see which ones are potentially
* usable with this index, and generate a list of all other relids
* that participate in such join clauses. We'll use this list later
* usable with this index, and generate the set of all other relids
* that participate in such join clauses. We'll use this set later
* to recognize outer rels that are equivalent for joining purposes.
* We compute both per-index and overall-for-relation lists.
* We compute both per-index and overall-for-relation sets.
*/
join_outerrelids = indexable_outerrelids(rel, index);
index->outer_relids = join_outerrelids;
all_join_outerrelids = set_unioni(all_join_outerrelids,
join_outerrelids);
all_join_outerrelids = bms_add_members(all_join_outerrelids,
join_outerrelids);
}
rel->index_outer_relids = all_join_outerrelids;
......@@ -609,7 +609,7 @@ group_clauses_by_indexkey_for_join(RelOptInfo *rel, IndexOptInfo *index,
JoinInfo *joininfo = (JoinInfo *) lfirst(i);
List *j;
if (!is_subseti(joininfo->unjoined_relids, outer_relids))
if (!bms_is_subset(joininfo->unjoined_relids, outer_relids))
continue;
foreach(j, joininfo->jinfo_restrictinfo)
......@@ -820,27 +820,27 @@ match_join_clause_to_indexkey(RelOptInfo *rel,
*/
if (match_index_to_operand(indexkey, leftop, rel, index))
{
List *othervarnos = pull_varnos(rightop);
Relids othervarnos = pull_varnos(rightop);
bool isIndexable;
isIndexable =
!intMember(lfirsti(rel->relids), othervarnos) &&
!bms_overlap(rel->relids, othervarnos) &&
!contain_volatile_functions(rightop) &&
is_indexable_operator(clause, opclass, true);
freeList(othervarnos);
bms_free(othervarnos);
return isIndexable;
}
if (match_index_to_operand(indexkey, rightop, rel, index))
{
List *othervarnos = pull_varnos(leftop);
Relids othervarnos = pull_varnos(leftop);
bool isIndexable;
isIndexable =
!intMember(lfirsti(rel->relids), othervarnos) &&
!bms_overlap(rel->relids, othervarnos) &&
!contain_volatile_functions(leftop) &&
is_indexable_operator(clause, opclass, false);
freeList(othervarnos);
bms_free(othervarnos);
return isIndexable;
}
......@@ -1312,14 +1312,14 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
/*
* indexable_outerrelids
* Finds all other relids that participate in any indexable join clause
* for the specified index. Returns a list of relids.
* for the specified index. Returns a set of relids.
*
* 'rel' is the relation for which 'index' is defined
*/
static Relids
indexable_outerrelids(RelOptInfo *rel, IndexOptInfo *index)
{
Relids outer_relids = NIL;
Relids outer_relids = NULL;
List *i;
foreach(i, rel->joininfo)
......@@ -1368,8 +1368,8 @@ indexable_outerrelids(RelOptInfo *rel, IndexOptInfo *index)
if (match_found)
{
outer_relids = set_unioni(outer_relids,
joininfo->unjoined_relids);
outer_relids = bms_add_members(outer_relids,
joininfo->unjoined_relids);
}
}
......@@ -1419,7 +1419,7 @@ best_inner_indexscan(Query *root, RelOptInfo *rel,
/*
* If there are no indexable joinclauses for this rel, exit quickly.
*/
if (!rel->index_outer_relids)
if (bms_is_empty(rel->index_outer_relids))
return NULL;
/*
* Otherwise, we have to do path selection in the memory context of
......@@ -1433,9 +1433,10 @@ best_inner_indexscan(Query *root, RelOptInfo *rel,
* to find the set of outer relids actually relevant for this index.
* If there are none, again we can fail immediately.
*/
outer_relids = set_intersecti(rel->index_outer_relids, outer_relids);
if (!outer_relids)
outer_relids = bms_intersect(rel->index_outer_relids, outer_relids);
if (bms_is_empty(outer_relids))
{
bms_free(outer_relids);
MemoryContextSwitchTo(oldcontext);
return NULL;
}
......@@ -1448,10 +1449,10 @@ best_inner_indexscan(Query *root, RelOptInfo *rel,
foreach(jlist, rel->index_inner_paths)
{
info = (InnerIndexscanInfo *) lfirst(jlist);
if (sameseti(info->other_relids, outer_relids) &&
if (bms_equal(info->other_relids, outer_relids) &&
info->isouterjoin == isouterjoin)
{
freeList(outer_relids);
bms_free(outer_relids);
MemoryContextSwitchTo(oldcontext);
return info->best_innerpath;
}
......@@ -1470,24 +1471,25 @@ best_inner_indexscan(Query *root, RelOptInfo *rel,
Relids index_outer_relids;
Path *path = NULL;
/* skip quickly if index has no useful join clauses */
if (!index->outer_relids)
continue;
/* identify set of relevant outer relids for this index */
index_outer_relids = set_intersecti(index->outer_relids, outer_relids);
if (!index_outer_relids)
index_outer_relids = bms_intersect(index->outer_relids, outer_relids);
/* skip if none */
if (bms_is_empty(index_outer_relids))
{
bms_free(index_outer_relids);
continue;
}
/*
* Look to see if we already computed the result for this index.
*/
foreach(jlist, index->inner_paths)
{
info = (InnerIndexscanInfo *) lfirst(jlist);
if (sameseti(info->other_relids, index_outer_relids) &&
if (bms_equal(info->other_relids, index_outer_relids) &&
info->isouterjoin == isouterjoin)
{
path = info->best_innerpath;
freeList(index_outer_relids); /* not needed anymore */
bms_free(index_outer_relids); /* not needed anymore */
break;
}
}
......@@ -1607,7 +1609,7 @@ make_innerjoin_index_path(Query *root,
restrictlist_selectivity(root,
set_ptrUnion(rel->baserestrictinfo,
clausegroup),
lfirsti(rel->relids),
rel->relid,
JOIN_INNER);
/* Like costsize.c, force estimate to be at least one row */
if (pathnode->rows < 1.0)
......@@ -1649,7 +1651,7 @@ match_index_to_operand(int indexkey,
* Simple index.
*/
if (operand && IsA(operand, Var) &&
lfirsti(rel->relids) == ((Var *) operand)->varno &&
rel->relid == ((Var *) operand)->varno &&
indexkey == ((Var *) operand)->varattno)
return true;
else
......@@ -1665,7 +1667,6 @@ match_index_to_operand(int indexkey,
static bool
function_index_operand(Expr *funcOpnd, RelOptInfo *rel, IndexOptInfo *index)
{
int relvarno = lfirsti(rel->relids);
FuncExpr *function;
List *funcargs;
int *indexKeys = index->indexkeys;
......@@ -1705,7 +1706,7 @@ function_index_operand(Expr *funcOpnd, RelOptInfo *rel, IndexOptInfo *index)
return false;
if (indexKeys[i] == 0)
return false;
if (var->varno != relvarno || var->varattno != indexKeys[i])
if (var->varno != rel->relid || var->varattno != indexKeys[i])
return false;
i++;
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinpath.c,v 1.77 2003/01/27 20:51:51 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinpath.c,v 1.78 2003/02/08 20:20:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -689,7 +689,7 @@ hash_inner_and_outer(Query *root,
{
RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(i);
if (restrictinfo->left_relids == NIL ||
if (restrictinfo->left_relids == NULL ||
restrictinfo->hashjoinoperator == InvalidOid)
continue; /* not hashjoinable */
......@@ -703,13 +703,13 @@ hash_inner_and_outer(Query *root,
/*
* Check if clause is usable with these input rels.
*/
if (is_subseti(restrictinfo->left_relids, outerrel->relids) &&
is_subseti(restrictinfo->right_relids, innerrel->relids))
if (bms_is_subset(restrictinfo->left_relids, outerrel->relids) &&
bms_is_subset(restrictinfo->right_relids, innerrel->relids))
{
/* righthand side is inner */
}
else if (is_subseti(restrictinfo->left_relids, innerrel->relids) &&
is_subseti(restrictinfo->right_relids, outerrel->relids))
else if (bms_is_subset(restrictinfo->left_relids, innerrel->relids) &&
bms_is_subset(restrictinfo->right_relids, outerrel->relids))
{
/* lefthand side is inner */
}
......@@ -808,12 +808,12 @@ select_mergejoin_clauses(RelOptInfo *joinrel,
switch (jointype)
{
case JOIN_RIGHT:
if (restrictinfo->left_relids == NIL ||
if (restrictinfo->left_relids == NULL ||
restrictinfo->mergejoinoperator == InvalidOid)
return NIL; /* not mergejoinable */
break;
case JOIN_FULL:
if (restrictinfo->left_relids == NIL ||
if (restrictinfo->left_relids == NULL ||
restrictinfo->mergejoinoperator == InvalidOid)
elog(ERROR, "FULL JOIN is only supported with mergejoinable join conditions");
break;
......@@ -823,7 +823,7 @@ select_mergejoin_clauses(RelOptInfo *joinrel,
}
}
if (restrictinfo->left_relids == NIL ||
if (restrictinfo->left_relids == NULL ||
restrictinfo->mergejoinoperator == InvalidOid)
continue; /* not mergejoinable */
......@@ -832,13 +832,13 @@ select_mergejoin_clauses(RelOptInfo *joinrel,
* needed on each side of the clause must be available from one or
* the other of the input rels.
*/
if (is_subseti(restrictinfo->left_relids, outerrel->relids) &&
is_subseti(restrictinfo->right_relids, innerrel->relids))
if (bms_is_subset(restrictinfo->left_relids, outerrel->relids) &&
bms_is_subset(restrictinfo->right_relids, innerrel->relids))
{
/* righthand side is inner */
}
else if (is_subseti(restrictinfo->left_relids, innerrel->relids) &&
is_subseti(restrictinfo->right_relids, outerrel->relids))
else if (bms_is_subset(restrictinfo->left_relids, innerrel->relids) &&
bms_is_subset(restrictinfo->right_relids, outerrel->relids))
{
/* lefthand side is inner */
}
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinrels.c,v 1.59 2003/01/20 18:54:51 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinrels.c,v 1.60 2003/02/08 20:20:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -151,7 +151,7 @@ make_rels_by_joins(Query *root, int level, List **joinrels)
{
RelOptInfo *new_rel = (RelOptInfo *) lfirst(r2);
if (nonoverlap_setsi(old_rel->relids, new_rel->relids))
if (!bms_overlap(old_rel->relids, new_rel->relids))
{
List *i;
......@@ -164,8 +164,8 @@ make_rels_by_joins(Query *root, int level, List **joinrels)
{
JoinInfo *joininfo = (JoinInfo *) lfirst(i);
if (is_subseti(joininfo->unjoined_relids,
new_rel->relids))
if (bms_is_subset(joininfo->unjoined_relids,
new_rel->relids))
{
RelOptInfo *jrel;
......@@ -268,7 +268,7 @@ make_rels_by_clause_joins(Query *root,
{
RelOptInfo *other_rel = (RelOptInfo *) lfirst(j);
if (is_subseti(unjoined_relids, other_rel->relids))
if (bms_is_subset(unjoined_relids, other_rel->relids))
{
RelOptInfo *jrel;
......@@ -312,7 +312,7 @@ make_rels_by_clauseless_joins(Query *root,
{
RelOptInfo *other_rel = (RelOptInfo *) lfirst(i);
if (nonoverlap_setsi(other_rel->relids, old_rel->relids))
if (!bms_overlap(other_rel->relids, old_rel->relids))
{
RelOptInfo *jrel;
......@@ -406,15 +406,15 @@ RelOptInfo *
make_join_rel(Query *root, RelOptInfo *rel1, RelOptInfo *rel2,
JoinType jointype)
{
List *joinrelids;
Relids joinrelids;
RelOptInfo *joinrel;
List *restrictlist;
/* We should never try to join two overlapping sets of rels. */
Assert(nonoverlap_setsi(rel1->relids, rel2->relids));
Assert(!bms_overlap(rel1->relids, rel2->relids));
/* Construct Relids set that identifies the joinrel. */
joinrelids = nconc(listCopy(rel1->relids), listCopy(rel2->relids));
joinrelids = bms_union(rel1->relids, rel2->relids);
/*
* If we are implementing IN clauses as joins, there are some joins
......@@ -433,15 +433,12 @@ make_join_rel(Query *root, RelOptInfo *rel1, RelOptInfo *rel2,
/*
* Cannot join if proposed join contains part, but only
* part, of the RHS, *and* it contains rels not in the RHS.
*
* Singleton RHS cannot be a problem, so skip expensive tests.
*/
if (length(ininfo->righthand) > 1 &&
overlap_setsi(ininfo->righthand, joinrelids) &&
!is_subseti(ininfo->righthand, joinrelids) &&
!is_subseti(joinrelids, ininfo->righthand))
if (bms_overlap(ininfo->righthand, joinrelids) &&
!bms_is_subset(ininfo->righthand, joinrelids) &&
!bms_is_subset(joinrelids, ininfo->righthand))
{
freeList(joinrelids);
bms_free(joinrelids);
return NULL;
}
......@@ -449,19 +446,19 @@ make_join_rel(Query *root, RelOptInfo *rel1, RelOptInfo *rel2,
* No issue unless we are looking at a join of the IN's RHS
* to other stuff.
*/
if (! (length(ininfo->righthand) < length(joinrelids) &&
is_subseti(ininfo->righthand, joinrelids)))
if (! (bms_is_subset(ininfo->righthand, joinrelids) &&
!bms_equal(ininfo->righthand, joinrelids)))
continue;
/*
* If we already joined IN's RHS to any part of its LHS in either
* input path, then this join is not constrained (the necessary
* work was done at a lower level).
*/
if (overlap_setsi(ininfo->lefthand, rel1->relids) &&
is_subseti(ininfo->righthand, rel1->relids))
if (bms_overlap(ininfo->lefthand, rel1->relids) &&
bms_is_subset(ininfo->righthand, rel1->relids))
continue;
if (overlap_setsi(ininfo->lefthand, rel2->relids) &&
is_subseti(ininfo->righthand, rel2->relids))
if (bms_overlap(ininfo->lefthand, rel2->relids) &&
bms_is_subset(ininfo->righthand, rel2->relids))
continue;
/*
* JOIN_IN technique will work if outerrel includes LHS and
......@@ -477,31 +474,31 @@ make_join_rel(Query *root, RelOptInfo *rel1, RelOptInfo *rel2,
*/
if (jointype != JOIN_INNER)
{
freeList(joinrelids);
bms_free(joinrelids);
return NULL;
}
if (is_subseti(ininfo->lefthand, rel1->relids) &&
sameseti(ininfo->righthand, rel2->relids))
if (bms_is_subset(ininfo->lefthand, rel1->relids) &&
bms_equal(ininfo->righthand, rel2->relids))
{
jointype = JOIN_IN;
}
else if (is_subseti(ininfo->lefthand, rel2->relids) &&
sameseti(ininfo->righthand, rel1->relids))
else if (bms_is_subset(ininfo->lefthand, rel2->relids) &&
bms_equal(ininfo->righthand, rel1->relids))
{
jointype = JOIN_REVERSE_IN;
}
else if (sameseti(ininfo->righthand, rel1->relids))
else if (bms_equal(ininfo->righthand, rel1->relids))
{
jointype = JOIN_UNIQUE_OUTER;
}
else if (sameseti(ininfo->righthand, rel2->relids))
else if (bms_equal(ininfo->righthand, rel2->relids))
{
jointype = JOIN_UNIQUE_INNER;
}
else
{
/* invalid join path */
freeList(joinrelids);
bms_free(joinrelids);
return NULL;
}
}
......@@ -579,7 +576,7 @@ make_join_rel(Query *root, RelOptInfo *rel1, RelOptInfo *rel2,
break;
}
freeList(joinrelids);
bms_free(joinrelids);
return joinrel;
}
......@@ -11,7 +11,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/pathkeys.c,v 1.45 2003/01/24 03:58:35 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/pathkeys.c,v 1.46 2003/02/08 20:20:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -198,7 +198,7 @@ generate_implied_equalities(Query *root)
* Collect info about relids mentioned in each item. For this
* routine we only really care whether there are any at all in
* each item, but process_implied_equality() needs the exact
* lists, so we may as well pull them here.
* sets, so we may as well pull them here.
*/
relids = (Relids *) palloc(nitems * sizeof(Relids));
have_consts = false;
......@@ -208,7 +208,7 @@ generate_implied_equalities(Query *root)
PathKeyItem *item1 = (PathKeyItem *) lfirst(ptr1);
relids[i1] = pull_varnos(item1->key);
if (relids[i1] == NIL)
if (bms_is_empty(relids[i1]))
have_consts = true;
i1++;
}
......@@ -221,12 +221,14 @@ generate_implied_equalities(Query *root)
foreach(ptr1, curset)
{
PathKeyItem *item1 = (PathKeyItem *) lfirst(ptr1);
bool i1_is_variable = !bms_is_empty(relids[i1]);
List *ptr2;
int i2 = i1 + 1;
foreach(ptr2, lnext(ptr1))
{
PathKeyItem *item2 = (PathKeyItem *) lfirst(ptr2);
bool i2_is_variable = !bms_is_empty(relids[i2]);
/*
* If it's "const = const" then just ignore it altogether.
......@@ -235,7 +237,7 @@ generate_implied_equalities(Query *root)
* propagating the comparison to Vars will cause us to
* produce zero rows out, as expected.)
*/
if (relids[i1] != NIL || relids[i2] != NIL)
if (i1_is_variable || i2_is_variable)
{
/*
* Tell process_implied_equality to delete the clause,
......@@ -243,8 +245,9 @@ generate_implied_equalities(Query *root)
* present in the list.
*/
bool delete_it = (have_consts &&
relids[i1] != NIL &&
relids[i2] != NIL);
i1_is_variable &&
i2_is_variable);
process_implied_equality(root,
item1->key, item2->key,
item1->sortop, item2->sortop,
......@@ -689,7 +692,7 @@ static Var *
find_indexkey_var(Query *root, RelOptInfo *rel, AttrNumber varattno)
{
List *temp;
int relid;
Index relid;
Oid reloid,
vartypeid;
int32 type_mod;
......@@ -702,7 +705,8 @@ find_indexkey_var(Query *root, RelOptInfo *rel, AttrNumber varattno)
return tle_var;
}
relid = lfirsti(rel->relids);
relid = rel->relid;
Assert(relid > 0);
reloid = getrelid(relid, root->rtable);
vartypeid = get_atttype(reloid, varattno);
type_mod = get_atttypmod(reloid, varattno);
......@@ -953,12 +957,12 @@ make_pathkeys_for_mergeclauses(Query *root,
cache_mergeclause_pathkeys(root, restrictinfo);
if (is_subseti(restrictinfo->left_relids, rel->relids))
if (bms_is_subset(restrictinfo->left_relids, rel->relids))
{
/* Rel is left side of mergeclause */
pathkey = restrictinfo->left_pathkey;
}
else if (is_subseti(restrictinfo->right_relids, rel->relids))
else if (bms_is_subset(restrictinfo->right_relids, rel->relids))
{
/* Rel is right side of mergeclause */
pathkey = restrictinfo->right_pathkey;
......
......@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/tidpath.c,v 1.13 2002/12/12 15:49:32 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/tidpath.c,v 1.14 2003/02/08 20:20:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -25,7 +25,7 @@
#include "parser/parse_coerce.h"
#include "utils/lsyscache.h"
static List *TidqualFromRestrictinfo(List *relids, List *restrictinfo);
static List *TidqualFromRestrictinfo(Relids relids, List *restrictinfo);
static bool isEvaluable(int varno, Node *node);
static Node *TidequalClause(int varno, OpExpr *node);
static List *TidqualFromExpr(int varno, Expr *expr);
......@@ -198,7 +198,7 @@ TidqualFromExpr(int varno, Expr *expr)
}
static List *
TidqualFromRestrictinfo(List *relids, List *restrictinfo)
TidqualFromRestrictinfo(Relids relids, List *restrictinfo)
{
List *lst,
*rlst = NIL;
......@@ -206,9 +206,9 @@ TidqualFromRestrictinfo(List *relids, List *restrictinfo)
Node *node;
Expr *expr;
if (length(relids) != 1)
if (bms_membership(relids) != BMS_SINGLETON)
return NIL;
varno = lfirsti(relids);
varno = bms_singleton_member(relids);
foreach(lst, restrictinfo)
{
node = lfirst(lst);
......
......@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.134 2003/02/03 15:07:07 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.135 2003/02/08 20:20:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -65,13 +65,14 @@ static HashJoin *create_hashjoin_plan(Query *root,
static void fix_indxqual_references(List *indexquals, IndexPath *index_path,
List **fixed_indexquals,
List **recheck_indexquals);
static void fix_indxqual_sublist(List *indexqual, int baserelid,
IndexOptInfo *index,
List **fixed_quals, List **recheck_quals);
static void fix_indxqual_sublist(List *indexqual,
Relids baserelids, int baserelid,
IndexOptInfo *index,
List **fixed_quals, List **recheck_quals);
static Node *fix_indxqual_operand(Node *node, int baserelid,
IndexOptInfo *index,
Oid *opclass);
static List *get_switched_clauses(List *clauses, List *outerrelids);
static List *get_switched_clauses(List *clauses, Relids outerrelids);
static List *order_qual_clauses(Query *root, List *clauses);
static void copy_path_costsize(Plan *dest, Path *src);
static void copy_plan_costsize(Plan *dest, Plan *src);
......@@ -100,7 +101,7 @@ static MergeJoin *make_mergejoin(List *tlist,
Plan *lefttree, Plan *righttree,
JoinType jointype);
static Sort *make_sort_from_pathkeys(Query *root, Plan *lefttree,
List *relids, List *pathkeys);
Relids relids, List *pathkeys);
/*
......@@ -502,7 +503,7 @@ create_unique_plan(Query *root, UniquePath *best_path)
{
InClauseInfo *ininfo = (InClauseInfo *) lfirst(l);
if (sameseti(ininfo->righthand, best_path->path.parent->relids))
if (bms_equal(ininfo->righthand, best_path->path.parent->relids))
{
sub_targetlist = ininfo->sub_targetlist;
break;
......@@ -601,14 +602,12 @@ static SeqScan *
create_seqscan_plan(Path *best_path, List *tlist, List *scan_clauses)
{
SeqScan *scan_plan;
Index scan_relid;
Index scan_relid = best_path->parent->relid;
/* there should be exactly one base rel involved... */
Assert(length(best_path->parent->relids) == 1);
/* it should be a base rel... */
Assert(scan_relid > 0);
Assert(best_path->parent->rtekind == RTE_RELATION);
scan_relid = (Index) lfirsti(best_path->parent->relids);
scan_plan = make_seqscan(tlist,
scan_clauses,
scan_relid);
......@@ -638,7 +637,7 @@ create_indexscan_plan(Query *root,
List *scan_clauses)
{
List *indxqual = best_path->indexqual;
Index baserelid;
Index baserelid = best_path->path.parent->relid;
List *qpqual;
Expr *indxqual_or_expr = NULL;
List *fixed_indxqual;
......@@ -647,12 +646,10 @@ create_indexscan_plan(Query *root,
List *ixinfo;
IndexScan *scan_plan;
/* there should be exactly one base rel involved... */
Assert(length(best_path->path.parent->relids) == 1);
/* it should be a base rel... */
Assert(baserelid > 0);
Assert(best_path->path.parent->rtekind == RTE_RELATION);
baserelid = lfirsti(best_path->path.parent->relids);
/*
* Build list of index OIDs.
*/
......@@ -763,14 +760,12 @@ static TidScan *
create_tidscan_plan(TidPath *best_path, List *tlist, List *scan_clauses)
{
TidScan *scan_plan;
Index scan_relid;
Index scan_relid = best_path->path.parent->relid;
/* there should be exactly one base rel involved... */
Assert(length(best_path->path.parent->relids) == 1);
/* it should be a base rel... */
Assert(scan_relid > 0);
Assert(best_path->path.parent->rtekind == RTE_RELATION);
scan_relid = (Index) lfirsti(best_path->path.parent->relids);
scan_plan = make_tidscan(tlist,
scan_clauses,
scan_relid,
......@@ -790,15 +785,12 @@ static SubqueryScan *
create_subqueryscan_plan(Path *best_path, List *tlist, List *scan_clauses)
{
SubqueryScan *scan_plan;
Index scan_relid;
Index scan_relid = best_path->parent->relid;
/* there should be exactly one base rel involved... */
Assert(length(best_path->parent->relids) == 1);
/* and it must be a subquery */
/* it should be a subquery base rel... */
Assert(scan_relid > 0);
Assert(best_path->parent->rtekind == RTE_SUBQUERY);
scan_relid = (Index) lfirsti(best_path->parent->relids);
scan_plan = make_subqueryscan(tlist,
scan_clauses,
scan_relid,
......@@ -816,15 +808,12 @@ static FunctionScan *
create_functionscan_plan(Path *best_path, List *tlist, List *scan_clauses)
{
FunctionScan *scan_plan;
Index scan_relid;
Index scan_relid = best_path->parent->relid;
/* there should be exactly one base rel involved... */
Assert(length(best_path->parent->relids) == 1);
/* and it must be a function */
/* it should be a function base rel... */
Assert(scan_relid > 0);
Assert(best_path->parent->rtekind == RTE_FUNCTION);
scan_relid = (Index) lfirsti(best_path->parent->relids);
scan_plan = make_functionscan(tlist, scan_clauses, scan_relid);
copy_path_costsize(&scan_plan->scan.plan, best_path);
......@@ -1055,7 +1044,8 @@ fix_indxqual_references(List *indexquals, IndexPath *index_path,
{
List *fixed_quals = NIL;
List *recheck_quals = NIL;
int baserelid = lfirsti(index_path->path.parent->relids);
Relids baserelids = index_path->path.parent->relids;
int baserelid = index_path->path.parent->relid;
List *ixinfo = index_path->indexinfo;
List *i;
......@@ -1066,7 +1056,7 @@ fix_indxqual_references(List *indexquals, IndexPath *index_path,
List *fixed_qual;
List *recheck_qual;
fix_indxqual_sublist(indexqual, baserelid, index,
fix_indxqual_sublist(indexqual, baserelids, baserelid, index,
&fixed_qual, &recheck_qual);
fixed_quals = lappend(fixed_quals, fixed_qual);
if (recheck_qual != NIL)
......@@ -1092,7 +1082,9 @@ fix_indxqual_references(List *indexquals, IndexPath *index_path,
* the index is lossy for this operator type.
*/
static void
fix_indxqual_sublist(List *indexqual, int baserelid, IndexOptInfo *index,
fix_indxqual_sublist(List *indexqual,
Relids baserelids, int baserelid,
IndexOptInfo *index,
List **fixed_quals, List **recheck_quals)
{
List *fixed_qual = NIL;
......@@ -1103,7 +1095,7 @@ fix_indxqual_sublist(List *indexqual, int baserelid, IndexOptInfo *index,
{
OpExpr *clause = (OpExpr *) lfirst(i);
OpExpr *newclause;
List *leftvarnos;
Relids leftvarnos;
Oid opclass;
if (!IsA(clause, OpExpr) || length(clause->args) != 2)
......@@ -1124,9 +1116,9 @@ fix_indxqual_sublist(List *indexqual, int baserelid, IndexOptInfo *index,
* (only) the base relation.
*/
leftvarnos = pull_varnos((Node *) lfirst(newclause->args));
if (length(leftvarnos) != 1 || lfirsti(leftvarnos) != baserelid)
if (!bms_equal(leftvarnos, baserelids))
CommuteClause(newclause);
freeList(leftvarnos);
bms_free(leftvarnos);
/*
* Now, determine which index attribute this is, change the
......@@ -1222,7 +1214,7 @@ fix_indxqual_operand(Node *node, int baserelid, IndexOptInfo *index,
* a modified list is returned.
*/
static List *
get_switched_clauses(List *clauses, List *outerrelids)
get_switched_clauses(List *clauses, Relids outerrelids)
{
List *t_list = NIL;
List *i;
......@@ -1233,7 +1225,7 @@ get_switched_clauses(List *clauses, List *outerrelids)
OpExpr *clause = (OpExpr *) restrictinfo->clause;
Assert(is_opclause(clause));
if (is_subseti(restrictinfo->right_relids, outerrelids))
if (bms_is_subset(restrictinfo->right_relids, outerrelids))
{
/*
* Duplicate just enough of the structure to allow commuting
......@@ -1628,7 +1620,7 @@ make_sort(Query *root, List *tlist, Plan *lefttree, int keycount)
*/
static Sort *
make_sort_from_pathkeys(Query *root, Plan *lefttree,
List *relids, List *pathkeys)
Relids relids, List *pathkeys)
{
List *tlist = lefttree->targetlist;
List *sort_tlist;
......@@ -1671,7 +1663,7 @@ make_sort_from_pathkeys(Query *root, Plan *lefttree,
foreach(j, keysublist)
{
pathkey = lfirst(j);
if (is_subseti(pull_varnos(pathkey->key), relids))
if (bms_is_subset(pull_varnos(pathkey->key), relids))
break;
}
if (!j)
......
This diff is collapsed.
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.69 2003/01/28 22:13:35 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.70 2003/02/08 20:20:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -607,7 +607,7 @@ Node *
convert_IN_to_join(Query *parse, SubLink *sublink)
{
Query *subselect = (Query *) sublink->subselect;
List *left_varnos;
Relids left_varnos;
int rtindex;
RangeTblEntry *rte;
RangeTblRef *rtr;
......@@ -635,7 +635,7 @@ convert_IN_to_join(Query *parse, SubLink *sublink)
* query, else it's not gonna be a join.
*/
left_varnos = pull_varnos((Node *) sublink->lefthand);
if (left_varnos == NIL)
if (bms_is_empty(left_varnos))
return NULL;
/*
* The left-hand expressions mustn't be volatile. (Perhaps we should
......@@ -666,7 +666,7 @@ convert_IN_to_join(Query *parse, SubLink *sublink)
*/
ininfo = makeNode(InClauseInfo);
ininfo->lefthand = left_varnos;
ininfo->righthand = makeListi1(rtindex);
ininfo->righthand = bms_make_singleton(rtindex);
parse->in_info_list = lcons(ininfo, parse->in_info_list);
/*
* Build the result qual expressions. As a side effect,
......
......@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.2 2003/01/25 23:10:27 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.3 2003/02/08 20:20:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -236,7 +236,7 @@ pull_up_subqueries(Query *parse, Node *jtnode, bool below_outer_join)
parse->rowMarks = nconc(parse->rowMarks, subquery->rowMarks);
/*
* We also have to fix the relid lists of any parent InClauseInfo
* We also have to fix the relid sets of any parent InClauseInfo
* nodes. (This could perhaps be done by ResolveNew, but it
* would clutter that routine's API unreasonably.)
*/
......@@ -611,10 +611,10 @@ preprocess_jointree(Query *parse, Node *jtnode)
}
/*
* fix_in_clause_relids: update RT-index lists of InClauseInfo nodes
* fix_in_clause_relids: update RT-index sets of InClauseInfo nodes
*
* When we pull up a subquery, any InClauseInfo references to the subquery's
* RT index have to be replaced by the list of substituted relids.
* RT index have to be replaced by the set of substituted relids.
*
* We assume we may modify the InClauseInfo nodes in-place.
*/
......@@ -627,26 +627,26 @@ fix_in_clause_relids(List *in_info_list, int varno, Relids subrelids)
{
InClauseInfo *ininfo = (InClauseInfo *) lfirst(l);
if (intMember(varno, ininfo->lefthand))
if (bms_is_member(varno, ininfo->lefthand))
{
ininfo->lefthand = lremovei(varno, ininfo->lefthand);
ininfo->lefthand = nconc(ininfo->lefthand, listCopy(subrelids));
ininfo->lefthand = bms_del_member(ininfo->lefthand, varno);
ininfo->lefthand = bms_add_members(ininfo->lefthand, subrelids);
}
if (intMember(varno, ininfo->righthand))
if (bms_is_member(varno, ininfo->righthand))
{
ininfo->righthand = lremovei(varno, ininfo->righthand);
ininfo->righthand = nconc(ininfo->righthand, listCopy(subrelids));
ininfo->righthand = bms_del_member(ininfo->righthand, varno);
ininfo->righthand = bms_add_members(ininfo->righthand, subrelids);
}
}
}
/*
* get_relids_in_jointree: get list of base RT indexes present in a jointree
* get_relids_in_jointree: get set of base RT indexes present in a jointree
*/
List *
Relids
get_relids_in_jointree(Node *jtnode)
{
Relids result = NIL;
Relids result = NULL;
if (jtnode == NULL)
return result;
......@@ -654,21 +654,17 @@ get_relids_in_jointree(Node *jtnode)
{
int varno = ((RangeTblRef *) jtnode)->rtindex;
result = makeListi1(varno);
result = bms_make_singleton(varno);
}
else if (IsA(jtnode, FromExpr))
{
FromExpr *f = (FromExpr *) jtnode;
List *l;
/*
* Note: we assume it's impossible to see same RT index from more
* than one subtree, so nconc() is OK rather than set_unioni().
*/
foreach(l, f->fromlist)
{
result = nconc(result,
get_relids_in_jointree(lfirst(l)));
result = bms_join(result,
get_relids_in_jointree(lfirst(l)));
}
}
else if (IsA(jtnode, JoinExpr))
......@@ -677,7 +673,7 @@ get_relids_in_jointree(Node *jtnode)
/* join's own RT index is not wanted in result */
result = get_relids_in_jointree(j->larg);
result = nconc(result, get_relids_in_jointree(j->rarg));
result = bms_join(result, get_relids_in_jointree(j->rarg));
}
else
elog(ERROR, "get_relids_in_jointree: unexpected node type %d",
......@@ -686,12 +682,12 @@ get_relids_in_jointree(Node *jtnode)
}
/*
* get_relids_for_join: get list of base RT indexes making up a join
* get_relids_for_join: get set of base RT indexes making up a join
*
* NB: this will not work reliably after preprocess_jointree() is run,
* since that may eliminate join nodes from the jointree.
*/
List *
Relids
get_relids_for_join(Query *parse, int joinrelid)
{
Node *jtnode;
......
......@@ -14,7 +14,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.88 2003/01/20 18:54:54 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.89 2003/02/08 20:20:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -62,7 +62,7 @@ static List *generate_append_tlist(List *colTypes, bool flag,
List *refnames_tlist);
static Node *adjust_inherited_attrs_mutator(Node *node,
adjust_inherited_attrs_context *context);
static List *adjust_rtindex_list(List *relids, Index oldrelid, Index newrelid);
static Relids adjust_relid_set(Relids relids, Index oldrelid, Index newrelid);
static List *adjust_inherited_tlist(List *tlist, Oid new_relid);
......@@ -604,7 +604,7 @@ tlist_same_datatypes(List *tlist, List *colTypes, bool junkOK)
/*
* find_all_inheritors -
* Returns an integer list of relids including the given rel plus
* Returns an integer list of relation OIDs including the given rel plus
* all relations that inherit from it, directly or indirectly.
*/
List *
......@@ -662,6 +662,8 @@ find_all_inheritors(Oid parentrel)
* its inh flag cleared, whether or not there were any children. This
* ensures we won't expand the same RTE twice, which would otherwise occur
* for the case of an inherited UPDATE/DELETE target relation.
*
* XXX probably should convert the result type to Relids?
*/
List *
expand_inherted_rtentry(Query *parse, Index rti, bool dup_parent)
......@@ -840,13 +842,13 @@ adjust_inherited_attrs_mutator(Node *node,
ininfo = (InClauseInfo *) expression_tree_mutator(node,
adjust_inherited_attrs_mutator,
(void *) context);
/* now fix InClauseInfo's rtindex lists */
ininfo->lefthand = adjust_rtindex_list(ininfo->lefthand,
context->old_rt_index,
context->new_rt_index);
ininfo->righthand = adjust_rtindex_list(ininfo->righthand,
context->old_rt_index,
context->new_rt_index);
/* now fix InClauseInfo's relid sets */
ininfo->lefthand = adjust_relid_set(ininfo->lefthand,
context->old_rt_index,
context->new_rt_index);
ininfo->righthand = adjust_relid_set(ininfo->righthand,
context->old_rt_index,
context->new_rt_index);
return (Node *) ininfo;
}
......@@ -873,14 +875,14 @@ adjust_inherited_attrs_mutator(Node *node,
newinfo->subclauseindices = NIL;
/*
* Adjust left/right relids lists too.
* Adjust left/right relid sets too.
*/
newinfo->left_relids = adjust_rtindex_list(oldinfo->left_relids,
context->old_rt_index,
context->new_rt_index);
newinfo->right_relids = adjust_rtindex_list(oldinfo->right_relids,
context->old_rt_index,
context->new_rt_index);
newinfo->left_relids = adjust_relid_set(oldinfo->left_relids,
context->old_rt_index,
context->new_rt_index);
newinfo->right_relids = adjust_relid_set(oldinfo->right_relids,
context->old_rt_index,
context->new_rt_index);
newinfo->eval_cost.startup = -1; /* reset these too */
newinfo->this_selec = -1;
......@@ -928,18 +930,18 @@ adjust_inherited_attrs_mutator(Node *node,
}
/*
* Substitute newrelid for oldrelid in a list of RT indexes
* Substitute newrelid for oldrelid in a Relid set
*/
static List *
adjust_rtindex_list(List *relids, Index oldrelid, Index newrelid)
static Relids
adjust_relid_set(Relids relids, Index oldrelid, Index newrelid)
{
if (intMember(oldrelid, relids))
if (bms_is_member(oldrelid, relids))
{
/* Ensure we have a modifiable copy */
relids = listCopy(relids);
relids = bms_copy(relids);
/* Remove old, add new */
relids = lremovei(oldrelid, relids);
relids = lconsi(newrelid, relids);
relids = bms_del_member(relids, oldrelid);
relids = bms_add_member(relids, newrelid);
}
return relids;
}
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.127 2003/02/04 00:50:00 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.128 2003/02/08 20:20:55 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
......@@ -885,7 +885,7 @@ has_distinct_on_clause(Query *query)
* clause_get_relids_vars
* Retrieves distinct relids and vars appearing within a clause.
*
* '*relids' is set to an integer list of all distinct "varno"s appearing
* '*relids' is set to the set of all distinct "varno"s appearing
* in Vars within the clause.
* '*vars' is set to a list of all distinct Vars appearing within the clause.
* Var nodes are considered distinct if they have different varno
......@@ -899,7 +899,7 @@ void
clause_get_relids_vars(Node *clause, Relids *relids, List **vars)
{
List *clvars = pull_var_clause(clause, false);
List *varno_list = NIL;
Relids varnos = NULL;
List *var_list = NIL;
List *i;
......@@ -908,8 +908,7 @@ clause_get_relids_vars(Node *clause, Relids *relids, List **vars)
Var *var = (Var *) lfirst(i);
List *vi;
if (!intMember(var->varno, varno_list))
varno_list = lconsi(var->varno, varno_list);
varnos = bms_add_member(varnos, var->varno);
foreach(vi, var_list)
{
Var *in_list = (Var *) lfirst(vi);
......@@ -923,7 +922,7 @@ clause_get_relids_vars(Node *clause, Relids *relids, List **vars)
}
freeList(clvars);
*relids = varno_list;
*relids = varnos;
*vars = var_list;
}
......@@ -936,10 +935,10 @@ clause_get_relids_vars(Node *clause, Relids *relids, List **vars)
int
NumRelids(Node *clause)
{
List *varno_list = pull_varnos(clause);
int result = length(varno_list);
Relids varnos = pull_varnos(clause);
int result = bms_num_members(varnos);
freeList(varno_list);
bms_free(varnos);
return result;
}
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/joininfo.c,v 1.33 2003/01/24 03:58:43 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/joininfo.c,v 1.34 2003/02/08 20:20:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -35,7 +35,7 @@ find_joininfo_node(RelOptInfo *this_rel, Relids join_relids)
{
JoinInfo *joininfo = (JoinInfo *) lfirst(i);
if (sameseti(join_relids, joininfo->unjoined_relids))
if (bms_equal(join_relids, joininfo->unjoined_relids))
return joininfo;
}
return NULL;
......@@ -86,23 +86,20 @@ add_join_clause_to_rels(Query *root,
RestrictInfo *restrictinfo,
Relids join_relids)
{
List *join_relid;
Relids tmprelids;
int cur_relid;
/* For every relid, find the joininfo, and add the proper join entries */
foreach(join_relid, join_relids)
tmprelids = bms_copy(join_relids);
while ((cur_relid = bms_first_member(tmprelids)) >= 0)
{
int cur_relid = lfirsti(join_relid);
Relids unjoined_relids = NIL;
Relids unjoined_relids;
JoinInfo *joininfo;
List *otherrel;
/* Get the relids not equal to the current relid */
foreach(otherrel, join_relids)
{
if (lfirsti(otherrel) != cur_relid)
unjoined_relids = lappendi(unjoined_relids, lfirsti(otherrel));
}
Assert(unjoined_relids != NIL);
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,
......@@ -113,11 +110,12 @@ add_join_clause_to_rels(Query *root,
joininfo->jinfo_restrictinfo = lappend(joininfo->jinfo_restrictinfo,
restrictinfo);
/*
* Can't freeList(unjoined_relids) because new joininfo node may
* link to it. We could avoid leaking memory by doing listCopy()
* 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);
}
/*
......@@ -136,23 +134,20 @@ remove_join_clause_from_rels(Query *root,
RestrictInfo *restrictinfo,
Relids join_relids)
{
List *join_relid;
Relids tmprelids;
int cur_relid;
/* For every relid, find the joininfo */
foreach(join_relid, join_relids)
tmprelids = bms_copy(join_relids);
while ((cur_relid = bms_first_member(tmprelids)) >= 0)
{
int cur_relid = lfirsti(join_relid);
Relids unjoined_relids = NIL;
Relids unjoined_relids;
JoinInfo *joininfo;
List *otherrel;
/* Get the relids not equal to the current relid */
foreach(otherrel, join_relids)
{
if (lfirsti(otherrel) != cur_relid)
unjoined_relids = lappendi(unjoined_relids, lfirsti(otherrel));
}
Assert(unjoined_relids != NIL);
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
......@@ -168,6 +163,7 @@ remove_join_clause_from_rels(Query *root,
Assert(ptrMember(restrictinfo, joininfo->jinfo_restrictinfo));
joininfo->jinfo_restrictinfo = lremove(restrictinfo,
joininfo->jinfo_restrictinfo);
freeList(unjoined_relids);
bms_free(unjoined_relids);
}
bms_free(tmprelids);
}
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.86 2003/01/27 20:51:54 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.87 2003/02/08 20:20:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -560,7 +560,7 @@ create_unique_path(Query *root, RelOptInfo *rel, Path *subpath)
{
InClauseInfo *ininfo = (InClauseInfo *) lfirst(l);
if (sameseti(ininfo->righthand, rel->relids))
if (bms_equal(ininfo->righthand, rel->relids))
{
sub_targetlist = ininfo->sub_targetlist;
break;
......
......@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.77 2003/02/03 15:07:07 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.78 2003/02/08 20:20:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -52,7 +52,7 @@ void
get_relation_info(Oid relationObjectId, RelOptInfo *rel)
{
Relation relation;
Index varno = lfirsti(rel->relids);
Index varno = rel->relid;
bool hasindex;
List *varlist = NIL;
List *indexinfos = NIL;
......@@ -175,7 +175,7 @@ get_relation_info(Oid relationObjectId, RelOptInfo *rel)
}
/* initialize cached join info to empty */
info->outer_relids = NIL;
info->outer_relids = NULL;
info->inner_paths = NIL;
index_close(indexRelation);
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/relnode.c,v 1.46 2003/02/03 15:07:07 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/relnode.c,v 1.47 2003/02/08 20:20:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -54,9 +54,7 @@ build_base_rel(Query *root, int relid)
foreach(rels, root->base_rel_list)
{
rel = (RelOptInfo *) lfirst(rels);
/* length(rel->relids) == 1 for all members of base_rel_list */
if (lfirsti(rel->relids) == relid)
if (relid == rel->relid)
elog(ERROR, "build_base_rel: rel already exists");
}
......@@ -64,8 +62,7 @@ build_base_rel(Query *root, int relid)
foreach(rels, root->other_rel_list)
{
rel = (RelOptInfo *) lfirst(rels);
if (lfirsti(rel->relids) == relid)
if (relid == rel->relid)
elog(ERROR, "build_base_rel: rel already exists as 'other' rel");
}
......@@ -92,9 +89,7 @@ build_other_rel(Query *root, int relid)
foreach(rels, root->other_rel_list)
{
rel = (RelOptInfo *) lfirst(rels);
/* length(rel->relids) == 1 for all members of other_rel_list */
if (lfirsti(rel->relids) == relid)
if (relid == rel->relid)
return rel;
}
......@@ -102,8 +97,7 @@ build_other_rel(Query *root, int relid)
foreach(rels, root->base_rel_list)
{
rel = (RelOptInfo *) lfirst(rels);
if (lfirsti(rel->relids) == relid)
if (relid == rel->relid)
elog(ERROR, "build_other_rel: rel already exists as base rel");
}
......@@ -133,7 +127,7 @@ make_base_rel(Query *root, int relid)
RangeTblEntry *rte = rt_fetch(relid, root->rtable);
rel->reloptkind = RELOPT_BASEREL;
rel->relids = makeListi1(relid);
rel->relids = bms_make_singleton(relid);
rel->rows = 0;
rel->width = 0;
rel->targetlist = NIL;
......@@ -142,6 +136,7 @@ make_base_rel(Query *root, int relid)
rel->cheapest_total_path = NULL;
rel->cheapest_unique_path = NULL;
rel->pruneable = true;
rel->relid = relid;
rel->rtekind = rte->rtekind;
rel->varlist = NIL;
rel->indexlist = NIL;
......@@ -151,9 +146,9 @@ make_base_rel(Query *root, int relid)
rel->baserestrictinfo = NIL;
rel->baserestrictcost.startup = 0;
rel->baserestrictcost.per_tuple = 0;
rel->outerjoinset = NIL;
rel->outerjoinset = NULL;
rel->joininfo = NIL;
rel->index_outer_relids = NIL;
rel->index_outer_relids = NULL;
rel->index_inner_paths = NIL;
/* Check type of rtable entry */
......@@ -190,17 +185,14 @@ find_base_rel(Query *root, int relid)
foreach(rels, root->base_rel_list)
{
rel = (RelOptInfo *) lfirst(rels);
/* length(rel->relids) == 1 for all members of base_rel_list */
if (lfirsti(rel->relids) == relid)
if (relid == rel->relid)
return rel;
}
foreach(rels, root->other_rel_list)
{
rel = (RelOptInfo *) lfirst(rels);
if (lfirsti(rel->relids) == relid)
if (relid == rel->relid)
return rel;
}
......@@ -211,7 +203,7 @@ find_base_rel(Query *root, int relid)
/*
* find_join_rel
* Returns relation entry corresponding to 'relids' (a list of RT indexes),
* Returns relation entry corresponding to 'relids' (a set of RT indexes),
* or NULL if none exists. This is for join relations.
*
* Note: there is probably no good reason for this to be called from
......@@ -227,7 +219,7 @@ find_join_rel(Query *root, Relids relids)
{
RelOptInfo *rel = (RelOptInfo *) lfirst(joinrels);
if (sameseti(rel->relids, relids))
if (bms_equal(rel->relids, relids))
return rel;
}
......@@ -239,7 +231,7 @@ find_join_rel(Query *root, Relids relids)
* Returns relation entry corresponding to the union of two given rels,
* creating a new relation entry if none already exists.
*
* 'joinrelids' is the Relids list that uniquely identifies the join
* 'joinrelids' is the Relids set that uniquely identifies the join
* 'outer_rel' and 'inner_rel' are relation nodes for the relations to be
* joined
* 'jointype': type of join (inner/outer)
......@@ -252,7 +244,7 @@ find_join_rel(Query *root, Relids relids)
*/
RelOptInfo *
build_join_rel(Query *root,
List *joinrelids,
Relids joinrelids,
RelOptInfo *outer_rel,
RelOptInfo *inner_rel,
JoinType jointype,
......@@ -288,7 +280,7 @@ build_join_rel(Query *root,
*/
joinrel = makeNode(RelOptInfo);
joinrel->reloptkind = RELOPT_JOINREL;
joinrel->relids = listCopy(joinrelids);
joinrel->relids = bms_copy(joinrelids);
joinrel->rows = 0;
joinrel->width = 0;
joinrel->targetlist = NIL;
......@@ -297,6 +289,7 @@ build_join_rel(Query *root,
joinrel->cheapest_total_path = NULL;
joinrel->cheapest_unique_path = NULL;
joinrel->pruneable = true;
joinrel->relid = 0; /* indicates not a baserel */
joinrel->rtekind = RTE_JOIN;
joinrel->varlist = NIL;
joinrel->indexlist = NIL;
......@@ -306,9 +299,9 @@ build_join_rel(Query *root,
joinrel->baserestrictinfo = NIL;
joinrel->baserestrictcost.startup = 0;
joinrel->baserestrictcost.per_tuple = 0;
joinrel->outerjoinset = NIL;
joinrel->outerjoinset = NULL;
joinrel->joininfo = NIL;
joinrel->index_outer_relids = NIL;
joinrel->index_outer_relids = NULL;
joinrel->index_inner_paths = NIL;
/*
......@@ -494,7 +487,7 @@ subbuild_joinrel_restrictlist(RelOptInfo *joinrel,
{
JoinInfo *joininfo = (JoinInfo *) lfirst(xjoininfo);
if (is_subseti(joininfo->unjoined_relids, joinrel->relids))
if (bms_is_subset(joininfo->unjoined_relids, joinrel->relids))
{
/*
* Clauses in this JoinInfo list become restriction clauses
......@@ -529,15 +522,16 @@ subbuild_joinrel_joinlist(RelOptInfo *joinrel,
JoinInfo *joininfo = (JoinInfo *) lfirst(xjoininfo);
Relids new_unjoined_relids;
new_unjoined_relids = set_differencei(joininfo->unjoined_relids,
joinrel->relids);
if (new_unjoined_relids == NIL)
new_unjoined_relids = bms_difference(joininfo->unjoined_relids,
joinrel->relids);
if (bms_is_empty(new_unjoined_relids))
{
/*
* Clauses in this JoinInfo list become restriction clauses
* for the joinrel, since they refer to no outside rels. So we
* can ignore them in this routine.
*/
bms_free(new_unjoined_relids);
}
else
{
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.48 2003/02/06 22:21:11 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.49 2003/02/08 20:20:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -24,7 +24,7 @@
typedef struct
{
List *varlist;
Relids varnos;
int sublevels_up;
} pull_varnos_context;
......@@ -58,13 +58,12 @@ static bool pull_var_clause_walker(Node *node,
pull_var_clause_context *context);
static Node *flatten_join_alias_vars_mutator(Node *node,
flatten_join_alias_vars_context *context);
static List *alias_rtindex_list(Query *root, List *rtlist);
static Relids alias_relid_set(Query *root, Relids relids);
/*
* pull_varnos
*
* Create a list of all the distinct varnos present in a parsetree.
* pull_varnos
* Create a set of all the distinct varnos present in a parsetree.
* Only varnos that reference level-zero rtable entries are considered.
*
* NOTE: this is used on not-yet-planned expressions. It may therefore find
......@@ -72,12 +71,12 @@ static List *alias_rtindex_list(Query *root, List *rtlist);
* references to the desired rtable level! But when we find a completed
* SubPlan, we only need to look at the parameters passed to the subplan.
*/
List *
Relids
pull_varnos(Node *node)
{
pull_varnos_context context;
context.varlist = NIL;
context.varnos = NULL;
context.sublevels_up = 0;
/*
......@@ -89,7 +88,7 @@ pull_varnos(Node *node)
(void *) &context,
0);
return context.varlist;
return context.varnos;
}
static bool
......@@ -101,9 +100,8 @@ pull_varnos_walker(Node *node, pull_varnos_context *context)
{
Var *var = (Var *) node;
if (var->varlevelsup == context->sublevels_up &&
!intMember(var->varno, context->varlist))
context->varlist = lconsi(var->varno, context->varlist);
if (var->varlevelsup == context->sublevels_up)
context->varnos = bms_add_member(context->varnos, var->varno);
return false;
}
if (IsA(node, Query))
......@@ -430,13 +428,13 @@ flatten_join_alias_vars_mutator(Node *node,
ininfo = (InClauseInfo *) expression_tree_mutator(node,
flatten_join_alias_vars_mutator,
(void *) context);
/* now fix InClauseInfo's rtindex lists */
/* now fix InClauseInfo's relid sets */
if (context->sublevels_up == 0)
{
ininfo->lefthand = alias_rtindex_list(context->root,
ininfo->lefthand);
ininfo->righthand = alias_rtindex_list(context->root,
ininfo->righthand);
ininfo->lefthand = alias_relid_set(context->root,
ininfo->lefthand);
ininfo->righthand = alias_relid_set(context->root,
ininfo->righthand);
}
return (Node *) ininfo;
}
......@@ -462,25 +460,26 @@ flatten_join_alias_vars_mutator(Node *node,
}
/*
* alias_rtindex_list: in a list of RT indexes, replace joins by their
* alias_relid_set: in a set of RT indexes, replace joins by their
* underlying base relids
*/
static List *
alias_rtindex_list(Query *root, List *rtlist)
static Relids
alias_relid_set(Query *root, Relids relids)
{
List *result = NIL;
List *l;
Relids result = NULL;
Relids tmprelids;
int rtindex;
foreach(l, rtlist)
tmprelids = bms_copy(relids);
while ((rtindex = bms_first_member(tmprelids)) >= 0)
{
int rtindex = lfirsti(l);
RangeTblEntry *rte;
RangeTblEntry *rte = rt_fetch(rtindex, root->rtable);
rte = rt_fetch(rtindex, root->rtable);
if (rte->rtekind == RTE_JOIN)
result = nconc(result, get_relids_for_join(root, rtindex));
result = bms_join(result, get_relids_for_join(root, rtindex));
else
result = lappendi(result, rtindex);
result = bms_add_member(result, rtindex);
}
bms_free(tmprelids);
return result;
}
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.103 2002/12/16 18:39:22 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.104 2003/02/08 20:20:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -301,8 +301,8 @@ transformJoinOnClause(ParseState *pstate, JoinExpr *j,
{
Node *result;
List *save_namespace;
List *clause_varnos,
*l;
Relids clause_varnos;
int varno;
/*
* This is a tad tricky, for two reasons. First, the namespace that
......@@ -333,17 +333,15 @@ transformJoinOnClause(ParseState *pstate, JoinExpr *j,
* here.)
*/
clause_varnos = pull_varnos(result);
foreach(l, clause_varnos)
while ((varno = bms_first_member(clause_varnos)) >= 0)
{
int varno = lfirsti(l);
if (!intMember(varno, containedRels))
{
elog(ERROR, "JOIN/ON clause refers to \"%s\", which is not part of JOIN",
rt_fetch(varno, pstate->p_rtable)->eref->aliasname);
}
}
freeList(clause_varnos);
bms_free(clause_varnos);
return result;
}
......@@ -490,7 +488,7 @@ transformRangeFunction(ParseState *pstate, RangeFunction *r)
* no local Var references in the transformed expression. (Outer
* references are OK, and are ignored here.)
*/
if (pull_varnos(funcexpr) != NIL)
if (!bms_is_empty(pull_varnos(funcexpr)))
elog(ERROR, "FROM function expression may not refer to other relations of same query level");
/*
......
......@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.70 2003/01/20 18:54:59 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.71 2003/02/08 20:20:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -24,6 +24,8 @@
static bool checkExprHasAggs_walker(Node *node, void *context);
static bool checkExprHasSubLink_walker(Node *node, void *context);
static Relids offset_relid_set(Relids relids, int offset);
static Relids adjust_relid_set(Relids relids, int oldrelid, int newrelid);
/*
......@@ -143,16 +145,10 @@ OffsetVarNodes_walker(Node *node, OffsetVarNodes_context *context)
if (context->sublevels_up == 0)
{
List *rt;
foreach(rt, ininfo->lefthand)
{
lfirsti(rt) += context->offset;
}
foreach(rt, ininfo->righthand)
{
lfirsti(rt) += context->offset;
}
ininfo->lefthand = offset_relid_set(ininfo->lefthand,
context->offset);
ininfo->righthand = offset_relid_set(ininfo->righthand,
context->offset);
}
/* fall through to examine children */
}
......@@ -210,6 +206,22 @@ OffsetVarNodes(Node *node, int offset, int sublevels_up)
OffsetVarNodes_walker(node, &context);
}
static Relids
offset_relid_set(Relids relids, int offset)
{
Relids result = NULL;
Relids tmprelids;
int rtindex;
tmprelids = bms_copy(relids);
while ((rtindex = bms_first_member(tmprelids)) >= 0)
{
result = bms_add_member(result, rtindex + offset);
}
bms_free(tmprelids);
return result;
}
/*
* ChangeVarNodes - adjust Var nodes for a specific change of RT index
*
......@@ -272,18 +284,12 @@ ChangeVarNodes_walker(Node *node, ChangeVarNodes_context *context)
if (context->sublevels_up == 0)
{
List *rt;
foreach(rt, ininfo->lefthand)
{
if (lfirsti(rt) == context->rt_index)
lfirsti(rt) = context->new_index;
}
foreach(rt, ininfo->righthand)
{
if (lfirsti(rt) == context->rt_index)
lfirsti(rt) = context->new_index;
}
ininfo->lefthand = adjust_relid_set(ininfo->lefthand,
context->rt_index,
context->new_index);
ininfo->righthand = adjust_relid_set(ininfo->righthand,
context->rt_index,
context->new_index);
}
/* fall through to examine children */
}
......@@ -345,6 +351,23 @@ ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
ChangeVarNodes_walker(node, &context);
}
/*
* Substitute newrelid for oldrelid in a Relid set
*/
static Relids
adjust_relid_set(Relids relids, int oldrelid, int newrelid)
{
if (bms_is_member(oldrelid, relids))
{
/* Ensure we have a modifiable copy */
relids = bms_copy(relids);
/* Remove old, add new */
relids = bms_del_member(relids, oldrelid);
relids = bms_add_member(relids, newrelid);
}
return relids;
}
/*
* IncrementVarSublevelsUp - adjust Var nodes when pushing them down in tree
*
......@@ -468,8 +491,8 @@ rangeTableEntry_used_walker(Node *node,
InClauseInfo *ininfo = (InClauseInfo *) node;
if (context->sublevels_up == 0 &&
(intMember(context->rt_index, ininfo->lefthand) ||
intMember(context->rt_index, ininfo->righthand)))
(bms_is_member(context->rt_index, ininfo->lefthand) ||
bms_is_member(context->rt_index, ininfo->righthand)))
return true;
/* fall through to examine children */
}
......
......@@ -15,7 +15,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.131 2003/01/28 22:13:35 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.132 2003/02/08 20:20:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -3822,7 +3822,7 @@ genericcostestimate(Query *root, RelOptInfo *rel,
/* Estimate the fraction of main-table tuples that will be visited */
*indexSelectivity = clauselist_selectivity(root, selectivityQuals,
lfirsti(rel->relids),
rel->relid,
JOIN_INNER);
/*
......@@ -3909,7 +3909,7 @@ btcostestimate(PG_FUNCTION_ARGS)
Oid relid;
HeapTuple tuple;
relid = getrelid(lfirsti(rel->relids), root->rtable);
relid = getrelid(rel->relid, root->rtable);
Assert(relid != InvalidOid);
tuple = SearchSysCache(STATRELATT,
ObjectIdGetDatum(relid),
......
/*-------------------------------------------------------------------------
*
* bitmapset.h
* PostgreSQL generic bitmap set package
*
* A bitmap set can represent any set of nonnegative integers, although
* it is mainly intended for sets where the maximum value is not large,
* say at most a few hundred. By convention, a NULL pointer is always
* accepted by all operations to represent the empty set. (But beware
* that this is not the only representation of the empty set. Use
* bms_is_empty() in preference to testing for NULL.)
*
*
* Copyright (c) 2003, PostgreSQL Global Development Group
*
* $Id: bitmapset.h,v 1.1 2003/02/08 20:20:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef BITMAPSET_H
#define BITMAPSET_H
/*
* Data representation
*/
/* The unit size can be adjusted by changing these three declarations: */
#define BITS_PER_BITMAPWORD 32
typedef uint32 bitmapword; /* must be an unsigned type */
typedef int32 signedbitmapword; /* must be the matching signed type */
typedef struct Bitmapset {
int nwords; /* number of words in array */
bitmapword words[1]; /* really [nwords] */
} Bitmapset; /* VARIABLE LENGTH STRUCT */
/* result of bms_membership */
typedef enum
{
BMS_EMPTY_SET, /* 0 members */
BMS_SINGLETON, /* 1 member */
BMS_MULTIPLE /* >1 member */
} BMS_Membership;
/*
* function prototypes in nodes/bitmapset.c
*/
extern Bitmapset *bms_copy(const Bitmapset *a);
extern bool bms_equal(const Bitmapset *a, const Bitmapset *b);
extern Bitmapset *bms_make_singleton(int x);
extern void bms_free(Bitmapset *a);
extern Bitmapset *bms_union(const Bitmapset *a, const Bitmapset *b);
extern Bitmapset *bms_intersect(const Bitmapset *a, const Bitmapset *b);
extern Bitmapset *bms_difference(const Bitmapset *a, const Bitmapset *b);
extern bool bms_is_subset(const Bitmapset *a, const Bitmapset *b);
extern bool bms_is_member(int x, const Bitmapset *a);
extern bool bms_overlap(const Bitmapset *a, const Bitmapset *b);
extern int bms_singleton_member(const Bitmapset *a);
extern int bms_num_members(const Bitmapset *a);
/* optimized tests when we don't need to know exact membership count: */
extern BMS_Membership bms_membership(const Bitmapset *a);
extern bool bms_is_empty(const Bitmapset *a);
/* these routines recycle (modify or free) their non-const inputs: */
extern Bitmapset *bms_add_member(Bitmapset *a, int x);
extern Bitmapset *bms_del_member(Bitmapset *a, int x);
extern Bitmapset *bms_add_members(Bitmapset *a, const Bitmapset *b);
extern Bitmapset *bms_int_members(Bitmapset *a, const Bitmapset *b);
extern Bitmapset *bms_del_members(Bitmapset *a, const Bitmapset *b);
extern Bitmapset *bms_join(Bitmapset *a, Bitmapset *b);
/* support for iterating through the integer elements of a set: */
extern int bms_first_member(Bitmapset *a);
#endif /* BITMAPSET_H */
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: pg_list.h,v 1.33 2003/01/27 20:51:54 tgl Exp $
* $Id: pg_list.h,v 1.34 2003/02/08 20:20:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -114,7 +114,6 @@ typedef struct List
*/
extern int length(List *list);
extern void *llast(List *list);
extern int llasti(List *list);
extern List *nconc(List *list1, List *list2);
extern List *lcons(void *datum, List *list);
extern List *lconsi(int datum, List *list);
......@@ -136,20 +135,16 @@ extern void *nth(int n, List *l);
extern int nthi(int n, List *l);
extern void set_nth(List *l, int n, void *elem);
extern List *set_difference(List *list1, List *list2);
extern List *set_differencei(List *list1, List *list2);
extern List *set_ptrDifference(List *list1, List *list2);
extern List *lreverse(List *l);
extern List *set_union(List *list1, List *list2);
extern List *set_unioni(List *list1, List *list2);
extern List *set_ptrUnion(List *list1, List *list2);
extern List *set_intersect(List *l1, List *l2);
extern List *set_intersecti(List *list1, List *list2);
extern List *set_difference(List *list1, List *list2);
extern List *set_differencei(List *list1, List *list2);
extern List *set_ptrDifference(List *list1, List *list2);
extern bool equali(List *list1, List *list2);
extern bool sameseti(List *list1, List *list2);
extern bool overlap_setsi(List *list1, List *list2);
#define nonoverlap_setsi(list1, list2) (!overlap_setsi(list1, list2))
extern bool is_subseti(List *list1, List *list2);
extern void freeList(List *list);
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: relation.h,v 1.78 2003/02/03 15:07:08 tgl Exp $
* $Id: relation.h,v 1.79 2003/02/08 20:20:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -15,16 +15,16 @@
#define RELATION_H
#include "access/sdir.h"
#include "nodes/bitmapset.h"
#include "nodes/parsenodes.h"
/*
* Relids
* List of relation identifiers (indexes into the rangetable).
*
* Note: these are lists of integers, not Nodes.
* Set of relation identifiers (indexes into the rangetable).
*/
typedef List *Relids;
typedef Bitmapset *Relids;
/*
* When looking for a "cheapest path", this enum specifies whether we want
......@@ -83,7 +83,7 @@ typedef struct QualCost
* Parts of this data structure are specific to various scan and join
* mechanisms. It didn't seem worth creating new node types for them.
*
* relids - List of base-relation identifiers; it is a base relation
* relids - Set of base-relation identifiers; it is a base relation
* if there is just one, a join relation if more than one
* rows - estimated number of tuples in the relation after restriction
* clauses have been applied (ie, output rows of a plan for it)
......@@ -104,6 +104,8 @@ typedef struct QualCost
*
* If the relation is a base relation it will have these fields set:
*
* relid - RTE index (this is redundant with the relids field, but
* is provided for convenience of access)
* rtekind - distinguishes plain relation, subquery, or function RTE
* varlist - list of Vars for physical columns (only if table)
* indexlist - list of IndexOptInfo nodes for relation's indexes
......@@ -128,12 +130,12 @@ typedef struct QualCost
* baserestrictcost - Estimated cost of evaluating the baserestrictinfo
* clauses at a single tuple (only used for base rels)
* outerjoinset - For a base rel: if the rel appears within the nullable
* side of an outer join, the list of all relids
* participating in the highest such outer join; else NIL.
* side of an outer join, the set of all relids
* participating in the highest such outer join; else NULL.
* Otherwise, unused.
* joininfo - List of JoinInfo nodes, containing info about each join
* clause in which this relation participates
* index_outer_relids - only used for base rels; list of outer relids
* index_outer_relids - only used for base rels; set of outer relids
* that participate in indexable joinclauses for this rel
* index_inner_paths - only used for base rels; list of InnerIndexscanInfo
* nodes showing best indexpaths for various subsets of
......@@ -174,8 +176,7 @@ typedef struct RelOptInfo
RelOptKind reloptkind;
/* all relations included in this RelOptInfo */
Relids relids; /* integer list of base relids (rangetable
* indexes) */
Relids relids; /* set of base relids (rangetable indexes) */
/* size estimates generated by planner */
double rows; /* estimated number of result tuples */
......@@ -190,6 +191,7 @@ typedef struct RelOptInfo
bool pruneable;
/* information about a base rel (not set for join rels!) */
Index relid;
RTEKind rtekind; /* RELATION, SUBQUERY, or FUNCTION */
List *varlist;
List *indexlist;
......@@ -201,7 +203,7 @@ typedef struct RelOptInfo
List *baserestrictinfo; /* RestrictInfo structures (if
* base rel) */
QualCost baserestrictcost; /* cost of evaluating the above */
Relids outerjoinset; /* integer list of base relids */
Relids outerjoinset; /* set of base relids */
List *joininfo; /* JoinInfo structures */
/* cached info about inner indexscan paths for relation: */
......@@ -585,11 +587,11 @@ typedef struct RestrictInfo
/*
* If the clause looks useful for joining --- that is, it is a binary
* opclause with nonoverlapping sets of relids referenced in the left
* and right sides --- then these two fields are set to lists of the
* referenced relids. Otherwise they are both NIL.
* and right sides --- then these two fields are set to sets of the
* referenced relids. Otherwise they are both NULL.
*/
List *left_relids; /* relids in left side of join clause */
List *right_relids; /* relids in right side of join clause */
Relids left_relids; /* relids in left side of join clause */
Relids right_relids; /* relids in right side of join clause */
/* valid if clause is mergejoinable, else InvalidOid: */
Oid mergejoinoperator; /* copy of clause operator */
......@@ -683,8 +685,8 @@ typedef struct InnerIndexscanInfo
typedef struct InClauseInfo
{
NodeTag type;
List *lefthand; /* base relids in lefthand expressions */
List *righthand; /* base relids coming from the subselect */
Relids lefthand; /* base relids in lefthand expressions */
Relids righthand; /* base relids coming from the subselect */
List *sub_targetlist; /* targetlist of original RHS subquery */
/*
* Note: sub_targetlist is just a list of Vars or expressions;
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: pathnode.h,v 1.48 2003/01/20 18:55:05 tgl Exp $
* $Id: pathnode.h,v 1.49 2003/02/08 20:20:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -16,6 +16,7 @@
#include "nodes/relation.h"
/*
* prototypes for pathnode.c
*/
......@@ -77,10 +78,10 @@ extern void build_base_rel(Query *root, int relid);
extern RelOptInfo *build_other_rel(Query *root, int relid);
extern RelOptInfo *find_base_rel(Query *root, int relid);
extern RelOptInfo *build_join_rel(Query *root,
List *joinrelids,
RelOptInfo *outer_rel,
RelOptInfo *inner_rel,
JoinType jointype,
List **restrictlist_ptr);
Relids joinrelids,
RelOptInfo *outer_rel,
RelOptInfo *inner_rel,
JoinType jointype,
List **restrictlist_ptr);
#endif /* PATHNODE_H */
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: prep.h,v 1.35 2003/01/25 23:10:30 tgl Exp $
* $Id: prep.h,v 1.36 2003/02/08 20:20:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -16,6 +16,8 @@
#include "nodes/parsenodes.h"
#include "nodes/plannodes.h"
#include "nodes/relation.h"
/*
* prototypes for prepjointree.c
......@@ -27,8 +29,8 @@ extern Node *pull_up_IN_clauses(Query *parse, Node *node);
extern Node *pull_up_subqueries(Query *parse, Node *jtnode,
bool below_outer_join);
extern Node *preprocess_jointree(Query *parse, Node *jtnode);
extern List *get_relids_in_jointree(Node *jtnode);
extern List *get_relids_for_join(Query *parse, int joinrelid);
extern Relids get_relids_in_jointree(Node *jtnode);
extern Relids get_relids_for_join(Query *parse, int joinrelid);
/*
* prototypes for prepqual.c
......
......@@ -7,17 +7,17 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: var.h,v 1.25 2003/01/20 18:55:06 tgl Exp $
* $Id: var.h,v 1.26 2003/02/08 20:20:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef VAR_H
#define VAR_H
#include "nodes/parsenodes.h"
#include "nodes/relation.h"
extern List *pull_varnos(Node *node);
extern Relids pull_varnos(Node *node);
extern bool contain_var_reference(Node *node, int varno, int varattno,
int levelsup);
extern bool contain_whole_tuple_var(Node *node, int varno, int levelsup);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment