diff options
Diffstat (limited to 'src/backend/nodes/equalfuncs.c')
-rw-r--r-- | src/backend/nodes/equalfuncs.c | 703 |
1 files changed, 703 insertions, 0 deletions
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c new file mode 100644 index 00000000000..d2dbef2bea2 --- /dev/null +++ b/src/backend/nodes/equalfuncs.c @@ -0,0 +1,703 @@ +/*------------------------------------------------------------------------- + * + * equalfuncs.c-- + * equal functions to compare the nodes + * + * Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.1.1.1 1996/07/09 06:21:32 scrappy Exp $ + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "nodes/nodes.h" +#include "nodes/primnodes.h" +#include "nodes/relation.h" +#include "nodes/execnodes.h" +#include "nodes/plannodes.h" + +#include "utils/builtins.h" /* for namestrcmp() */ +#include "utils/datum.h" +#include "utils/elog.h" +#include "storage/itemptr.h" + +/* + * Stuff from primnodes.h + */ + +/* + * Resdom is a subclass of Node. + */ +static bool +_equalResdom(Resdom *a, Resdom *b) +{ + if (a->resno != b->resno) + return (false); + if (a->restype != b->restype) + return (false); + if (a->reslen != b->reslen) + return (false); + if (strcmp(a->resname, b->resname) != 0) + return (false); + if (a->reskey != b->reskey) + return (false); + if (a->reskeyop != b->reskeyop) + return (false); + + return (true); +} + +static bool +_equalFjoin(Fjoin *a, Fjoin *b) +{ + int nNodes; + + if (a->fj_initialized != b->fj_initialized) + return (false); + if (a->fj_nNodes != b->fj_nNodes) + return (false); + if (!equal(a->fj_innerNode, b->fj_innerNode)) + return (false); + + nNodes = a->fj_nNodes; + if (memcmp(a->fj_results, b->fj_results, nNodes*sizeof(Datum)) != 0) + return (false); + if (memcmp(a->fj_alwaysDone, b->fj_alwaysDone, nNodes*sizeof(bool)) != 0) + return (false); + + return(true); +} + +/* + * Expr is a subclass of Node. + */ +static bool +_equalExpr(Expr *a, Expr *b) +{ + if (a->opType != b->opType) + return (false); + if (!equal(a->oper, b->oper)) + return (false); + if (!equal(a->args, b->args)) + return (false); + + return (true); +} + +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 +_equalVar(Var *a, Var *b) +{ + if (a->varno != b->varno) + return (false); + if (a->varattno != b->varattno) + return (false); + if (a->vartype != b->vartype) + return (false); + if (a->varnoold != b->varnoold) + return (false); + if (a->varoattno != b->varoattno) + return (false); + + 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 +_equalOper(Oper *a, Oper *b) +{ + if (a->opno != b->opno) + return (false); + if (a->opresulttype != b->opresulttype) + return (false); + + return (true); +} + +/* + * Const is a subclass of Expr. + */ +static bool +_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) + return(false); + if (a->constlen != b->constlen) + return(false); + if (a->constisnull != b->constisnull) + return(false); + if (a->constbyval != b->constbyval) + return(false); + return(datumIsEqual(a->constvalue, b->constvalue, + a->consttype, a->constbyval, a->constlen)); +} + +/* + * Param is a subclass of Expr. + */ +static bool +_equalParam(Param *a, Param *b) +{ + if (a->paramkind != b->paramkind) + return (false); + if (a->paramtype != b->paramtype) + return (false); + if (!equal(a->param_tlist, b->param_tlist)) + return (false); + + switch (a->paramkind) { + case PARAM_NAMED: + case PARAM_NEW: + case PARAM_OLD: + if (strcmp(a->paramname, b->paramname) != 0) + return (false); + break; + case PARAM_NUM: + if (a->paramid != b->paramid) + return (false); + break; + case PARAM_INVALID: + /* + * XXX: Hmmm... What are we supposed to return + * in this case ?? + */ + return(true); + break; + default: + elog(WARN, "_equalParam: Invalid paramkind value: %d", + a->paramkind); + } + + return (true); +} + +/* + * Func is a subclass of Expr. + */ +static bool +_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); + if (!equal(a->func_tlist, b->func_tlist)) + return (false); + if (!equal(a->func_planlist, b->func_planlist)) + return (false); + + return (true); +} + +/* + * CInfo is a subclass of Node. + */ +static bool +_equalCInfo(CInfo *a, CInfo *b) +{ + Assert(IsA(a,CInfo)); + Assert(IsA(b,CInfo)); + + if (!equal(a->clause, b->clause)) + return(false); + if (a->selectivity != b->selectivity) + return(false); + if (a->notclause != b->notclause) + return(false); +#ifdef EqualMergeOrderExists + if (!EqualMergeOrder(a->mergesortorder,b->mergesortorder)) + return(false); +#endif + if(a->hashjoinoperator != b->hashjoinoperator) + return(false); + return(equal((a->indexids), + (b->indexids))); +} + +static bool +_equalJoinMethod(JoinMethod *a, JoinMethod *b) +{ + Assert(IsA(a,JoinMethod)); + Assert(IsA(b,JoinMethod)); + + if (!equal((a->jmkeys), + (b->jmkeys))) + return(false); + if (!equal((a->clauses), + (b->clauses))) + return(false); + return(true); +} + +static bool +_equalPath(Path *a, Path *b) +{ + if (a->pathtype != b->pathtype) + return(false); + if (a->parent != b->parent) + return(false); + /* + if (a->path_cost != b->path_cost) + return(false); + */ + if (a->p_ordering.ordtype == SORTOP_ORDER) { + int i = 0; + if (a->p_ordering.ord.sortop==NULL || + b->p_ordering.ord.sortop==NULL) { + + if (a->p_ordering.ord.sortop != b->p_ordering.ord.sortop) + return false; + } else { + while(a->p_ordering.ord.sortop[i]!=0 && + b->p_ordering.ord.sortop[i]!=0) { + if (a->p_ordering.ord.sortop[i] != b->p_ordering.ord.sortop[i]) + return false; + i++; + } + if (a->p_ordering.ord.sortop[i]!=0 || + b->p_ordering.ord.sortop[i]!=0) + return false; + } + } else { + if (!equal((a->p_ordering.ord.merge), + (b->p_ordering.ord.merge))) + return(false); + } + if (!equal((a->keys), + (b->keys))) + return(false); + /* + if (a->outerjoincost != b->outerjoincost) + return(false); + */ + if (!equali((a->joinid), + (b->joinid))) + return(false); + return(true); +} + +static bool +_equalIndexPath(IndexPath *a, IndexPath *b) +{ + if (!_equalPath((Path*)a,(Path*)b)) + return(false); + if (!equali((a->indexid), (b->indexid))) + return(false); + if (!equal((a->indexqual), (b->indexqual))) + return(false); + return(true); +} + +static bool +_equalJoinPath(JoinPath *a,JoinPath *b) +{ + Assert(IsA_JoinPath(a)); + Assert(IsA_JoinPath(b)); + + if (!_equalPath((Path*)a,(Path*)b)) + return(false); + if (!equal((a->pathclauseinfo), (b->pathclauseinfo))) + return(false); + if (!equal((a->outerjoinpath), (b->outerjoinpath))) + return(false); + if (!equal((a->innerjoinpath), (b->innerjoinpath))) + return(false); + return(true); +} + +static bool +_equalMergePath(MergePath *a, MergePath *b) +{ + Assert(IsA(a,MergePath)); + Assert(IsA(b,MergePath)); + + if (!_equalJoinPath((JoinPath*)a,(JoinPath*)b)) + return(false); + if (!equal((a->path_mergeclauses), (b->path_mergeclauses))) + return(false); + if (!equal((a->outersortkeys), (b->outersortkeys))) + return(false); + if (!equal((a->innersortkeys), (b->innersortkeys))) + return(false); + return(true); +} + +static bool +_equalHashPath(HashPath *a, HashPath *b) +{ + Assert(IsA(a,HashPath)); + Assert(IsA(b,HashPath)); + + if (!_equalJoinPath((JoinPath*)a,(JoinPath*)b)) + return(false); + if (!equal((a->path_hashclauses), (b->path_hashclauses))) + return(false); + if (!equal((a->outerhashkeys), (b->outerhashkeys))) + return(false); + if (!equal((a->innerhashkeys), (b->innerhashkeys))) + return(false); + return(true); +} + +static bool +_equalJoinKey(JoinKey *a, JoinKey *b) +{ + Assert(IsA(a,JoinKey)); + Assert(IsA(b,JoinKey)); + + if (!equal((a->outer),(b->outer))) + return(false); + if (!equal((a->inner),(b->inner))) + return(false); + return(true); +} + +static bool +_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) + return(false); + if (a->left_operator != b->left_operator) + return(false); + if (a->right_operator != b->right_operator) + return(false); + if (a->left_type != b->left_type) + return(false); + if (a->right_type != b->right_type) + return(false); + return(true); +} + +static bool +_equalHInfo(HInfo *a, HInfo *b) +{ + Assert(IsA(a,HInfo)); + Assert(IsA(b,HInfo)); + + if (a->hashop != b->hashop) + return(false); + return(true); +} + +/* XXX This equality function is a quick hack, should be + * fixed to compare all fields. + */ +static bool +_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 (!equal((a->indxqual),(b->indxqual))) + return(false); + + if (a->scan.scanrelid != b->scan.scanrelid) + return(false); + + if (!equali((a->indxid),(b->indxid))) + return(false); + return(true); +} + +static bool +_equalJInfo(JInfo *a, JInfo *b) +{ + Assert(IsA(a,JInfo)); + Assert(IsA(b,JInfo)); + if (!equal((a->otherrels),(b->otherrels))) + return(false); + if (!equal((a->jinfoclauseinfo),(b->jinfoclauseinfo))) + return(false); + if (a->mergesortable != b->mergesortable) + return(false); + if (a->hashjoinable != b->hashjoinable) + return(false); + return(true); +} + +/* + * Stuff from execnodes.h + */ + +/* + * EState is a subclass of Node. + */ +static bool +_equalEState(EState *a, EState *b) +{ + if (a->es_direction != b->es_direction) + return (false); + + if (!equal(a->es_range_table, b->es_range_table)) + return (false); + + if (a->es_result_relation_info != b->es_result_relation_info) + return (false); + + return (true); +} + + +/* + * equal -- are two lists equal? + * + * This is a comparison by value. It would be simpler to write it + * to be recursive, but it should run faster if we iterate. + */ +static bool +_equalValue(Value *a, Value *b) +{ + if (a->type != b->type) + return (false); + + switch(a->type) { + case T_String: + return strcmp(a->val.str, b->val.str); + case T_Integer: + return (a->val.ival==b->val.ival); + case T_Float: + return (a->val.dval==b->val.dval); + default: + break; + } + + return (true); +} + +/* + * equal-- + * returns whether two nodes are equal + */ +bool +equal(void *a, void *b) +{ + bool retval; + + if (a == b) + return(true); + /* + * note that a!=b, so only one of them can be NULL + */ + if (a==NULL || b==NULL) + return (false); + /* + * are they the same type of nodes? + */ + if (nodeTag(a)!=nodeTag(b)) + return (false); + + switch(nodeTag(a)) { + case T_Resdom: + retval = _equalResdom(a, b); + break; + case T_Fjoin: + retval = _equalFjoin(a, b); + break; + case T_Expr: + retval = _equalExpr(a, b); + break; + case T_Iter: + retval = _equalIter(a, b); + break; + case T_Stream: + retval = _equalStream(a, b); + break; + case T_Var: + retval = _equalVar(a, b); + break; + case T_Array: + retval = _equalArray(a, b); + break; + case T_ArrayRef: + retval = _equalArrayRef(a, b); + break; + case T_Oper: + retval = _equalOper(a, b); + break; + case T_Const: + retval = _equalConst(a, b); + break; + case T_Param: + retval = _equalParam(a, b); + break; + case T_Func: + retval = _equalFunc(a, b); + break; + case T_CInfo: + retval = _equalCInfo(a, b); + break; + case T_JoinMethod: + retval = _equalJoinMethod(a, b); + break; + case T_Path: + retval = _equalPath(a, b); + break; + case T_IndexPath: + retval = _equalIndexPath(a, b); + break; + case T_JoinPath: + retval = _equalJoinPath(a, b); + break; + case T_MergePath: + retval = _equalMergePath(a, b); + break; + case T_HashPath: + retval = _equalHashPath(a, b); + break; + case T_JoinKey: + retval = _equalJoinKey(a, b); + break; + case T_MergeOrder: + retval = _equalMergeOrder(a, b); + break; + case T_HInfo: + retval = _equalHInfo(a, b); + break; + case T_IndexScan: + retval = _equalIndexScan(a, b); + break; + case T_JInfo: + retval = _equalJInfo(a, b); + break; + case T_EState: + retval = _equalEState(a, b); + break; + case T_Integer: case T_String: case T_Float: + retval = _equalValue(a, b); + break; + case T_List: + { + List *la = (List*)a; + List *lb = (List*)b; + List *l; + + if (a==NULL && b==NULL) + return (true); + if (length(a)!=length(b)) + return (false); + foreach(l, la) { + if (!equal(lfirst(l), lfirst(lb))) + return (false); + lb = lnext(lb); + } + retval = true; + } + break; + default: + elog(NOTICE, "equal: don't know whether nodes of type %d are equal", + nodeTag(a)); + break; + } + + return retval; +} + +/* + * equali-- + * compares two lists of integers + * + * XXX temp hack. needs something like T_IntList + */ +bool equali(List *a, List *b) +{ + List *la = (List*)a; + List *lb = (List*)b; + List *l; + + if (a==NULL && b==NULL) + return (true); + if (length(a)!=length(b)) + return (false); + foreach(l, la) { + if (lfirsti(l) != lfirsti(lb)) + return (false); + lb = lnext(lb); + } + return true; +} |