equalfuncs.c 18.0 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * equalfuncs.c
4
 *	  equality functions to compare node trees
5
 *
B
Add:  
Bruce Momjian 已提交
6 7
 * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
 * Portions Copyright (c) 1994, Regents of the University of California
8 9 10
 *
 *
 * IDENTIFICATION
11
 *	  $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.57 2000/01/27 18:11:28 tgl Exp $
12 13 14
 *
 *-------------------------------------------------------------------------
 */
15

16 17 18
#include "postgres.h"

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

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

24

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

29
static bool
30
_equalResdom(Resdom *a, Resdom *b)
31
{
32
	if (a->resno != b->resno)
33
		return false;
34
	if (a->restype != b->restype)
35
		return false;
36
	if (a->restypmod != b->restypmod)
37
		return false;
38 39 40 41 42 43 44 45 46 47 48 49
	if (a->resname && b->resname)
	{
		if (strcmp(a->resname, b->resname) != 0)
			return false;
	}
	else
	{
		/* must both be null to be equal */
		if (a->resname != b->resname)
			return false;
	}
	if (a->ressortgroupref != b->ressortgroupref)
50
		return false;
51
	if (a->reskey != b->reskey)
52
		return false;
53
	if (a->reskeyop != b->reskeyop)
54
		return false;
55
	/* we ignore resjunk flag ... is this correct? */
56

57
	return true;
58 59
}

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

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

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

78
	return true;
79 80
}

81
static bool
82
_equalExpr(Expr *a, Expr *b)
83
{
84 85 86 87
	/* 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.
	 */
88
	if (a->opType != b->opType)
89
		return false;
90
	if (!equal(a->oper, b->oper))
91
		return false;
92
	if (!equal(a->args, b->args))
93
		return false;
94

95
	return true;
96 97
}

98
static bool
99
_equalVar(Var *a, Var *b)
100
{
101
	if (a->varno != b->varno)
102
		return false;
103
	if (a->varattno != b->varattno)
104
		return false;
105
	if (a->vartype != b->vartype)
106
		return false;
107
	if (a->vartypmod != b->vartypmod)
108
		return false;
109
	if (a->varlevelsup != b->varlevelsup)
110
		return false;
111
	if (a->varnoold != b->varnoold)
112
		return false;
113
	if (a->varoattno != b->varoattno)
114
		return false;
115

116
	return true;
117 118
}

119
static bool
120
_equalOper(Oper *a, Oper *b)
121
{
122
	if (a->opno != b->opno)
123
		return false;
124
	if (a->opresulttype != b->opresulttype)
125
		return false;
126 127 128 129 130 131
	/* 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...
	 */
132

133
	return true;
134 135
}

136
static bool
137
_equalConst(Const *a, Const *b)
138
{
139
	if (a->consttype != b->consttype)
140
		return false;
141
	if (a->constlen != b->constlen)
142
		return false;
143
	if (a->constisnull != b->constisnull)
144
		return false;
145
	if (a->constbyval != b->constbyval)
146
		return false;
147
	/* XXX What about constisset and constiscast? */
148 149 150 151 152 153 154
	/*
	 * We treat all NULL constants of the same type as equal.
	 * Someday this might need to change?  But datumIsEqual
	 * doesn't work on nulls, so...
	 */
	if (a->constisnull)
		return true;
155 156
	return (datumIsEqual(a->constvalue, b->constvalue,
						 a->consttype, a->constbyval, a->constlen));
157 158
}

159
static bool
160
_equalParam(Param *a, Param *b)
161
{
162
	if (a->paramkind != b->paramkind)
163
		return false;
164
	if (a->paramtype != b->paramtype)
165
		return false;
166
	if (!equal(a->param_tlist, b->param_tlist))
167
		return false;
168 169 170

	switch (a->paramkind)
	{
171 172 173 174
		case PARAM_NAMED:
		case PARAM_NEW:
		case PARAM_OLD:
			if (strcmp(a->paramname, b->paramname) != 0)
175
				return false;
176 177
			break;
		case PARAM_NUM:
V
Vadim B. Mikheev 已提交
178
		case PARAM_EXEC:
179
			if (a->paramid != b->paramid)
180
				return false;
181 182 183 184 185 186
			break;
		case PARAM_INVALID:

			/*
			 * XXX: Hmmm... What are we supposed to return in this case ??
			 */
187
			return true;
188 189
			break;
		default:
190
			elog(ERROR, "_equalParam: Invalid paramkind value: %d",
191
				 a->paramkind);
192 193
	}

194
	return true;
195 196
}

