equalfuncs.c 17 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * equalfuncs.c
4
 *	  equal functions to compare the nodes
5 6 7 8 9
 *
 * Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
10
 *	  $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.36 1999/05/12 15:01:33 wieck Exp $
11 12 13
 *
 *-------------------------------------------------------------------------
 */
14 15
#include <string.h>

16 17 18 19 20 21 22 23 24 25 26 27 28
#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"

29
static bool equali(List *a, List *b);
30

31
/*
32
 *	Stuff from primnodes.h
33 34 35
 */

/*
36
 *	Resdom is a subclass of Node.
37
 */
38
static bool
39
_equalResdom(Resdom *a, Resdom *b)
40
{
41
	if (a->resno != b->resno)
42
		return false;
43
	if (a->restype != b->restype)
44
		return false;
45
	if (a->restypmod != b->restypmod)
46
		return false;
47
	if (strcmp(a->resname, b->resname) != 0)
48
		return false;
49
	if (a->reskey != b->reskey)
50
		return false;
51 52
	if (a->resgroupref != b->resgroupref)
		return false;
53
	if (a->reskeyop != b->reskeyop)
54
		return false;
55

56
	return true;
57 58
}

59
static bool
60
_equalFjoin(Fjoin *a, Fjoin *b)
61
{
62
	int			nNodes;
63 64

	if (a->fj_initialized != b->fj_initialized)
65
		return false;
66
	if (a->fj_nNodes != b->fj_nNodes)
67
		return false;
68
	if (!equal(a->fj_innerNode, b->fj_innerNode))
69
		return false;
70 71 72

	nNodes = a->fj_nNodes;
	if (memcmp(a->fj_results, b->fj_results, nNodes * sizeof(Datum)) != 0)
73
		return false;
74
	if (memcmp(a->fj_alwaysDone, b->fj_alwaysDone, nNodes * sizeof(bool)) != 0)
75
		return false;
76

77
	return true;
78 79 80
}

/*
81
 *	Expr is a subclass of Node.
82
 */
83
static bool
84
_equalExpr(Expr *a, Expr *b)
85
{
86
	if (a->opType != b->opType)
87
		return false;
88
	if (!equal(a->oper, b->oper))
89
		return false;
90
	if (!equal(a->args, b->args))
91
		return false;
92

93
	return true;
94 95
}

96
static bool
97
_equalIter(Iter *a, Iter *b)
98
{
99
	return equal(a->iterexpr, b->iterexpr);
100 101
}

102
static bool
103
_equalStream(Stream *a, Stream *b)
104
{
105
	if (a->clausetype != b->clausetype)
106
		return false;
107
	if (a->groupup != b->groupup)
108
		return false;
109
	if (a->groupcost != b->groupcost)
110
		return false;
111
	if (a->groupsel != b->groupsel)
112
		return false;
113
	if (!equal(a->pathptr, b->pathptr))
114
		return false;
115
	if (!equal(a->cinfo, b->cinfo))
116
		return false;
117
	if (!equal(a->upstream, b->upstream))
118 119
		return false;
	return equal(a->downstream, b->downstream);
120 121 122
}

/*
123
 *	Var is a subclass of Expr.
124
 */
125
static bool
126
_equalVar(Var *a, Var *b)
127
{
128
	if (a->varno != b->varno)
129
		return false;
130
	if (a->varattno != b->varattno)
131
		return false;
132
	if (a->vartype != b->vartype)
133
		return false;
134
	if (a->vartypmod != b->vartypmod)
135
		return false;
136
	if (a->varlevelsup != b->varlevelsup)
137
		return false;
138
	if (a->varnoold != b->varnoold)
139
		return false;
140
	if (a->varoattno != b->varoattno)
141
		return false;
142

143
	return true;
144 145
}

146
static bool
Bruce Momjian's avatar
Bruce Momjian committed
147
_equalArray(Array *a, Array *b)
148
{
149
	if (a->arrayelemtype != b->arrayelemtype)
150
		return false;
151
	if (a->arrayndim != b->arrayndim)
152
		return false;
153
	if (a->arraylow.indx[0] != b->arraylow.indx[0])
154
		return false;
155
	if (a->arrayhigh.indx[0] != b->arrayhigh.indx[0])
156
		return false;
157
	if (a->arraylen != b->arraylen)
158 159
		return false;
	return TRUE;
160 161
}

