equalfuncs.c 16.4 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.48 1999/08/21 03:48:57 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 38 39 40 41 42 43 44 45 46 47 48
	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)
49
		return false;
50
	if (a->reskey != b->reskey)
51
		return false;
52
	if (a->reskeyop != b->reskeyop)
53
		return false;
54
	/* we ignore resjunk flag ... is this correct? */
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
static bool
81
_equalExpr(Expr *a, Expr *b)
82
{
83 84 85 86
	/* 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.
	 */
87
	if (a->opType != b->opType)
88
		return false;
89
	if (!equal(a->oper, b->oper))
90
		return false;
91
	if (!equal(a->args, b->args))
92
		return false;
93

94
	return true;
95 96
}

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

115
	return true;
116 117
}

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

132
	return true;
133 134
}

135
static bool
136
_equalConst(Const *a, Const *b)
137
{
138
	if (a->consttype != b->consttype)
139
		return false;
140
	if (a->constlen != b->constlen)
141
		return false;
142
	if (a->constisnull != b->constisnull)
143
		return false;
144
	if (a->constbyval != b->constbyval)
145
		return false;
146
	/* XXX What about constisset and constiscast? */
147 148
	return (datumIsEqual(a->constvalue, b->constvalue,
						 a->consttype, a->constbyval, a->constlen));
149 150
}

151
static bool
152
_equalParam(Param *a, Param *b)
153
{
154
	if (a->paramkind != b->paramkind)
155
		return false;
156
	if (a->paramtype != b->paramtype)
157
		return false;
158
	if (!equal(a->param_tlist, b->param_tlist))
159
		return false;
160 161 162

	switch (a->paramkind)
	{
163 164 165 166
		case PARAM_NAMED:
		case PARAM_NEW:
		case PARAM_OLD:
			if (strcmp(a->paramname, b->paramname) != 0)
167
				return false;
168 169
			break;
		case PARAM_NUM:
V
Vadim B. Mikheev 已提交
170
		case PARAM_EXEC:
171
			if (a->paramid != b->paramid)
172
				return false;
173 174 175 176 177 178
			break;
		case PARAM_INVALID:

			/*
			 * XXX: Hmmm... What are we supposed to return in this case ??
			 */
179
			return true;
180 181
			break;
		default:
182
			elog(ERROR, "_equalParam: Invalid paramkind value: %d",
183
				 a->paramkind);
184 185
	}

186
	return true;
187 188
}

189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
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;
}

209 210 211 212 213 214 215 216 217 218 219 220 221
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;
222
	/* ignore aggno, which is only a private field for the executor */
223 224 225
	return true;
}

226
static bool
227
_equalArray(Array *a, Array *b)
228
{
229
	if (a->arrayelemtype != b->arrayelemtype)
230
		return false;
231 232
	/* We need not check arrayelemlength, arrayelembyval if types match */
	if (a->arrayndim != b->arrayndim)
233
		return false;
234 235
	/* XXX shouldn't we be checking all indices??? */
	if (a->arraylow.indx[0] != b->arraylow.indx[0])
236
		return false;
237
	if (a->arrayhigh.indx[0] != b->arrayhigh.indx[0])
238
		return false;
239
	if (a->arraylen != b->arraylen)
240
		return false;
241

242
	return true;
243 244
}

245
static bool
246
_equalArrayRef(ArrayRef *a, ArrayRef *b)
247
{
248
	if (a->refelemtype != b->refelemtype)
249
		return false;
250
	if (a->refattrlength != b->refattrlength)
251
		return false;
252
	if (a->refelemlength != b->refelemlength)
253
		return false;
254
	if (a->refelembyval != b->refelembyval)
255
		return false;
256 257 258 259 260 261 262
	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);
263 264
}

B
Bruce Momjian 已提交
265
/*
266
 * Stuff from relation.h
B
Bruce Momjian 已提交
267
 */
268

