equalfuncs.c 17.7 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * equalfuncs.c
4
 *	  equality functions to compare node trees
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.45 1999/07/29 02:45:36 tgl Exp $
11 12 13
 *
 *-------------------------------------------------------------------------
 */
14

15 16 17
#include "postgres.h"

#include "nodes/plannodes.h"
B
Bruce Momjian 已提交
18
#include "nodes/relation.h"
19 20
#include "utils/datum.h"

21
static bool equali(List *a, List *b);
22

23

24
/*
25
 *	Stuff from primnodes.h
26 27
 */

28
static bool
29
_equalResdom(Resdom *a, Resdom *b)
30
{
31
	if (a->resno != b->resno)
32
		return false;
33
	if (a->restype != b->restype)
34
		return false;
35
	if (a->restypmod != b->restypmod)
36
		return false;
37
	if (strcmp(a->resname, b->resname) != 0)
38
		return false;
39
	if (a->reskey != b->reskey)
40
		return false;
41
	if (a->reskeyop != b->reskeyop)
42
		return false;
43 44 45
	if (a->resgroupref != b->resgroupref)
		return false;
	/* we ignore resjunk flag ... is this correct? */
46

47
	return true;
48 49
}

50
static bool
51
_equalFjoin(Fjoin *a, Fjoin *b)
52
{
53
	int			nNodes;
54 55

	if (a->fj_initialized != b->fj_initialized)
56
		return false;
57
	if (a->fj_nNodes != b->fj_nNodes)
58
		return false;
59
	if (!equal(a->fj_innerNode, b->fj_innerNode))
60
		return false;
61 62 63

	nNodes = a->fj_nNodes;
	if (memcmp(a->fj_results, b->fj_results, nNodes * sizeof(Datum)) != 0)
64
		return false;
65
	if (memcmp(a->fj_alwaysDone, b->fj_alwaysDone, nNodes * sizeof(bool)) != 0)
66
		return false;
67

68
	return true;
69 70
}

71
static bool
72
_equalExpr(Expr *a, Expr *b)
73
{
74 75 76 77
	/* 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.
	 */
78
	if (a->opType != b->opType)
79
		return false;
80
	if (!equal(a->oper, b->oper))
81
		return false;
82
	if (!equal(a->args, b->args))
83
		return false;
84

85
	return true;
86 87
}

88
static bool
89
_equalVar(Var *a, Var *b)
90
{
91
	if (a->varno != b->varno)
92
		return false;
93
	if (a->varattno != b->varattno)
94
		return false;
95
	if (a->vartype != b->vartype)
96
		return false;
97
	if (a->vartypmod != b->vartypmod)
98
		return false;
99
	if (a->varlevelsup != b->varlevelsup)
100
		return false;
101
	if (a->varnoold != b->varnoold)
102
		return false;
103
	if (a->varoattno != b->varoattno)
104
		return false;
105

106
	return true;
107 108
}

109
static bool
110
_equalOper(Oper *a, Oper *b)
111
{
112
	if (a->opno != b->opno)
113
		return false;
114
	if (a->opresulttype != b->opresulttype)
115
		return false;
116 117 118 119 120 121
	/* 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...
	 */
122

123
	return true;
124 125
}

126
static bool
127
_equalConst(Const *a, Const *b)
128
{
129
	if (a->consttype != b->consttype)
130
		return false;
131
	if (a->constlen != b->constlen)
132
		return false;
133
	if (a->constisnull != b->constisnull)
134
		return false;
135
	if (a->constbyval != b->constbyval)
136
		return false;
137
	/* XXX What about constisset and constiscast? */
138 139
	return (datumIsEqual(a->constvalue, b->constvalue,
						 a->consttype, a->constbyval, a->constlen));
140 141
}

142
static bool
143
_equalParam(Param *a, Param *b)
144
{
145
	if (a->paramkind != b->paramkind)
146
		return false;
147
	if (a->paramtype != b->paramtype)
148
		return false;
149
	if (!equal(a->param_tlist, b->param_tlist))
150
		return false;
151 152 153

	switch (a->paramkind)
	{
154 155 156 157
		case PARAM_NAMED:
		case PARAM_NEW:
		case PARAM_OLD:
			if (strcmp(a->paramname, b->paramname) != 0)
158
				return false;
159 160
			break;
		case PARAM_NUM:
V
Vadim B. Mikheev 已提交
161
		case PARAM_EXEC:
162
			if (a->paramid != b->paramid)
163
				return false;
164 165 166 167 168 169
			break;
		case PARAM_INVALID:

			/*
			 * XXX: Hmmm... What are we supposed to return in this case ??
			 */
170
			return true;
171 172
			break;
		default:
173
			elog(ERROR, "_equalParam: Invalid paramkind value: %d",
174
				 a->paramkind);
175 176
	}

177
	return true;
178 179
}

