equalfuncs.c 17.0 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
B
Bruce Momjian 已提交
10
 *	  $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.29 1999/02/10 21:02:33 momjian 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
	if (a->reskeyop != b->reskeyop)
52
		return false;
53

54
	return true;
55 56
}

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

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

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

75
	return true;
76 77 78
}

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

91
	return true;
92 93
}

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

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

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

141
	return true;
142 143
}

144
static bool
B
Bruce Momjian 已提交
145
_equalArray(Array *a, Array *b)
146
{
147
	if (a->arrayelemtype != b->arrayelemtype)
148
		return false;
149
	if (a->arrayndim != b->arrayndim)
150
		return false;
151
	if (a->arraylow.indx[0] != b->arraylow.indx[0])
152
		return false;
153
	if (a->arrayhigh.indx[0] != b->arrayhigh.indx[0])
154
		return false;
155
	if (a->arraylen != b->arraylen)
156 157
		return false;
	return TRUE;
158 159
}

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

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

191
	return true;
192 193 194
}

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

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

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

	switch (a->paramkind)
	{
232 233 234 235
		case PARAM_NAMED:
		case PARAM_NEW:
		case PARAM_OLD:
			if (strcmp(a->paramname, b->paramname) != 0)
236
				return false;
237 238
			break;
		case PARAM_NUM:
V
Vadim B. Mikheev 已提交
239
		case PARAM_EXEC:
240
			if (a->paramid != b->paramid)
241
				return false;
242 243 244 245 246 247
			break;
		case PARAM_INVALID:

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

255
	return true;
256 257 258
}

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

277
	return true;
278 279 280
}

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

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

B
Bruce Momjian 已提交
304 305 306 307
/*
 * RelOptInfo is a subclass of Node.
 */
static bool
B
Bruce Momjian 已提交
308
_equalRelOptInfo(RelOptInfo *a, RelOptInfo *b)
B
Bruce Momjian 已提交
309 310 311 312
{
	Assert(IsA(a, RelOptInfo));
	Assert(IsA(b, RelOptInfo));

313
	return equal(a->relids, b->relids);
B
Bruce Momjian 已提交
314 315
}

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

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

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

	/*
	 * if (a->path_cost != b->path_cost) return(false);
	 */
340
	if (a->path_order->ordtype == SORTOP_ORDER)
341
	{
342
		int			i = 0;
343

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

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

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

392
static bool
393
_equalJoinPath(JoinPath *a, JoinPath *b)
394
{
395 396 397 398
	Assert(IsA_JoinPath(a));
	Assert(IsA_JoinPath(b));

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

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

	if (!_equalJoinPath((JoinPath *) a, (JoinPath *) b))
416
		return false;
B
Bruce Momjian 已提交
417
	if (!equal(a->path_mergeclauses, b->path_mergeclauses))
418
		return false;
B
Bruce Momjian 已提交
419
	if (!equal(a->outersortkeys, b->outersortkeys))
420
		return false;
B
Bruce Momjian 已提交
421
	if (!equal(a->innersortkeys, b->innersortkeys))
422 423
		return false;
	return true;
424 425
}

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

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

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

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

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

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

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

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

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

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

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

	if (a->scan.scanrelid != b->scan.scanrelid)
505
		return false;
506

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

V
Vadim B. Mikheev 已提交
512 513 514 515
static bool
_equalSubPlan(SubPlan *a, SubPlan *b)
{
	if (a->plan_id != b->plan_id)
516
		return false;
V
Vadim B. Mikheev 已提交
517

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

521
	return true;
V
Vadim B. Mikheev 已提交
522 523
}

524
static bool
525
_equalJoinInfo(JoinInfo * a, JoinInfo * b)
526
{
527 528
	Assert(IsA(a, JoinInfo));
	Assert(IsA(b, JoinInfo));
529
	if (!equal(a->otherrels, b->otherrels))
530
		return false;
531
	if (!equal(a->jinfo_restrictinfo, b->jinfo_restrictinfo))
532
		return false;
533
	if (a->mergejoinable != b->mergejoinable)
534
		return false;
535
	if (a->hashjoinable != b->hashjoinable)
536 537
		return false;
	return true;
538 539 540
}

/*
541
 *	Stuff from execnodes.h
542 543 544
 */

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

	if (!equal(a->es_range_table, b->es_range_table))
554
		return false;
555 556

	if (a->es_result_relation_info != b->es_result_relation_info)
557
		return false;
558

559
	return true;
560 561
}

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
/*
 * 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;
}

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

671
	return true;
672 673
}

674
/*
675
 * Stuff from pg_list.h
676
 */
677

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

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

696
	return true;
697 698 699 700
}

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

708
	if (a == b)
709
		return true;
710 711 712 713 714

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

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

	switch (nodeTag(a))
	{
725 726 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
		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;
761 762
		case T_RestrictInfo:
			retval = _equalRestrictInfo(a, b);
763
			break;
B
Bruce Momjian 已提交
764 765 766
		case T_RelOptInfo:
			retval = _equalRelOptInfo(a, b);
			break;
767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790
		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;
791 792
		case T_HashInfo:
			retval = _equalHashInfo(a, b);
793 794 795 796
			break;
		case T_IndexScan:
			retval = _equalIndexScan(a, b);
			break;
V
Vadim B. Mikheev 已提交
797 798 799
		case T_SubPlan:
			retval = _equalSubPlan(a, b);
			break;
800 801
		case T_JoinInfo:
			retval = _equalJoinInfo(a, b);
802 803 804 805 806 807 808 809 810 811
			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:
812
			{
813 814 815 816 817
				List	   *la = (List *) a;
				List	   *lb = (List *) b;
				List	   *l;

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

	return retval;
846 847 848 849
}

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

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