B
Bruce Momjian 已提交
269
static bool
270
_equalRelOptInfo(RelOptInfo *a, RelOptInfo *b)
B
Bruce Momjian 已提交
271
{
272 273 274
	/* We treat RelOptInfos as equal if they refer to the same base rels
	 * joined in the same order.  Is this sufficient?
	 */
275
	return equali(a->relids, b->relids);
B
Bruce Momjian 已提交
276 277
}

278
static bool
279
_equalPathKeyItem(PathKeyItem *a, PathKeyItem *b)
280
{
281
	if (a->sortop != b->sortop)
282
		return false;
283
	if (!equal(a->key, b->key))
284 285
		return false;
	return true;
286 287
}

288
static bool
289
_equalPath(Path *a, Path *b)
290
{
291
	if (a->pathtype != b->pathtype)
292
		return false;
293
	if (!equal(a->parent, b->parent))
294
		return false;
295 296
	/* do not check path_cost, since it may not be set yet, and being
	 * a float there are roundoff error issues anyway...
297
	 */
298
	if (!equal(a->pathkeys, b->pathkeys))
299 300
		return false;
	return true;
301 302
}

303
static bool
304
_equalIndexPath(IndexPath *a, IndexPath *b)
305
{
306
	if (!_equalPath((Path *) a, (Path *) b))
307
		return false;
308
	if (!equali(a->indexid, b->indexid))
309
		return false;
310
	if (!equal(a->indexqual, b->indexqual))
311
		return false;
312 313
	if (!equali(a->joinrelids, b->joinrelids))
		return false;
314
	return true;
315 316
}

317
static bool
318
_equalJoinPath(JoinPath *a, JoinPath *b)
319
{
320
	if (!_equalPath((Path *) a, (Path *) b))
321
		return false;
322
	if (!equal(a->pathinfo, b->pathinfo))
323
		return false;
324
	if (!equal(a->outerjoinpath, b->outerjoinpath))
325
		return false;
326
	if (!equal(a->innerjoinpath, b->innerjoinpath))
327 328
		return false;
	return true;
329 330
}

331
static bool
332
_equalNestPath(NestPath *a, NestPath *b)
333
{
334
	if (!_equalJoinPath((JoinPath *) a, (JoinPath *) b))
335 336
		return false;
	return true;
337 338
}

339
static bool
340
_equalMergePath(MergePath *a, MergePath *b)
341
{
342
	if (!_equalJoinPath((JoinPath *) a, (JoinPath *) b))
343
		return false;
344
	if (!equal(a->path_mergeclauses, b->path_mergeclauses))
345
		return false;
346
	if (!equal(a->outersortkeys, b->outersortkeys))
347
		return false;
348
	if (!equal(a->innersortkeys, b->innersortkeys))
349 350
		return false;
	return true;
351 352
}

353
static bool
354
_equalHashPath(HashPath *a, HashPath *b)
355
{
356
	if (!_equalJoinPath((JoinPath *) a, (JoinPath *) b))
357
		return false;
358
	if (!equal(a->path_hashclauses, b->path_hashclauses))
359 360
		return false;
	return true;
361 362
}

363 364
/* XXX	This equality function is a quick hack, should be
 *		fixed to compare all fields.
365 366 367
 *
 * XXX  Why is this even here?  We don't have equal() funcs for
 *      any other kinds of Plan nodes... likely this is dead code...
368
 */
369
static bool
370
_equalIndexScan(IndexScan *a, IndexScan *b)
371
{
372 373 374 375
	/*
	 * if(a->scan.plan.cost != b->scan.plan.cost) return(false);
	 */

376
	if (!equal(a->indxqual, b->indxqual))
377
		return false;
378 379

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

382 383 384
	if (a->indxorderdir != b->indxorderdir)
		return false;

385
	if (!equali(a->indxid, b->indxid))
386 387
		return false;
	return true;
388 389
}