162
static bool
Bruce Momjian's avatar
Bruce Momjian committed
163
_equalArrayRef(ArrayRef *a, ArrayRef *b)
164
{
165
	if (a->refelemtype != b->refelemtype)
166
		return false;
167
	if (a->refattrlength != b->refattrlength)
168
		return false;
169
	if (a->refelemlength != b->refelemlength)
170
		return false;
171
	if (a->refelembyval != b->refelembyval)
172
		return false;
173
	if (!equal(a->refupperindexpr, b->refupperindexpr))
174
		return false;
175
	if (!equal(a->reflowerindexpr, b->reflowerindexpr))
176
		return false;
177
	if (!equal(a->refexpr, b->refexpr))
178 179
		return false;
	return equal(a->refassgnexpr, b->refassgnexpr);
180 181 182
}

/*
183
 *	Oper is a subclass of Expr.
184
 */
185
static bool
186
_equalOper(Oper *a, Oper *b)
187
{
188
	if (a->opno != b->opno)
189
		return false;
190
	if (a->opresulttype != b->opresulttype)
191
		return false;
192

193
	return true;
194 195 196
}

/*
197
 *	Const is a subclass of Expr.
198
 */
199
static bool
200
_equalConst(Const *a, Const *b)
201
{
202 203 204 205 206 207

	/*
	 * * this function used to do a pointer compare on a and b.  That's *
	 * ridiculous.	-- JMH, 7/11/92
	 */
	if (a->consttype != b->consttype)
208
		return false;
209
	if (a->constlen != b->constlen)
210
		return false;
211
	if (a->constisnull != b->constisnull)
212
		return false;
213
	if (a->constbyval != b->constbyval)
214
		return false;
215 216
	return (datumIsEqual(a->constvalue, b->constvalue,
						 a->consttype, a->constbyval, a->constlen));
217 218 219
}

/*
220
 *	Param is a subclass of Expr.
221
 */
222
static bool
223
_equalParam(Param *a, Param *b)
224
{
225
	if (a->paramkind != b->paramkind)
226
		return false;
227
	if (a->paramtype != b->paramtype)
228
		return false;
229
	if (!equal(a->param_tlist, b->param_tlist))
230
		return false;
231 232 233

	switch (a->paramkind)
	{
234 235 236 237
		case PARAM_NAMED:
		case PARAM_NEW:
		case PARAM_OLD:
			if (strcmp(a->paramname, b->paramname) != 0)
238
				return false;
239 240
			break;
		case PARAM_NUM:
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
241
		case PARAM_EXEC:
242
			if (a->paramid != b->paramid)
243
				return false;
244 245 246 247 248 249
			break;
		case PARAM_INVALID:

			/*
			 * XXX: Hmmm... What are we supposed to return in this case ??
			 */
250
			return true;
251 252
			break;
		default:
253
			elog(ERROR, "_equalParam: Invalid paramkind value: %d",
254
				 a->paramkind);
255 256
	}

257
	return true;
258 259 260
}

/*
261
 *	Func is a subclass of Expr.
262
 */
263
static bool
264
_equalFunc(Func *a, Func *b)
265
{
266
	if (a->funcid != b->funcid)
267
		return false;
268
	if (a->functype != b->functype)
269
		return false;
270
	if (a->funcisindex != b->funcisindex)
271
		return false;
272
	if (a->funcsize != b->funcsize)
273
		return false;
274
	if (!equal(a->func_tlist, b->func_tlist))
275
		return false;
276
	if (!equal(a->func_planlist, b->func_planlist))
277
		return false;
278

279
	return true;
280 281 282
}

/*
283
 * RestrictInfo is a subclass of Node.
284
 */