197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
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;
}

217 218 219 220 221 222 223 224 225 226 227 228 229
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->usenulls != b->usenulls)
		return false;
230 231 232 233
	if (a->aggstar != b->aggstar)
		return false;
	if (a->aggdistinct != b->aggdistinct)
		return false;
234
	/* ignore aggno, which is only a private field for the executor */
235 236 237
	return true;
}

238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
static bool
_equalSubLink(SubLink *a, SubLink *b)
{
	if (a->subLinkType != b->subLinkType)
		return false;
	if (a->useor != b->useor)
		return false;
	if (!equal(a->lefthand, b->lefthand))
		return false;
	if (!equal(a->oper, b->oper))
		return false;
	if (!equal(a->subselect, b->subselect))
		return false;
	return true;
}

254
static bool
255
_equalArray(Array *a, Array *b)
256
{
257
	if (a->arrayelemtype != b->arrayelemtype)
258
		return false;
259 260
	/* We need not check arrayelemlength, arrayelembyval if types match */
	if (a->arrayndim != b->arrayndim)
261
		return false;
262 263
	/* XXX shouldn't we be checking all indices??? */
	if (a->arraylow.indx[0] != b->arraylow.indx[0])
264
		return false;
265
	if (a->arrayhigh.indx[0] != b->arrayhigh.indx[0])
266
		return false;
267
	if (a->arraylen != b->arraylen)
268
		return false;
269

270
	return true;
271 272
}

273
static bool
274
_equalArrayRef(ArrayRef *a, ArrayRef *b)
275
{
276
	if (a->refelemtype != b->refelemtype)
277
		return false;
278
	if (a->refattrlength != b->refattrlength)
279
		return false;
280
	if (a->refelemlength != b->refelemlength)
281
		return false;
282
	if (a->refelembyval != b->refelembyval)
283
		return false;
284 285 286 287 288 289 290
	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);
291 292
}

B
Bruce Momjian 已提交
293
/*
294
 * Stuff from relation.h
B
Bruce Momjian 已提交
295
 */
296

B
Bruce Momjian 已提交
297
static bool
298
_equalRelOptInfo(RelOptInfo *a, RelOptInfo *b)
B
Bruce Momjian 已提交
299
{
300 301 302
	/* We treat RelOptInfos as equal if they refer to the same base rels
	 * joined in the same order.  Is this sufficient?
	 */
303
	return equali(a->relids, b->relids);
B
Bruce Momjian 已提交
304 305
}

306 307 308 309 310 311 312 313 314 315 316
static bool
_equalIndexOptInfo(IndexOptInfo *a, IndexOptInfo *b)
{
	/* We treat IndexOptInfos as equal if they refer to the same index.
	 * Is this sufficient?
	 */
	if (a->indexoid != b->indexoid)
		return false;
	return true;
}

317
static bool
318
_equalPathKeyItem(PathKeyItem *a, PathKeyItem *b)
319
{
320
	if (a->sortop != b->sortop)
321
		return false;
322
	if (!equal(a->key, b->key))
323 324
		return false;
	return true;
325 326
}

327
static bool
328
_equalPath(Path *a, Path *b)
329
{
330
	if (a->pathtype != b->pathtype)
331
		return false;
332
	if (!equal(a->parent, b->parent))
333
		return false;
334 335
	/* do not check path_cost, since it may not be set yet, and being
	 * a float there are roundoff error issues anyway...
336
	 */
337
	if (!equal(a->pathkeys, b->pathkeys))
338 339
		return false;
	return true;
340 341
}