180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
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;
	/* 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;
}

200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
static bool
_equalAggref(Aggref *a, Aggref *b)
{
	if (strcmp(a->aggname, b->aggname) != 0)
		return false;
	if (a->basetype != b->basetype)
		return false;
	if (a->aggtype != b->aggtype)
		return false;
	if (!equal(a->target, b->target))
		return false;
	if (a->aggno != b->aggno)
		return false;
	if (a->usenulls != b->usenulls)
		return false;
	return true;
}

218
static bool
219
_equalArray(Array *a, Array *b)
220
{
221
	if (a->arrayelemtype != b->arrayelemtype)
222
		return false;
223 224
	/* We need not check arrayelemlength, arrayelembyval if types match */
	if (a->arrayndim != b->arrayndim)
225
		return false;
226 227
	/* XXX shouldn't we be checking all indices??? */
	if (a->arraylow.indx[0] != b->arraylow.indx[0])
228
		return false;
229
	if (a->arrayhigh.indx[0] != b->arrayhigh.indx[0])
230
		return false;
231
	if (a->arraylen != b->arraylen)
232
		return false;
233

234
	return true;
235 236
}

237
static bool
238
_equalArrayRef(ArrayRef *a, ArrayRef *b)
239
{
240
	if (a->refelemtype != b->refelemtype)
241
		return false;
242
	if (a->refattrlength != b->refattrlength)
243
		return false;
244
	if (a->refelemlength != b->refelemlength)
245
		return false;
246
	if (a->refelembyval != b->refelembyval)
247
		return false;
248 249 250 251 252 253 254
	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);
255 256
}

B
Bruce Momjian 已提交
257
/*
258
 * Stuff from relation.h
B
Bruce Momjian 已提交
259
 */
260

B
Bruce Momjian 已提交
261
static bool
262
_equalRelOptInfo(RelOptInfo *a, RelOptInfo *b)
B
Bruce Momjian 已提交
263
{
264 265 266
	/* We treat RelOptInfos as equal if they refer to the same base rels
	 * joined in the same order.  Is this sufficient?
	 */
267
	return equal(a->relids, b->relids);
B
Bruce Momjian 已提交
268 269
}

270
static bool
271
_equalJoinMethod(JoinMethod *a, JoinMethod *b)
272
{
273
	if (!equal(a->jmkeys, b->jmkeys))
274
		return false;
275
	if (!equal(a->clauses, b->clauses))
276 277
		return false;
	return true;
278 279
}

280
static bool
281
_equalPath(Path *a, Path *b)
282
{
283
	if (a->pathtype != b->pathtype)
284
		return false;
285
	if (a->parent != b->parent)	/* should this use equal() ? */
286
		return false;
287 288
	/* do not check path_cost, since it may not be set yet, and being
	 * a float there are roundoff error issues anyway...
289
	 */
290 291 292 293

	/* XXX this should probably be in an _equalPathOrder function... */
	if (a->pathorder->ordtype != b->pathorder->ordtype)
		return false;
B
Bruce Momjian 已提交
294
	if (a->pathorder->ordtype == SORTOP_ORDER)
295
	{
B
Bruce Momjian 已提交
296 297
		if (a->pathorder->ord.sortop == NULL ||
			b->pathorder->ord.sortop == NULL)
298
		{
B
Bruce Momjian 已提交
299
			if (a->pathorder->ord.sortop != b->pathorder->ord.sortop)
300 301 302 303
				return false;
		}
		else
		{
304 305 306
			int			i = 0;

			while (a->pathorder->ord.sortop[i] != 0)
307
			{
B
Bruce Momjian 已提交
308
				if (a->pathorder->ord.sortop[i] != b->pathorder->ord.sortop[i])
309 310 311
					return false;
				i++;
			}
312
			if (b->pathorder->ord.sortop[i] != 0)
313 314 315 316 317
				return false;
		}
	}
	else
	{
B
Bruce Momjian 已提交
318
		if (!equal(a->pathorder->ord.merge, b->pathorder->ord.merge))
319
			return false;
320
	}
321

322
	if (!equal(a->pathkeys, b->pathkeys))
323
		return false;
324
	/* do not check outerjoincost either */
325
	if (!equali(a->joinid, b->joinid))
326 327
		return false;
	return true;
328 329
}

330
static bool
331
_equalIndexPath(IndexPath *a, IndexPath *b)
332
{
333
	if (!_equalPath((Path *) a, (Path *) b))
334
		return false;
335
	if (!equali(a->indexid, b->indexid))
336
		return false;
337
	if (!equal(a->indexqual, b->indexqual))
338
		return false;
339
	/* We do not need to check indexkeys */
340
	return true;
341 342
}