285
static bool
286
_equalRestrictInfo(RestrictInfo *a, RestrictInfo *b)
287
{
288 289
	Assert(IsA(a, RestrictInfo));
	Assert(IsA(b, RestrictInfo));
290 291

	if (!equal(a->clause, b->clause))
292
		return false;
293
	if (a->selectivity != b->selectivity)
294
		return false;
295
	if (a->notclause != b->notclause)
296
		return false;
297
#ifdef EqualMergeOrderExists
298
	if (!EqualMergeOrder(a->mergejoinorder, b->mergejoinorder))
299
		return false;
300
#endif
301
	if (a->hashjoinoperator != b->hashjoinoperator)
302
		return false;
303
	return equal(a->indexids, b->indexids);
304 305
}

306 307 308 309
/*
 * RelOptInfo is a subclass of Node.
 */
static bool
Bruce Momjian's avatar
Bruce Momjian committed
310
_equalRelOptInfo(RelOptInfo *a, RelOptInfo *b)
311 312 313 314
{
	Assert(IsA(a, RelOptInfo));
	Assert(IsA(b, RelOptInfo));

315
	return equal(a->relids, b->relids);
316 317
}

318
static bool
319
_equalJoinMethod(JoinMethod *a, JoinMethod *b)
320
{
321 322 323
	Assert(IsA(a, JoinMethod));
	Assert(IsA(b, JoinMethod));

324
	if (!equal(a->jmkeys, b->jmkeys))
325
		return false;
326
	if (!equal(a->clauses, b->clauses))
327 328
		return false;
	return true;
329 330
}

331
static bool
332
_equalPath(Path *a, Path *b)
333
{
334
	if (a->pathtype != b->pathtype)
335
		return false;
336
	if (a->parent != b->parent)
337
		return false;
338 339 340 341

	/*
	 * if (a->path_cost != b->path_cost) return(false);
	 */
Bruce Momjian's avatar
Bruce Momjian committed
342
	if (a->pathorder->ordtype == SORTOP_ORDER)
343
	{
344
		int			i = 0;
345

Bruce Momjian's avatar
Bruce Momjian committed
346 347
		if (a->pathorder->ord.sortop == NULL ||
			b->pathorder->ord.sortop == NULL)
348
		{
Bruce Momjian's avatar
Bruce Momjian committed
349
			if (a->pathorder->ord.sortop != b->pathorder->ord.sortop)
350 351 352 353
				return false;
		}
		else
		{
Bruce Momjian's avatar
Bruce Momjian committed
354 355
			while (a->pathorder->ord.sortop[i] != 0 &&
				   b->pathorder->ord.sortop[i] != 0)
356
			{
Bruce Momjian's avatar
Bruce Momjian committed
357
				if (a->pathorder->ord.sortop[i] != b->pathorder->ord.sortop[i])
358 359 360
					return false;
				i++;
			}
Bruce Momjian's avatar
Bruce Momjian committed
361 362
			if (a->pathorder->ord.sortop[i] != 0 ||
				b->pathorder->ord.sortop[i] != 0)
363 364 365 366 367
				return false;
		}
	}
	else
	{
Bruce Momjian's avatar
Bruce Momjian committed
368
		if (!equal(a->pathorder->ord.merge, b->pathorder->ord.merge))
369
			return false;
370
	}
371
	if (!equal(a->pathkeys, b->pathkeys))
372
		return false;
373 374 375 376

	/*
	 * if (a->outerjoincost != b->outerjoincost) return(false);
	 */
377
	if (!equali(a->joinid, b->joinid))
378 379
		return false;
	return true;
380 381
}

382
static bool
383
_equalIndexPath(IndexPath *a, IndexPath *b)
384
{
385
	if (!_equalPath((Path *) a, (Path *) b))
386
		return false;
387
	if (!equali(a->indexid, b->indexid))
388
		return false;
389
	if (!equal(a->indexqual, b->indexqual))
390 391
		return false;
	return true;
392 393
}