342
static bool
343
_equalIndexPath(IndexPath *a, IndexPath *b)
344
{
345
	if (!_equalPath((Path *) a, (Path *) b))
346
		return false;
347
	if (!equali(a->indexid, b->indexid))
348
		return false;
349
	if (!equal(a->indexqual, b->indexqual))
350
		return false;
351 352
	if (!equali(a->joinrelids, b->joinrelids))
		return false;
353
	return true;
354 355
}

356 357 358 359 360 361 362 363 364 365 366 367
static bool
_equalTidPath(TidPath *a, TidPath *b)
{
	if (!_equalPath((Path *) a, (Path *) b))
		return false;
	if (!equal(a->tideval, b->tideval))
		return false;
	if (!equali(a->unjoined_relids, b->unjoined_relids))
		return false;
	return true;
}

368
static bool
369
_equalJoinPath(JoinPath *a, JoinPath *b)
370
{
371
	if (!_equalPath((Path *) a, (Path *) b))
372
		return false;
373
	if (!equal(a->outerjoinpath, b->outerjoinpath))
374
		return false;
375
	if (!equal(a->innerjoinpath, b->innerjoinpath))
376 377
		return false;
	return true;
378 379
}

380
static bool
381
_equalNestPath(NestPath *a, NestPath *b)
382
{
383
	if (!_equalJoinPath((JoinPath *) a, (JoinPath *) b))
384 385
		return false;
	return true;
386 387
}

388
static bool
389
_equalMergePath(MergePath *a, MergePath *b)
390
{
391
	if (!_equalJoinPath((JoinPath *) a, (JoinPath *) b))
392
		return false;
393
	if (!equal(a->path_mergeclauses, b->path_mergeclauses))
394
		return false;
395
	if (!equal(a->outersortkeys, b->outersortkeys))
396
		return false;
397
	if (!equal(a->innersortkeys, b->innersortkeys))
398 399
		return false;
	return true;
400 401
}

402
static bool
403
_equalHashPath(HashPath *a, HashPath *b)
404
{
405
	if (!_equalJoinPath((JoinPath *) a, (JoinPath *) b))
406
		return false;
407
	if (!equal(a->path_hashclauses, b->path_hashclauses))
408 409
		return false;
	return true;
410 411
}

412 413
/* XXX	This equality function is a quick hack, should be
 *		fixed to compare all fields.
414 415 416
 *
 * XXX  Why is this even here?  We don't have equal() funcs for
 *      any other kinds of Plan nodes... likely this is dead code...
417
 */
418
static bool
419
_equalIndexScan(IndexScan *a, IndexScan *b)
420
{
421 422 423 424
	/*
	 * if(a->scan.plan.cost != b->scan.plan.cost) return(false);
	 */

425
	if (!equal(a->indxqual, b->indxqual))
426
		return false;
427 428

	if (a->scan.scanrelid != b->scan.scanrelid)
429
		return false;
430

431 432 433
	if (a->indxorderdir != b->indxorderdir)
		return false;

434
	if (!equali(a->indxid, b->indxid))
435 436
		return false;
	return true;
437 438
}

439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460
static bool
_equalTidScan(TidScan *a, TidScan *b)
{
	Assert(IsA(a, TidScan));
	Assert(IsA(b, TidScan));

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

	if (a->needRescan != b->needRescan)
		return false;

	if (!equal(a->tideval, b->tideval))
		return false;

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

	return true;
}

V
Vadim B. Mikheev 已提交
461 462 463
static bool
_equalSubPlan(SubPlan *a, SubPlan *b)
{
464
	/* should compare plans, but have to settle for comparing plan IDs */
V
Vadim B. Mikheev 已提交
465
	if (a->plan_id != b->plan_id)
466
		return false;
V
Vadim B. Mikheev 已提交
467

468 469 470
	if (!equal(a->rtable, b->rtable))
		return false;

471
	if (!equal(a->sublink, b->sublink))
472
		return false;
473

474
	return true;
V
Vadim B. Mikheev 已提交
475 476
}