343
static bool
344
_equalNestPath(NestPath *a, NestPath *b)
345
{
346
	if (!_equalPath((Path *) a, (Path *) b))
347
		return false;
348
	if (!equal(a->pathinfo, b->pathinfo))
349
		return false;
350
	if (!equal(a->outerjoinpath, b->outerjoinpath))
351
		return false;
352
	if (!equal(a->innerjoinpath, b->innerjoinpath))
353 354
		return false;
	return true;
355 356
}

357
static bool
358
_equalMergePath(MergePath *a, MergePath *b)
359
{
360
	if (!_equalNestPath((NestPath *) a, (NestPath *) b))
361
		return false;
B
Bruce Momjian 已提交
362
	if (!equal(a->path_mergeclauses, b->path_mergeclauses))
363
		return false;
B
Bruce Momjian 已提交
364
	if (!equal(a->outersortkeys, b->outersortkeys))
365
		return false;
B
Bruce Momjian 已提交
366
	if (!equal(a->innersortkeys, b->innersortkeys))
367 368
		return false;
	return true;
369 370
}

371
static bool
372
_equalHashPath(HashPath *a, HashPath *b)
373
{
374
	if (!_equalNestPath((NestPath *) a, (NestPath *) b))
375
		return false;
376
	if (!equal(a->path_hashclauses, b->path_hashclauses))
377
		return false;
378
	if (!equal(a->outerhashkeys, b->outerhashkeys))
379
		return false;
380
	if (!equal(a->innerhashkeys, b->innerhashkeys))
381 382
		return false;
	return true;
383 384
}

385
static bool
386
_equalJoinKey(JoinKey *a, JoinKey *b)
387
{
388
	if (!equal(a->outer, b->outer))
389
		return false;
390
	if (!equal(a->inner, b->inner))
391 392
		return false;
	return true;
393 394
}

395
static bool
396
_equalMergeOrder(MergeOrder *a, MergeOrder *b)
397
{
398
	if (a->join_operator != b->join_operator)
399
		return false;
400
	if (a->left_operator != b->left_operator)
401
		return false;
402
	if (a->right_operator != b->right_operator)
403
		return false;
404
	if (a->left_type != b->left_type)
405
		return false;
406
	if (a->right_type != b->right_type)
407 408
		return false;
	return true;
409 410
}

411
static bool
412
_equalHashInfo(HashInfo *a, HashInfo *b)
413
{
414 415
	if (!_equalJoinMethod((JoinMethod *) a, (JoinMethod *) b))
		return false;
416
	if (a->hashop != b->hashop)
417 418
		return false;
	return true;
419 420
}

421 422
/* XXX	This equality function is a quick hack, should be
 *		fixed to compare all fields.
423 424 425
 *
 * XXX  Why is this even here?  We don't have equal() funcs for
 *      any other kinds of Plan nodes... likely this is dead code...
426
 */
427
static bool
428
_equalIndexScan(IndexScan *a, IndexScan *b)
429
{
430 431 432 433
	/*
	 * if(a->scan.plan.cost != b->scan.plan.cost) return(false);
	 */

434
	if (!equal(a->indxqual, b->indxqual))
435
		return false;
436 437

	if (a->scan.scanrelid != b->scan.scanrelid)
438
		return false;
439

440
	if (!equali(a->indxid, b->indxid))
441 442
		return false;
	return true;
443 444
}

V
Vadim B. Mikheev 已提交
445 446 447 448
static bool
_equalSubPlan(SubPlan *a, SubPlan *b)
{
	if (a->plan_id != b->plan_id)
449
		return false;
V
Vadim B. Mikheev 已提交
450

451
	if (!equal(a->sublink->oper, b->sublink->oper))
452
		return false;
453

454
	return true;
V
Vadim B. Mikheev 已提交
455 456
}

457
static bool
458
_equalJoinInfo(JoinInfo *a, JoinInfo *b)
459
{
B
Bruce Momjian 已提交
460
	if (!equal(a->unjoined_relids, b->unjoined_relids))
461
		return false;
462
	if (!equal(a->jinfo_restrictinfo, b->jinfo_restrictinfo))
463
		return false;
464
	if (a->mergejoinable != b->mergejoinable)
465
		return false;
466
	if (a->hashjoinable != b->hashjoinable)
467 468
		return false;
	return true;
469 470
}

471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509
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);
}

510
/*
511
 *	Stuff from execnodes.h
512 513 514
 */

/*
515
 *	EState is a subclass of Node.
516
 */
517
static bool
518
_equalEState(EState *a, EState *b)
519
{
520
	if (a->es_direction != b->es_direction)
521
		return false;
522 523

	if (!equal(a->es_range_table, b->es_range_table))
524
		return false;
525 526

	if (a->es_result_relation_info != b->es_result_relation_info)
527
		return false;
528

529
	return true;
530 531
}