394
static bool
395
_equalNestPath(NestPath *a, NestPath *b)
396
{
397 398 399 400
	Assert(IsA_JoinPath(a));
	Assert(IsA_JoinPath(b));

	if (!_equalPath((Path *) a, (Path *) b))
401
		return false;
402
	if (!equal(a->pathinfo, b->pathinfo))
403
		return false;
404
	if (!equal(a->outerjoinpath, b->outerjoinpath))
405
		return false;
406
	if (!equal(a->innerjoinpath, b->innerjoinpath))
407 408
		return false;
	return true;
409 410
}

411
static bool
412
_equalMergePath(MergePath *a, MergePath *b)
413
{
414 415 416
	Assert(IsA(a, MergePath));
	Assert(IsA(b, MergePath));

417
	if (!_equalNestPath((NestPath *) a, (NestPath *) b))
418
		return false;
Bruce Momjian's avatar
Bruce Momjian committed
419
	if (!equal(a->path_mergeclauses, b->path_mergeclauses))
420
		return false;
Bruce Momjian's avatar
Bruce Momjian committed
421
	if (!equal(a->outersortkeys, b->outersortkeys))
422
		return false;
Bruce Momjian's avatar
Bruce Momjian committed
423
	if (!equal(a->innersortkeys, b->innersortkeys))
424 425
		return false;
	return true;
426 427
}

428
static bool
429
_equalHashPath(HashPath *a, HashPath *b)
430
{
431 432 433
	Assert(IsA(a, HashPath));
	Assert(IsA(b, HashPath));

434
	if (!_equalNestPath((NestPath *) a, (NestPath *) b))
435
		return false;
436
	if (!equal((a->path_hashclauses), (b->path_hashclauses)))
437
		return false;
438
	if (!equal(a->outerhashkeys, b->outerhashkeys))
439
		return false;
440
	if (!equal(a->innerhashkeys, b->innerhashkeys))
441 442
		return false;
	return true;
443 444
}

445
static bool
446
_equalJoinKey(JoinKey *a, JoinKey *b)
447
{
448 449 450
	Assert(IsA(a, JoinKey));
	Assert(IsA(b, JoinKey));

451
	if (!equal(a->outer, b->outer))
452
		return false;
453
	if (!equal(a->inner, b->inner))
454 455
		return false;
	return true;
456 457
}

458
static bool
459
_equalMergeOrder(MergeOrder *a, MergeOrder *b)
460
{
461
	if (a == (MergeOrder *) NULL && b == (MergeOrder *) NULL)
462
		return true;
463 464 465 466
	Assert(IsA(a, MergeOrder));
	Assert(IsA(b, MergeOrder));

	if (a->join_operator != b->join_operator)
467
		return false;
468
	if (a->left_operator != b->left_operator)
469
		return false;
470
	if (a->right_operator != b->right_operator)
471
		return false;
472
	if (a->left_type != b->left_type)
473
		return false;
474
	if (a->right_type != b->right_type)
475 476
		return false;
	return true;
477 478
}

479
static bool
480
_equalHashInfo(HashInfo *a, HashInfo *b)
481
{
482 483
	Assert(IsA(a, HashInfo));
	Assert(IsA(b, HashInfo));
484 485

	if (a->hashop != b->hashop)
486 487
		return false;
	return true;
488 489
}

490 491
/* XXX	This equality function is a quick hack, should be
 *		fixed to compare all fields.
492
 */
493
static bool
494
_equalIndexScan(IndexScan *a, IndexScan *b)
495
{
496 497 498 499 500 501 502
	Assert(IsA(a, IndexScan));
	Assert(IsA(b, IndexScan));

	/*
	 * if(a->scan.plan.cost != b->scan.plan.cost) return(false);
	 */

503
	if (!equal(a->indxqual, b->indxqual))
504
		return false;
505 506

	if (a->scan.scanrelid != b->scan.scanrelid)
507
		return false;
508

509
	if (!equali(a->indxid, b->indxid))
510 511
		return false;
	return true;
512 513
}

Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
514 515 516 517
static bool
_equalSubPlan(SubPlan *a, SubPlan *b)
{
	if (a->plan_id != b->plan_id)
518
		return false;
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
519

520
	if (!equal(a->sublink->oper, b->sublink->oper))
521
		return false;
522

523
	return true;
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
524 525
}