477
static bool
478
_equalRestrictInfo(RestrictInfo *a, RestrictInfo *b)
479
{
480
	if (!equal(a->clause, b->clause))
481
		return false;
482
	if (!equal(a->subclauseindices, b->subclauseindices))
483
		return false;
484
	if (a->mergejoinoperator != b->mergejoinoperator)
485
		return false;
486 487 488 489 490
	if (a->left_sortop != b->left_sortop)
		return false;
	if (a->right_sortop != b->right_sortop)
		return false;
	if (a->hashjoinoperator != b->hashjoinoperator)
491 492
		return false;
	return true;
493 494
}

495
static bool
496
_equalJoinInfo(JoinInfo *a, JoinInfo *b)
497
{
498
	if (!equali(a->unjoined_relids, b->unjoined_relids))
499
		return false;
500
	if (!equal(a->jinfo_restrictinfo, b->jinfo_restrictinfo))
501
		return false;
502
	return true;
503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530
}

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);
}

531
/*
532
 *	Stuff from execnodes.h
533 534 535
 */

/*
536
 *	EState is a subclass of Node.
537
 */
538
static bool
539
_equalEState(EState *a, EState *b)
540
{
541
	if (a->es_direction != b->es_direction)
542
		return false;
543 544

	if (!equal(a->es_range_table, b->es_range_table))
545
		return false;
546 547

	if (a->es_result_relation_info != b->es_result_relation_info)
548
		return false;
549

550
	return true;
551 552
}

553 554 555 556 557 558 559 560 561 562 563 564 565
/*
 * 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 已提交
566 567
	if (a->into && b->into)
	{
568 569
		if (strcmp(a->into, b->into) != 0)
			return false;
B
Bruce Momjian 已提交
570 571 572
	}
	else
	{
573 574 575 576 577 578 579 580 581 582 583 584 585 586 587
		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;
588 589 590 591 592 593 594 595
	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;
596 597
	if (!equal(a->distinctClause, b->distinctClause))
		return false;
598 599 600 601 602 603 604 605 606 607 608 609 610 611 612
	if (!equal(a->sortClause, b->sortClause))
		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 已提交
613
	/*
614 615 616
	 * We do not check the internal-to-the-planner fields: base_rel_list,
	 * join_rel_list, query_pathkeys.  They might not be set yet, and
	 * in any case they should be derivable from the other fields.
617 618 619 620 621 622 623
	 */
	return true;
}

static bool
_equalRangeTblEntry(RangeTblEntry *a, RangeTblEntry *b)
{
B
Bruce Momjian 已提交
624 625
	if (a->relname && b->relname)
	{
626 627
		if (strcmp(a->relname, b->relname) != 0)
			return false;
B
Bruce Momjian 已提交
628 629 630
	}
	else
	{
631 632 633
		if (a->relname != b->relname)
			return false;
	}
B
Bruce Momjian 已提交
634 635
	if (a->refname && b->refname)
	{
636 637
		if (strcmp(a->refname, b->refname) != 0)
			return false;
B
Bruce Momjian 已提交
638 639 640
	}
	else
	{
641 642 643 644 645 646 647 648 649
		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;
650 651
	if (a->inJoinSet != b->inJoinSet)
		return false;
652 653 654 655 656 657
	if (a->skipAcl != b->skipAcl)
		return false;

	return true;
}

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

668
	return true;
669 670
}

671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696
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;
}

697
/*
698
 * Stuff from pg_list.h
699
 */
700

701
static bool
702
_equalValue(Value *a, Value *b)
703
{
704
	if (a->type != b->type)
705
		return false;
706 707 708

	switch (a->type)
	{
709 710 711
		case T_String:
			return strcmp(a->val.str, b->val.str);
		case T_Integer:
712
			return a->val.ival == b->val.ival;
713
		case T_Float:
714
			return a->val.dval == b->val.dval;
715 716
		default:
			break;
717 718
	}

719
	return true;
720 721 722
}