V
Vadim B. Mikheev 已提交
390 391 392 393
static bool
_equalSubPlan(SubPlan *a, SubPlan *b)
{
	if (a->plan_id != b->plan_id)
394
		return false;
V
Vadim B. Mikheev 已提交
395

396
	if (!equal(a->sublink->oper, b->sublink->oper))
397
		return false;
398

399
	return true;
V
Vadim B. Mikheev 已提交
400 401
}

402
static bool
403
_equalRestrictInfo(RestrictInfo *a, RestrictInfo *b)
404
{
405
	if (!equal(a->clause, b->clause))
406
		return false;
407 408
	/* do not check selectivity because of roundoff error worries */
	if (!equal(a->subclauseindices, b->subclauseindices))
409
		return false;
410
	if (a->mergejoinoperator != b->mergejoinoperator)
411
		return false;
412 413 414 415 416
	if (a->left_sortop != b->left_sortop)
		return false;
	if (a->right_sortop != b->right_sortop)
		return false;
	if (a->hashjoinoperator != b->hashjoinoperator)
417 418
		return false;
	return true;
419 420
}

421
static bool
422
_equalJoinInfo(JoinInfo *a, JoinInfo *b)
423
{
424
	if (!equali(a->unjoined_relids, b->unjoined_relids))
425
		return false;
426
	if (!equal(a->jinfo_restrictinfo, b->jinfo_restrictinfo))
427
		return false;
428
	return true;
429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456
}

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

457
/*
458
 *	Stuff from execnodes.h
459 460 461
 */

/*
462
 *	EState is a subclass of Node.
463
 */
464
static bool
465
_equalEState(EState *a, EState *b)
466
{
467
	if (a->es_direction != b->es_direction)
468
		return false;
469 470

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

	if (a->es_result_relation_info != b->es_result_relation_info)
474
		return false;
475

476
	return true;
477 478
}

479 480 481 482 483 484 485 486 487 488 489 490 491
/*
 * 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 已提交
492 493
	if (a->into && b->into)
	{
494 495
		if (strcmp(a->into, b->into) != 0)
			return false;
B
Bruce Momjian 已提交
496 497 498
	}
	else
	{
499 500 501 502 503 504 505 506 507 508 509 510 511 512 513
		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;
514 515 516 517 518 519 520 521
	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;
B
Bruce Momjian 已提交
522 523
	if (a->uniqueFlag && b->uniqueFlag)
	{
524 525
		if (strcmp(a->uniqueFlag, b->uniqueFlag) != 0)
			return false;
B
Bruce Momjian 已提交
526 527 528
	}
	else
	{
529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546
		if (a->uniqueFlag != b->uniqueFlag)
			return false;
	}
	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 已提交
547
	/*
548 549 550
	 * 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.
551 552 553 554 555 556 557
	 */
	return true;
}

