mirror of
https://github.com/postgres/postgres.git
synced 2025-07-28 23:42:10 +03:00
Add equal() funcs for Case nodes ... amazing we had not
detected this omission before. Miscellaneous other cleanups.
This commit is contained in:
@ -1,13 +1,13 @@
|
|||||||
/*-------------------------------------------------------------------------
|
/*-------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* equalfuncs.c
|
* equalfuncs.c
|
||||||
* equal functions to compare the nodes
|
* equality functions to compare node trees
|
||||||
*
|
*
|
||||||
* Copyright (c) 1994, Regents of the University of California
|
* Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.44 1999/07/24 23:21:06 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.45 1999/07/29 02:45:36 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -20,13 +20,11 @@
|
|||||||
|
|
||||||
static bool equali(List *a, List *b);
|
static bool equali(List *a, List *b);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Stuff from primnodes.h
|
* Stuff from primnodes.h
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
* Resdom is a subclass of Node.
|
|
||||||
*/
|
|
||||||
static bool
|
static bool
|
||||||
_equalResdom(Resdom *a, Resdom *b)
|
_equalResdom(Resdom *a, Resdom *b)
|
||||||
{
|
{
|
||||||
@ -40,10 +38,11 @@ _equalResdom(Resdom *a, Resdom *b)
|
|||||||
return false;
|
return false;
|
||||||
if (a->reskey != b->reskey)
|
if (a->reskey != b->reskey)
|
||||||
return false;
|
return false;
|
||||||
if (a->resgroupref != b->resgroupref)
|
|
||||||
return false;
|
|
||||||
if (a->reskeyop != b->reskeyop)
|
if (a->reskeyop != b->reskeyop)
|
||||||
return false;
|
return false;
|
||||||
|
if (a->resgroupref != b->resgroupref)
|
||||||
|
return false;
|
||||||
|
/* we ignore resjunk flag ... is this correct? */
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -69,12 +68,13 @@ _equalFjoin(Fjoin *a, Fjoin *b)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Expr is a subclass of Node.
|
|
||||||
*/
|
|
||||||
static bool
|
static bool
|
||||||
_equalExpr(Expr *a, Expr *b)
|
_equalExpr(Expr *a, Expr *b)
|
||||||
{
|
{
|
||||||
|
/* We do not examine typeOid, since the optimizer often doesn't
|
||||||
|
* bother to set it in created nodes, and it is logically a
|
||||||
|
* derivative of the oper field anyway.
|
||||||
|
*/
|
||||||
if (a->opType != b->opType)
|
if (a->opType != b->opType)
|
||||||
return false;
|
return false;
|
||||||
if (!equal(a->oper, b->oper))
|
if (!equal(a->oper, b->oper))
|
||||||
@ -85,35 +85,6 @@ _equalExpr(Expr *a, Expr *b)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
|
||||||
_equalIter(Iter *a, Iter *b)
|
|
||||||
{
|
|
||||||
return equal(a->iterexpr, b->iterexpr);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
_equalStream(Stream *a, Stream *b)
|
|
||||||
{
|
|
||||||
if (a->clausetype != b->clausetype)
|
|
||||||
return false;
|
|
||||||
if (a->groupup != b->groupup)
|
|
||||||
return false;
|
|
||||||
if (a->groupcost != b->groupcost)
|
|
||||||
return false;
|
|
||||||
if (a->groupsel != b->groupsel)
|
|
||||||
return false;
|
|
||||||
if (!equal(a->pathptr, b->pathptr))
|
|
||||||
return false;
|
|
||||||
if (!equal(a->cinfo, b->cinfo))
|
|
||||||
return false;
|
|
||||||
if (!equal(a->upstream, b->upstream))
|
|
||||||
return false;
|
|
||||||
return equal(a->downstream, b->downstream);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Var is a subclass of Expr.
|
|
||||||
*/
|
|
||||||
static bool
|
static bool
|
||||||
_equalVar(Var *a, Var *b)
|
_equalVar(Var *a, Var *b)
|
||||||
{
|
{
|
||||||
@ -135,45 +106,6 @@ _equalVar(Var *a, Var *b)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
|
||||||
_equalArray(Array *a, Array *b)
|
|
||||||
{
|
|
||||||
if (a->arrayelemtype != b->arrayelemtype)
|
|
||||||
return false;
|
|
||||||
if (a->arrayndim != b->arrayndim)
|
|
||||||
return false;
|
|
||||||
if (a->arraylow.indx[0] != b->arraylow.indx[0])
|
|
||||||
return false;
|
|
||||||
if (a->arrayhigh.indx[0] != b->arrayhigh.indx[0])
|
|
||||||
return false;
|
|
||||||
if (a->arraylen != b->arraylen)
|
|
||||||
return false;
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
_equalArrayRef(ArrayRef *a, ArrayRef *b)
|
|
||||||
{
|
|
||||||
if (a->refelemtype != b->refelemtype)
|
|
||||||
return false;
|
|
||||||
if (a->refattrlength != b->refattrlength)
|
|
||||||
return false;
|
|
||||||
if (a->refelemlength != b->refelemlength)
|
|
||||||
return false;
|
|
||||||
if (a->refelembyval != b->refelembyval)
|
|
||||||
return false;
|
|
||||||
if (!equal(a->refupperindexpr, b->refupperindexpr))
|
|
||||||
return false;
|
|
||||||
if (!equal(a->reflowerindexpr, b->reflowerindexpr))
|
|
||||||
return false;
|
|
||||||
if (!equal(a->refexpr, b->refexpr))
|
|
||||||
return false;
|
|
||||||
return equal(a->refassgnexpr, b->refassgnexpr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Oper is a subclass of Expr.
|
|
||||||
*/
|
|
||||||
static bool
|
static bool
|
||||||
_equalOper(Oper *a, Oper *b)
|
_equalOper(Oper *a, Oper *b)
|
||||||
{
|
{
|
||||||
@ -181,21 +113,19 @@ _equalOper(Oper *a, Oper *b)
|
|||||||
return false;
|
return false;
|
||||||
if (a->opresulttype != b->opresulttype)
|
if (a->opresulttype != b->opresulttype)
|
||||||
return false;
|
return false;
|
||||||
|
/* We do not examine opid, opsize, or op_fcache, since these are
|
||||||
|
* logically derived from opno, and they may not be set yet depending
|
||||||
|
* on how far along the node is in the parse/plan pipeline.
|
||||||
|
*
|
||||||
|
* It's probably not really necessary to check opresulttype either...
|
||||||
|
*/
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Const is a subclass of Expr.
|
|
||||||
*/
|
|
||||||
static bool
|
static bool
|
||||||
_equalConst(Const *a, Const *b)
|
_equalConst(Const *a, Const *b)
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
|
||||||
* * this function used to do a pointer compare on a and b. That's *
|
|
||||||
* ridiculous. -- JMH, 7/11/92
|
|
||||||
*/
|
|
||||||
if (a->consttype != b->consttype)
|
if (a->consttype != b->consttype)
|
||||||
return false;
|
return false;
|
||||||
if (a->constlen != b->constlen)
|
if (a->constlen != b->constlen)
|
||||||
@ -204,13 +134,11 @@ _equalConst(Const *a, Const *b)
|
|||||||
return false;
|
return false;
|
||||||
if (a->constbyval != b->constbyval)
|
if (a->constbyval != b->constbyval)
|
||||||
return false;
|
return false;
|
||||||
|
/* XXX What about constisset and constiscast? */
|
||||||
return (datumIsEqual(a->constvalue, b->constvalue,
|
return (datumIsEqual(a->constvalue, b->constvalue,
|
||||||
a->consttype, a->constbyval, a->constlen));
|
a->consttype, a->constbyval, a->constlen));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Param is a subclass of Expr.
|
|
||||||
*/
|
|
||||||
static bool
|
static bool
|
||||||
_equalParam(Param *a, Param *b)
|
_equalParam(Param *a, Param *b)
|
||||||
{
|
{
|
||||||
@ -249,9 +177,26 @@ _equalParam(Param *a, Param *b)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static bool
|
||||||
* Aggref is a subclass of Expr.
|
_equalFunc(Func *a, Func *b)
|
||||||
*/
|
{
|
||||||
|
if (a->funcid != b->funcid)
|
||||||
|
return false;
|
||||||
|
if (a->functype != b->functype)
|
||||||
|
return false;
|
||||||
|
if (a->funcisindex != b->funcisindex)
|
||||||
|
return false;
|
||||||
|
if (a->funcsize != b->funcsize)
|
||||||
|
return false;
|
||||||
|
/* Note we do not look at func_fcache */
|
||||||
|
if (!equal(a->func_tlist, b->func_tlist))
|
||||||
|
return false;
|
||||||
|
if (!equal(a->func_planlist, b->func_planlist))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
_equalAggref(Aggref *a, Aggref *b)
|
_equalAggref(Aggref *a, Aggref *b)
|
||||||
{
|
{
|
||||||
@ -270,68 +215,61 @@ _equalAggref(Aggref *a, Aggref *b)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Func is a subclass of Expr.
|
|
||||||
*/
|
|
||||||
static bool
|
static bool
|
||||||
_equalFunc(Func *a, Func *b)
|
_equalArray(Array *a, Array *b)
|
||||||
{
|
{
|
||||||
if (a->funcid != b->funcid)
|
if (a->arrayelemtype != b->arrayelemtype)
|
||||||
return false;
|
return false;
|
||||||
if (a->functype != b->functype)
|
/* We need not check arrayelemlength, arrayelembyval if types match */
|
||||||
|
if (a->arrayndim != b->arrayndim)
|
||||||
return false;
|
return false;
|
||||||
if (a->funcisindex != b->funcisindex)
|
/* XXX shouldn't we be checking all indices??? */
|
||||||
|
if (a->arraylow.indx[0] != b->arraylow.indx[0])
|
||||||
return false;
|
return false;
|
||||||
if (a->funcsize != b->funcsize)
|
if (a->arrayhigh.indx[0] != b->arrayhigh.indx[0])
|
||||||
return false;
|
return false;
|
||||||
if (!equal(a->func_tlist, b->func_tlist))
|
if (a->arraylen != b->arraylen)
|
||||||
return false;
|
|
||||||
if (!equal(a->func_planlist, b->func_planlist))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* RestrictInfo is a subclass of Node.
|
|
||||||
*/
|
|
||||||
static bool
|
static bool
|
||||||
_equalRestrictInfo(RestrictInfo *a, RestrictInfo *b)
|
_equalArrayRef(ArrayRef *a, ArrayRef *b)
|
||||||
{
|
{
|
||||||
Assert(IsA(a, RestrictInfo));
|
if (a->refelemtype != b->refelemtype)
|
||||||
Assert(IsA(b, RestrictInfo));
|
|
||||||
|
|
||||||
if (!equal(a->clause, b->clause))
|
|
||||||
return false;
|
return false;
|
||||||
if (a->selectivity != b->selectivity)
|
if (a->refattrlength != b->refattrlength)
|
||||||
return false;
|
return false;
|
||||||
#ifdef EqualMergeOrderExists
|
if (a->refelemlength != b->refelemlength)
|
||||||
if (!EqualMergeOrder(a->mergejoinorder, b->mergejoinorder))
|
|
||||||
return false;
|
return false;
|
||||||
#endif
|
if (a->refelembyval != b->refelembyval)
|
||||||
if (a->hashjoinoperator != b->hashjoinoperator)
|
|
||||||
return false;
|
return false;
|
||||||
return equal(a->indexids, b->indexids);
|
if (!equal(a->refupperindexpr, b->refupperindexpr))
|
||||||
|
return false;
|
||||||
|
if (!equal(a->reflowerindexpr, b->reflowerindexpr))
|
||||||
|
return false;
|
||||||
|
if (!equal(a->refexpr, b->refexpr))
|
||||||
|
return false;
|
||||||
|
return equal(a->refassgnexpr, b->refassgnexpr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* RelOptInfo is a subclass of Node.
|
* Stuff from relation.h
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
_equalRelOptInfo(RelOptInfo *a, RelOptInfo *b)
|
_equalRelOptInfo(RelOptInfo *a, RelOptInfo *b)
|
||||||
{
|
{
|
||||||
Assert(IsA(a, RelOptInfo));
|
/* We treat RelOptInfos as equal if they refer to the same base rels
|
||||||
Assert(IsA(b, RelOptInfo));
|
* joined in the same order. Is this sufficient?
|
||||||
|
*/
|
||||||
return equal(a->relids, b->relids);
|
return equal(a->relids, b->relids);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
_equalJoinMethod(JoinMethod *a, JoinMethod *b)
|
_equalJoinMethod(JoinMethod *a, JoinMethod *b)
|
||||||
{
|
{
|
||||||
Assert(IsA(a, JoinMethod));
|
|
||||||
Assert(IsA(b, JoinMethod));
|
|
||||||
|
|
||||||
if (!equal(a->jmkeys, b->jmkeys))
|
if (!equal(a->jmkeys, b->jmkeys))
|
||||||
return false;
|
return false;
|
||||||
if (!equal(a->clauses, b->clauses))
|
if (!equal(a->clauses, b->clauses))
|
||||||
@ -344,16 +282,17 @@ _equalPath(Path *a, Path *b)
|
|||||||
{
|
{
|
||||||
if (a->pathtype != b->pathtype)
|
if (a->pathtype != b->pathtype)
|
||||||
return false;
|
return false;
|
||||||
if (a->parent != b->parent)
|
if (a->parent != b->parent) /* should this use equal() ? */
|
||||||
return false;
|
return false;
|
||||||
|
/* do not check path_cost, since it may not be set yet, and being
|
||||||
/*
|
* a float there are roundoff error issues anyway...
|
||||||
* if (a->path_cost != b->path_cost) return(false);
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* XXX this should probably be in an _equalPathOrder function... */
|
||||||
|
if (a->pathorder->ordtype != b->pathorder->ordtype)
|
||||||
|
return false;
|
||||||
if (a->pathorder->ordtype == SORTOP_ORDER)
|
if (a->pathorder->ordtype == SORTOP_ORDER)
|
||||||
{
|
{
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
if (a->pathorder->ord.sortop == NULL ||
|
if (a->pathorder->ord.sortop == NULL ||
|
||||||
b->pathorder->ord.sortop == NULL)
|
b->pathorder->ord.sortop == NULL)
|
||||||
{
|
{
|
||||||
@ -362,15 +301,15 @@ _equalPath(Path *a, Path *b)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
while (a->pathorder->ord.sortop[i] != 0 &&
|
int i = 0;
|
||||||
b->pathorder->ord.sortop[i] != 0)
|
|
||||||
|
while (a->pathorder->ord.sortop[i] != 0)
|
||||||
{
|
{
|
||||||
if (a->pathorder->ord.sortop[i] != b->pathorder->ord.sortop[i])
|
if (a->pathorder->ord.sortop[i] != b->pathorder->ord.sortop[i])
|
||||||
return false;
|
return false;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
if (a->pathorder->ord.sortop[i] != 0 ||
|
if (b->pathorder->ord.sortop[i] != 0)
|
||||||
b->pathorder->ord.sortop[i] != 0)
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -379,12 +318,10 @@ _equalPath(Path *a, Path *b)
|
|||||||
if (!equal(a->pathorder->ord.merge, b->pathorder->ord.merge))
|
if (!equal(a->pathorder->ord.merge, b->pathorder->ord.merge))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!equal(a->pathkeys, b->pathkeys))
|
if (!equal(a->pathkeys, b->pathkeys))
|
||||||
return false;
|
return false;
|
||||||
|
/* do not check outerjoincost either */
|
||||||
/*
|
|
||||||
* if (a->outerjoincost != b->outerjoincost) return(false);
|
|
||||||
*/
|
|
||||||
if (!equali(a->joinid, b->joinid))
|
if (!equali(a->joinid, b->joinid))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
@ -399,15 +336,13 @@ _equalIndexPath(IndexPath *a, IndexPath *b)
|
|||||||
return false;
|
return false;
|
||||||
if (!equal(a->indexqual, b->indexqual))
|
if (!equal(a->indexqual, b->indexqual))
|
||||||
return false;
|
return false;
|
||||||
|
/* We do not need to check indexkeys */
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
_equalNestPath(NestPath *a, NestPath *b)
|
_equalNestPath(NestPath *a, NestPath *b)
|
||||||
{
|
{
|
||||||
Assert(IsA_JoinPath(a));
|
|
||||||
Assert(IsA_JoinPath(b));
|
|
||||||
|
|
||||||
if (!_equalPath((Path *) a, (Path *) b))
|
if (!_equalPath((Path *) a, (Path *) b))
|
||||||
return false;
|
return false;
|
||||||
if (!equal(a->pathinfo, b->pathinfo))
|
if (!equal(a->pathinfo, b->pathinfo))
|
||||||
@ -422,9 +357,6 @@ _equalNestPath(NestPath *a, NestPath *b)
|
|||||||
static bool
|
static bool
|
||||||
_equalMergePath(MergePath *a, MergePath *b)
|
_equalMergePath(MergePath *a, MergePath *b)
|
||||||
{
|
{
|
||||||
Assert(IsA(a, MergePath));
|
|
||||||
Assert(IsA(b, MergePath));
|
|
||||||
|
|
||||||
if (!_equalNestPath((NestPath *) a, (NestPath *) b))
|
if (!_equalNestPath((NestPath *) a, (NestPath *) b))
|
||||||
return false;
|
return false;
|
||||||
if (!equal(a->path_mergeclauses, b->path_mergeclauses))
|
if (!equal(a->path_mergeclauses, b->path_mergeclauses))
|
||||||
@ -439,12 +371,9 @@ _equalMergePath(MergePath *a, MergePath *b)
|
|||||||
static bool
|
static bool
|
||||||
_equalHashPath(HashPath *a, HashPath *b)
|
_equalHashPath(HashPath *a, HashPath *b)
|
||||||
{
|
{
|
||||||
Assert(IsA(a, HashPath));
|
|
||||||
Assert(IsA(b, HashPath));
|
|
||||||
|
|
||||||
if (!_equalNestPath((NestPath *) a, (NestPath *) b))
|
if (!_equalNestPath((NestPath *) a, (NestPath *) b))
|
||||||
return false;
|
return false;
|
||||||
if (!equal((a->path_hashclauses), (b->path_hashclauses)))
|
if (!equal(a->path_hashclauses, b->path_hashclauses))
|
||||||
return false;
|
return false;
|
||||||
if (!equal(a->outerhashkeys, b->outerhashkeys))
|
if (!equal(a->outerhashkeys, b->outerhashkeys))
|
||||||
return false;
|
return false;
|
||||||
@ -456,9 +385,6 @@ _equalHashPath(HashPath *a, HashPath *b)
|
|||||||
static bool
|
static bool
|
||||||
_equalJoinKey(JoinKey *a, JoinKey *b)
|
_equalJoinKey(JoinKey *a, JoinKey *b)
|
||||||
{
|
{
|
||||||
Assert(IsA(a, JoinKey));
|
|
||||||
Assert(IsA(b, JoinKey));
|
|
||||||
|
|
||||||
if (!equal(a->outer, b->outer))
|
if (!equal(a->outer, b->outer))
|
||||||
return false;
|
return false;
|
||||||
if (!equal(a->inner, b->inner))
|
if (!equal(a->inner, b->inner))
|
||||||
@ -469,11 +395,6 @@ _equalJoinKey(JoinKey *a, JoinKey *b)
|
|||||||
static bool
|
static bool
|
||||||
_equalMergeOrder(MergeOrder *a, MergeOrder *b)
|
_equalMergeOrder(MergeOrder *a, MergeOrder *b)
|
||||||
{
|
{
|
||||||
if (a == (MergeOrder *) NULL && b == (MergeOrder *) NULL)
|
|
||||||
return true;
|
|
||||||
Assert(IsA(a, MergeOrder));
|
|
||||||
Assert(IsA(b, MergeOrder));
|
|
||||||
|
|
||||||
if (a->join_operator != b->join_operator)
|
if (a->join_operator != b->join_operator)
|
||||||
return false;
|
return false;
|
||||||
if (a->left_operator != b->left_operator)
|
if (a->left_operator != b->left_operator)
|
||||||
@ -490,9 +411,8 @@ _equalMergeOrder(MergeOrder *a, MergeOrder *b)
|
|||||||
static bool
|
static bool
|
||||||
_equalHashInfo(HashInfo *a, HashInfo *b)
|
_equalHashInfo(HashInfo *a, HashInfo *b)
|
||||||
{
|
{
|
||||||
Assert(IsA(a, HashInfo));
|
if (!_equalJoinMethod((JoinMethod *) a, (JoinMethod *) b))
|
||||||
Assert(IsA(b, HashInfo));
|
return false;
|
||||||
|
|
||||||
if (a->hashop != b->hashop)
|
if (a->hashop != b->hashop)
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
@ -500,13 +420,13 @@ _equalHashInfo(HashInfo *a, HashInfo *b)
|
|||||||
|
|
||||||
/* XXX This equality function is a quick hack, should be
|
/* XXX This equality function is a quick hack, should be
|
||||||
* fixed to compare all fields.
|
* fixed to compare all fields.
|
||||||
|
*
|
||||||
|
* XXX Why is this even here? We don't have equal() funcs for
|
||||||
|
* any other kinds of Plan nodes... likely this is dead code...
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
_equalIndexScan(IndexScan *a, IndexScan *b)
|
_equalIndexScan(IndexScan *a, IndexScan *b)
|
||||||
{
|
{
|
||||||
Assert(IsA(a, IndexScan));
|
|
||||||
Assert(IsA(b, IndexScan));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if(a->scan.plan.cost != b->scan.plan.cost) return(false);
|
* if(a->scan.plan.cost != b->scan.plan.cost) return(false);
|
||||||
*/
|
*/
|
||||||
@ -537,8 +457,6 @@ _equalSubPlan(SubPlan *a, SubPlan *b)
|
|||||||
static bool
|
static bool
|
||||||
_equalJoinInfo(JoinInfo *a, JoinInfo *b)
|
_equalJoinInfo(JoinInfo *a, JoinInfo *b)
|
||||||
{
|
{
|
||||||
Assert(IsA(a, JoinInfo));
|
|
||||||
Assert(IsA(b, JoinInfo));
|
|
||||||
if (!equal(a->unjoined_relids, b->unjoined_relids))
|
if (!equal(a->unjoined_relids, b->unjoined_relids))
|
||||||
return false;
|
return false;
|
||||||
if (!equal(a->jinfo_restrictinfo, b->jinfo_restrictinfo))
|
if (!equal(a->jinfo_restrictinfo, b->jinfo_restrictinfo))
|
||||||
@ -550,6 +468,45 @@ _equalJoinInfo(JoinInfo *a, JoinInfo *b)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
_equalRestrictInfo(RestrictInfo *a, RestrictInfo *b)
|
||||||
|
{
|
||||||
|
if (!equal(a->clause, b->clause))
|
||||||
|
return false;
|
||||||
|
/* do not check selectivity because of roundoff error worries */
|
||||||
|
if (!equal(a->mergejoinorder, b->mergejoinorder))
|
||||||
|
return false;
|
||||||
|
if (a->hashjoinoperator != b->hashjoinoperator)
|
||||||
|
return false;
|
||||||
|
return equal(a->indexids, b->indexids);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
_equalIter(Iter *a, Iter *b)
|
||||||
|
{
|
||||||
|
return equal(a->iterexpr, b->iterexpr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
_equalStream(Stream *a, Stream *b)
|
||||||
|
{
|
||||||
|
if (a->clausetype != b->clausetype)
|
||||||
|
return false;
|
||||||
|
if (a->groupup != b->groupup)
|
||||||
|
return false;
|
||||||
|
if (a->groupcost != b->groupcost)
|
||||||
|
return false;
|
||||||
|
if (a->groupsel != b->groupsel)
|
||||||
|
return false;
|
||||||
|
if (!equal(a->pathptr, b->pathptr))
|
||||||
|
return false;
|
||||||
|
if (!equal(a->cinfo, b->cinfo))
|
||||||
|
return false;
|
||||||
|
if (!equal(a->upstream, b->upstream))
|
||||||
|
return false;
|
||||||
|
return equal(a->downstream, b->downstream);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Stuff from execnodes.h
|
* Stuff from execnodes.h
|
||||||
*/
|
*/
|
||||||
@ -696,6 +653,32 @@ _equalTargetEntry(TargetEntry *a, TargetEntry *b)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
_equalCaseExpr(CaseExpr *a, CaseExpr *b)
|
||||||
|
{
|
||||||
|
if (a->casetype != b->casetype)
|
||||||
|
return false;
|
||||||
|
if (!equal(a->arg, b->arg))
|
||||||
|
return false;
|
||||||
|
if (!equal(a->args, b->args))
|
||||||
|
return false;
|
||||||
|
if (!equal(a->defresult, b->defresult))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
_equalCaseWhen(CaseWhen *a, CaseWhen *b)
|
||||||
|
{
|
||||||
|
if (!equal(a->expr, b->expr))
|
||||||
|
return false;
|
||||||
|
if (!equal(a->result, b->result))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Stuff from pg_list.h
|
* Stuff from pg_list.h
|
||||||
*/
|
*/
|
||||||
@ -842,9 +825,10 @@ equal(void *a, void *b)
|
|||||||
List *lb = (List *) b;
|
List *lb = (List *) b;
|
||||||
List *l;
|
List *l;
|
||||||
|
|
||||||
if (a == NULL && b == NULL)
|
/* Try to reject by length check before we grovel through
|
||||||
return true;
|
* all the elements...
|
||||||
if (length(a) != length(b))
|
*/
|
||||||
|
if (length(la) != length(lb))
|
||||||
return false;
|
return false;
|
||||||
foreach(l, la)
|
foreach(l, la)
|
||||||
{
|
{
|
||||||
@ -864,6 +848,12 @@ equal(void *a, void *b)
|
|||||||
case T_TargetEntry:
|
case T_TargetEntry:
|
||||||
retval = _equalTargetEntry(a, b);
|
retval = _equalTargetEntry(a, b);
|
||||||
break;
|
break;
|
||||||
|
case T_CaseExpr:
|
||||||
|
retval = _equalCaseExpr(a, b);
|
||||||
|
break;
|
||||||
|
case T_CaseWhen:
|
||||||
|
retval = _equalCaseWhen(a, b);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
elog(NOTICE, "equal: don't know whether nodes of type %d are equal",
|
elog(NOTICE, "equal: don't know whether nodes of type %d are equal",
|
||||||
nodeTag(a));
|
nodeTag(a));
|
||||||
@ -876,25 +866,21 @@ equal(void *a, void *b)
|
|||||||
/*
|
/*
|
||||||
* equali
|
* equali
|
||||||
* compares two lists of integers
|
* compares two lists of integers
|
||||||
*
|
|
||||||
* XXX temp hack. needs something like T_IntList
|
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
equali(List *a, List *b)
|
equali(List *a, List *b)
|
||||||
{
|
{
|
||||||
List *la = (List *) a;
|
|
||||||
List *lb = (List *) b;
|
|
||||||
List *l;
|
List *l;
|
||||||
|
|
||||||
if (a == NULL && b == NULL)
|
foreach(l, a)
|
||||||
return true;
|
|
||||||
if (length(a) != length(b))
|
|
||||||
return false;
|
|
||||||
foreach(l, la)
|
|
||||||
{
|
{
|
||||||
if (lfirsti(l) != lfirsti(lb))
|
if (b == NIL)
|
||||||
return false;
|
return false;
|
||||||
lb = lnext(lb);
|
if (lfirsti(l) != lfirsti(b))
|
||||||
|
return false;
|
||||||
|
b = lnext(b);
|
||||||
}
|
}
|
||||||
|
if (b != NIL)
|
||||||
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user