532 533 534 535 536 537 538 539 540 541 542 543 544
/*
 * 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;
B
Bruce Momjian 已提交
545 546
	if (a->into && b->into)
	{
547 548
		if (strcmp(a->into, b->into) != 0)
			return false;
B
Bruce Momjian 已提交
549 550 551
	}
	else
	{
552 553 554 555 556 557 558 559 560 561 562 563 564 565 566
		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;
B
Bruce Momjian 已提交
567 568
	if (a->uniqueFlag && b->uniqueFlag)
	{
569 570
		if (strcmp(a->uniqueFlag, b->uniqueFlag) != 0)
			return false;
B
Bruce Momjian 已提交
571 572 573
	}
	else
	{
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
		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;

B
Bruce Momjian 已提交
600 601 602 603
	/*
	 * 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.
604 605 606 607 608 609 610
	 */
	return true;
}

static bool
_equalRangeTblEntry(RangeTblEntry *a, RangeTblEntry *b)
{
B
Bruce Momjian 已提交
611 612
	if (a->relname && b->relname)
	{
613 614
		if (strcmp(a->relname, b->relname) != 0)
			return false;
B
Bruce Momjian 已提交
615 616 617
	}
	else
	{
618 619 620
		if (a->relname != b->relname)
			return false;
	}
B
Bruce Momjian 已提交
621 622
	if (a->refname && b->refname)
	{
623 624
		if (strcmp(a->refname, b->refname) != 0)
			return false;
B
Bruce Momjian 已提交
625 626 627
	}
	else
	{
628 629 630 631 632 633 634 635 636 637 638 639 640 641 642
		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;
}

643
static bool
644
_equalTargetEntry(TargetEntry *a, TargetEntry *b)
645
{
646
	if (!equal(a->resdom, b->resdom))
647
		return false;
648
	if (!equal(a->fjoin, b->fjoin))
649
		return false;
650
	if (!equal(a->expr, b->expr))
651
		return false;
652

653
	return true;
654 655
}

656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681
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;
}

682
/*
683
 * Stuff from pg_list.h
684
 */
685

686
static bool
687
_equalValue(Value *a, Value *b)
688
{
689
	if (a->type != b->type)
690
		return false;
691 692 693

	switch (a->type)
	{
694 695 696
		case T_String:
			return strcmp(a->val.str, b->val.str);
		case T_Integer:
697
			return a->val.ival == b->val.ival;
698
		case T_Float:
699
			return a->val.dval == b->val.dval;
700 701
		default:
			break;
702 703
	}

704
	return true;
705 706 707
}

/*
708
 * equal
709
 *	  returns whether two nodes are equal
710 711 712 713
 */
bool
equal(void *a, void *b)
{
714
	bool		retval = false;
715

716
	if (a == b)
717
		return true;
718 719 720 721 722

	/*
	 * note that a!=b, so only one of them can be NULL
	 */
	if (a == NULL || b == NULL)
723
		return false;
724 725 726 727 728

	/*
	 * are they the same type of nodes?
	 */
	if (nodeTag(a) != nodeTag(b))
729
		return false;
730 731 732

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

828 829 830 831
				/* Try to reject by length check before we grovel through
				 * all the elements...
				 */
				if (length(la) != length(lb))
832
					return false;
833 834 835
				foreach(l, la)
				{
					if (!equal(lfirst(l), lfirst(lb)))
836
						return false;
837 838 839
					lb = lnext(lb);
				}
				retval = true;
840
			}
841
			break;
842 843 844 845 846 847 848 849 850
		case T_Query:
			retval = _equalQuery(a, b);
			break;
		case T_RangeTblEntry:
			retval = _equalRangeTblEntry(a, b);
			break;
		case T_TargetEntry:
			retval = _equalTargetEntry(a, b);
			break;
851 852 853 854 855 856
		case T_CaseExpr:
			retval = _equalCaseExpr(a, b);
			break;
		case T_CaseWhen:
			retval = _equalCaseWhen(a, b);
			break;
857 858 859 860
		default:
			elog(NOTICE, "equal: don't know whether nodes of type %d are equal",
				 nodeTag(a));
			break;
861
	}
862 863

	return retval;
864 865 866
}

/*
867
 * equali
868
 *	  compares two lists of integers
869
 */
870
static bool
871
equali(List *a, List *b)
872
{
873
	List	   *l;
874

875
	foreach(l, a)
876
	{
877 878 879
		if (b == NIL)
			return false;
		if (lfirsti(l) != lfirsti(b))
880
			return false;
881
		b = lnext(b);
882
	}
883 884
	if (b != NIL)
		return false;
885
	return true;
886
}