static bool
_equalRangeTblEntry(RangeTblEntry *a, RangeTblEntry *b)
{
B
Bruce Momjian 已提交
558 559
	if (a->relname && b->relname)
	{
560 561
		if (strcmp(a->relname, b->relname) != 0)
			return false;
B
Bruce Momjian 已提交
562 563 564
	}
	else
	{
565 566 567
		if (a->relname != b->relname)
			return false;
	}
B
Bruce Momjian 已提交
568 569
	if (a->refname && b->refname)
	{
570 571
		if (strcmp(a->refname, b->refname) != 0)
			return false;
B
Bruce Momjian 已提交
572 573 574
	}
	else
	{
575 576 577 578 579 580 581 582 583 584 585 586 587 588 589
		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;
}

590
static bool
591
_equalTargetEntry(TargetEntry *a, TargetEntry *b)
592
{
593
	if (!equal(a->resdom, b->resdom))
594
		return false;
595
	if (!equal(a->fjoin, b->fjoin))
596
		return false;
597
	if (!equal(a->expr, b->expr))
598
		return false;
599

600
	return true;
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
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;
}

629
/*
630
 * Stuff from pg_list.h
631
 */
632

633
static bool
634
_equalValue(Value *a, Value *b)
635
{
636
	if (a->type != b->type)
637
		return false;
638 639 640

	switch (a->type)
	{
641 642 643
		case T_String:
			return strcmp(a->val.str, b->val.str);
		case T_Integer:
644
			return a->val.ival == b->val.ival;
645
		case T_Float:
646
			return a->val.dval == b->val.dval;
647 648
		default:
			break;
649 650
	}

651
	return true;
652 653 654
}

/*
655
 * equal
656
 *	  returns whether two nodes are equal
657 658 659 660
 */
bool
equal(void *a, void *b)
{
661
	bool		retval = false;
662

663
	if (a == b)
664
		return true;
665 666 667 668 669

	/*
	 * note that a!=b, so only one of them can be NULL
	 */
	if (a == NULL || b == NULL)
670
		return false;
671 672 673 674 675

	/*
	 * are they the same type of nodes?
	 */
	if (nodeTag(a) != nodeTag(b))
676
		return false;
677 678 679

	switch (nodeTag(a))
	{
680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712
		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;
713 714 715
		case T_Aggref:
			retval = _equalAggref(a, b);
			break;
716 717 718
		case T_Func:
			retval = _equalFunc(a, b);
			break;
719 720
		case T_RestrictInfo:
			retval = _equalRestrictInfo(a, b);
721
			break;
B
Bruce Momjian 已提交
722 723 724
		case T_RelOptInfo:
			retval = _equalRelOptInfo(a, b);
			break;
725 726
		case T_PathKeyItem:
			retval = _equalPathKeyItem(a, b);
727 728 729 730 731 732 733
			break;
		case T_Path:
			retval = _equalPath(a, b);
			break;
		case T_IndexPath:
			retval = _equalIndexPath(a, b);
			break;
734 735
		case T_NestPath:
			retval = _equalNestPath(a, b);
736 737 738 739 740 741 742 743 744 745
			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;
V
Vadim B. Mikheev 已提交
746 747 748
		case T_SubPlan:
			retval = _equalSubPlan(a, b);
			break;
749 750
		case T_JoinInfo:
			retval = _equalJoinInfo(a, b);
751 752 753 754 755 756 757 758 759 760
			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:
761
			{
762 763 764 765
				List	   *la = (List *) a;
				List	   *lb = (List *) b;
				List	   *l;

766 767 768 769
				/* Try to reject by length check before we grovel through
				 * all the elements...
				 */
				if (length(la) != length(lb))
770
					return false;
771 772 773
				foreach(l, la)
				{
					if (!equal(lfirst(l), lfirst(lb)))
774
						return false;
775 776 777
					lb = lnext(lb);
				}
				retval = true;
778
			}
779
			break;
780 781 782 783 784 785 786 787 788
		case T_Query:
			retval = _equalQuery(a, b);
			break;
		case T_RangeTblEntry:
			retval = _equalRangeTblEntry(a, b);
			break;
		case T_TargetEntry:
			retval = _equalTargetEntry(a, b);
			break;
789 790 791 792 793 794
		case T_CaseExpr:
			retval = _equalCaseExpr(a, b);
			break;
		case T_CaseWhen:
			retval = _equalCaseWhen(a, b);
			break;
795 796 797 798
		default:
			elog(NOTICE, "equal: don't know whether nodes of type %d are equal",
				 nodeTag(a));
			break;
799
	}
800 801

	return retval;
802 803 804
}

/*
805
 * equali
806
 *	  compares two lists of integers
807
 */
808
static bool
809
equali(List *a, List *b)
810
{
811
	List	   *l;
812

813
	foreach(l, a)
814
	{
815 816 817
		if (b == NIL)
			return false;
		if (lfirsti(l) != lfirsti(b))
818
			return false;
819
		b = lnext(b);
820
	}
821 822
	if (b != NIL)
		return false;
823
	return true;
824
}