/*
723
 * equal
724
 *	  returns whether two nodes are equal
725 726 727 728
 */
bool
equal(void *a, void *b)
{
729
	bool		retval = false;
730

731
	if (a == b)
732
		return true;
733 734 735 736 737

	/*
	 * note that a!=b, so only one of them can be NULL
	 */
	if (a == NULL || b == NULL)
738
		return false;
739 740 741 742 743

	/*
	 * are they the same type of nodes?
	 */
	if (nodeTag(a) != nodeTag(b))
744
		return false;
745 746 747

	switch (nodeTag(a))
	{
748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780
		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;
781 782
		case T_Aggref:
			retval = _equalAggref(a, b);
783 784 785
			break;
		case T_SubLink:
			retval = _equalSubLink(a, b);
786
			break;
787 788 789
		case T_Func:
			retval = _equalFunc(a, b);
			break;
790 791
		case T_RestrictInfo:
			retval = _equalRestrictInfo(a, b);
792
			break;
B
Bruce Momjian 已提交
793 794 795
		case T_RelOptInfo:
			retval = _equalRelOptInfo(a, b);
			break;
796 797 798
		case T_IndexOptInfo:
			retval = _equalIndexOptInfo(a, b);
			break;
799 800
		case T_PathKeyItem:
			retval = _equalPathKeyItem(a, b);
801 802 803 804 805 806 807
			break;
		case T_Path:
			retval = _equalPath(a, b);
			break;
		case T_IndexPath:
			retval = _equalIndexPath(a, b);
			break;
808 809 810
		case T_TidPath:
			retval = _equalTidPath(a, b);
			break;
811 812
		case T_NestPath:
			retval = _equalNestPath(a, b);
813 814 815 816 817 818 819 820 821 822
			break;
		case T_MergePath:
			retval = _equalMergePath(a, b);
			break;
		case T_HashPath:
			retval = _equalHashPath(a, b);
			break;
		case T_IndexScan:
			retval = _equalIndexScan(a, b);
			break;
823 824 825
		case T_TidScan:
			retval = _equalTidScan(a, b);
			break;
V
Vadim B. Mikheev 已提交
826 827 828
		case T_SubPlan:
			retval = _equalSubPlan(a, b);
			break;
829 830
		case T_JoinInfo:
			retval = _equalJoinInfo(a, b);
831 832 833 834 835 836 837 838 839 840
			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:
841
			{
842 843 844 845
				List	   *la = (List *) a;
				List	   *lb = (List *) b;
				List	   *l;

846 847 848 849
				/* Try to reject by length check before we grovel through
				 * all the elements...
				 */
				if (length(la) != length(lb))
850
					return false;
851 852 853
				foreach(l, la)
				{
					if (!equal(lfirst(l), lfirst(lb)))
854
						return false;
855 856 857
					lb = lnext(lb);
				}
				retval = true;
858
			}
859
			break;
860 861 862 863 864 865 866 867 868
		case T_Query:
			retval = _equalQuery(a, b);
			break;
		case T_RangeTblEntry:
			retval = _equalRangeTblEntry(a, b);
			break;
		case T_TargetEntry:
			retval = _equalTargetEntry(a, b);
			break;
869 870 871 872 873 874
		case T_CaseExpr:
			retval = _equalCaseExpr(a, b);
			break;
		case T_CaseWhen:
			retval = _equalCaseWhen(a, b);
			break;
875 876 877 878
		default:
			elog(NOTICE, "equal: don't know whether nodes of type %d are equal",
				 nodeTag(a));
			break;
879
	}
880 881

	return retval;
882 883 884
}

/*
885
 * equali
886
 *	  compares two lists of integers
887
 */
888
static bool
889
equali(List *a, List *b)
890
{
891
	List	   *l;
892

893
	foreach(l, a)
894
	{
895 896 897
		if (b == NIL)
			return false;
		if (lfirsti(l) != lfirsti(b))
898
			return false;
899
		b = lnext(b);
900
	}
901 902
	if (b != NIL)
		return false;
903
	return true;
904
}