526
static bool
527
_equalJoinInfo(JoinInfo *a, JoinInfo *b)
528
{
529 530
	Assert(IsA(a, JoinInfo));
	Assert(IsA(b, JoinInfo));
Bruce Momjian's avatar
Bruce Momjian committed
531
	if (!equal(a->unjoined_relids, b->unjoined_relids))
532
		return false;
533
	if (!equal(a->jinfo_restrictinfo, b->jinfo_restrictinfo))
534
		return false;
535
	if (a->mergejoinable != b->mergejoinable)
536
		return false;
537
	if (a->hashjoinable != b->hashjoinable)
538 539
		return false;
	return true;
540 541 542
}

/*
543
 *	Stuff from execnodes.h
544 545 546
 */

/*
547
 *	EState is a subclass of Node.
548
 */
549
static bool
550
_equalEState(EState *a, EState *b)
551
{
552
	if (a->es_direction != b->es_direction)
553
		return false;
554 555

	if (!equal(a->es_range_table, b->es_range_table))
556
		return false;
557 558

	if (a->es_result_relation_info != b->es_result_relation_info)
559
		return false;
560

561
	return true;
562 563
}

564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662
/*
 * Stuff from parsenodes.h
 */

static bool
_equalQuery(Query *a, Query *b)
{
	if (a->commandType != b->commandType)
		return false;
	if (!equal(a->utilityStmt, b->utilityStmt))
		return false;
	if (a->resultRelation != b->resultRelation)
		return false;
	if (a->into && b->into) {
		if (strcmp(a->into, b->into) != 0)
			return false;
	} else {
		if (a->into != b->into)
			return false;
	}
	if (a->isPortal != b->isPortal)
		return false;
	if (a->isBinary != b->isBinary)
		return false;
	if (a->isTemp != b->isTemp)
		return false;
	if (a->unionall != b->unionall)
		return false;
	if (a->hasAggs != b->hasAggs)
		return false;
	if (a->hasSubLinks != b->hasSubLinks)
		return false;
	if (a->uniqueFlag && b->uniqueFlag) {
		if (strcmp(a->uniqueFlag, b->uniqueFlag) != 0)
			return false;
	} else {
		if (a->uniqueFlag != b->uniqueFlag)
			return false;
	}
	if (!equal(a->sortClause, b->sortClause))
		return false;
	if (!equal(a->rtable, b->rtable))
		return false;
	if (!equal(a->targetList, b->targetList))
		return false;
	if (!equal(a->qual, b->qual))
		return false;
	if (!equal(a->rowMark, b->rowMark))
		return false;
	if (!equal(a->groupClause, b->groupClause))
		return false;
	if (!equal(a->havingQual, b->havingQual))
		return false;
	if (!equal(a->intersectClause, b->intersectClause))
		return false;
	if (!equal(a->unionClause, b->unionClause))
		return false;
	if (!equal(a->limitOffset, b->limitOffset))
		return false;
	if (!equal(a->limitCount, b->limitCount))
		return false;

	/* We do not check the internal-to-the-planner fields
	 * base_rel_list and join_rel_list.  They might not be
	 * set yet, and in any case they should be derivable
	 * from the other fields.
	 */
	return true;
}

static bool
_equalRangeTblEntry(RangeTblEntry *a, RangeTblEntry *b)
{
	if (a->relname && b->relname) {
		if (strcmp(a->relname, b->relname) != 0)
			return false;
	} else {
		if (a->relname != b->relname)
			return false;
	}
	if (a->refname && b->refname) {
		if (strcmp(a->refname, b->refname) != 0)
			return false;
	} else {
		if (a->refname != b->refname)
			return false;
	}
	if (a->relid != b->relid)
		return false;
	if (a->inh != b->inh)
		return false;
	if (a->inFromCl != b->inFromCl)
		return false;
	if (a->skipAcl != b->skipAcl)
		return false;

	return true;
}

663
static bool
664
_equalTargetEntry(TargetEntry *a, TargetEntry *b)
665
{
666
	if (!equal(a->resdom, b->resdom))
667
		return false;
668
	if (!equal(a->fjoin, b->fjoin))
669
		return false;
670
	if (!equal(a->expr, b->expr))
671
		return false;
672

673
	return true;
674 675
}

676
/*
677
 * Stuff from pg_list.h
678
 */
679

680
static bool
681
_equalValue(Value *a, Value *b)
682
{
683
	if (a->type != b->type)
684
		return false;
685 686 687

	switch (a->type)
	{
688 689 690
		case T_String:
			return strcmp(a->val.str, b->val.str);
		case T_Integer:
691
			return a->val.ival == b->val.ival;
692
		case T_Float:
693
			return a->val.dval == b->val.dval;
694 695
		default:
			break;
696 697
	}

698
	return true;
699 700 701
}

/*
702
 * equal
703
 *	  returns whether two nodes are equal
704 705 706 707
 */
bool
equal(void *a, void *b)
{
708
	bool		retval = false;
709

710
	if (a == b)
711
		return true;
712 713 714 715 716

	/*
	 * note that a!=b, so only one of them can be NULL
	 */
	if (a == NULL || b == NULL)
717
		return false;
718 719 720 721 722

	/*
	 * are they the same type of nodes?
	 */
	if (nodeTag(a) != nodeTag(b))
723
		return false;
724 725 726

	switch (nodeTag(a))
	{
727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762
		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;
763 764
		case T_RestrictInfo:
			retval = _equalRestrictInfo(a, b);
765
			break;
766 767 768
		case T_RelOptInfo:
			retval = _equalRelOptInfo(a, b);
			break;
769 770 771 772 773 774 775 776 777
		case T_JoinMethod:
			retval = _equalJoinMethod(a, b);
			break;
		case T_Path:
			retval = _equalPath(a, b);
			break;
		case T_IndexPath:
			retval = _equalIndexPath(a, b);
			break;
778 779
		case T_NestPath:
			retval = _equalNestPath(a, b);
780 781 782 783 784 785 786 787 788 789 790 791 792
			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;
793 794
		case T_HashInfo:
			retval = _equalHashInfo(a, b);
795 796 797 798
			break;
		case T_IndexScan:
			retval = _equalIndexScan(a, b);
			break;
Vadim B. Mikheev's avatar
Vadim B. Mikheev committed
799 800 801
		case T_SubPlan:
			retval = _equalSubPlan(a, b);
			break;
802 803
		case T_JoinInfo:
			retval = _equalJoinInfo(a, b);
804 805 806 807 808 809 810 811 812 813
			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:
814
			{
815 816 817 818 819
				List	   *la = (List *) a;
				List	   *lb = (List *) b;
				List	   *l;

				if (a == NULL && b == NULL)
820
					return true;
821
				if (length(a) != length(b))
822
					return false;
823 824 825
				foreach(l, la)
				{
					if (!equal(lfirst(l), lfirst(lb)))
826
						return false;
827 828 829
					lb = lnext(lb);
				}
				retval = true;
830
			}
831
			break;
832 833 834 835 836 837 838 839 840
		case T_Query:
			retval = _equalQuery(a, b);
			break;
		case T_RangeTblEntry:
			retval = _equalRangeTblEntry(a, b);
			break;
		case T_TargetEntry:
			retval = _equalTargetEntry(a, b);
			break;
841 842 843 844
		default:
			elog(NOTICE, "equal: don't know whether nodes of type %d are equal",
				 nodeTag(a));
			break;
845
	}
846 847

	return retval;
848 849 850
}

/*
851
 * equali
852
 *	  compares two lists of integers
853 854 855
 *
 * XXX temp hack. needs something like T_IntList
 */
856
static bool
857
equali(List *a, List *b)
858
{
859 860 861
	List	   *la = (List *) a;
	List	   *lb = (List *) b;
	List	   *l;
862 863

	if (a == NULL && b == NULL)
864
		return true;
865
	if (length(a) != length(b))
866
		return false;
867 868 869
	foreach(l, la)
	{
		if (lfirsti(l) != lfirsti(lb))
870
			return false;
871 872 873
		lb = lnext(lb);
	}
	return true;
874
}