PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
equalfuncs.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * equalfuncs.c
4 * Equality functions to compare node trees.
5 *
6 * NOTE: it is intentional that parse location fields (in nodes that have
7 * one) are not compared. This is because we want, for example, a variable
8 * "x" to be considered equal() to another reference to "x" in the query.
9 *
10 *
11 * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
12 * Portions Copyright (c) 1994, Regents of the University of California
13 *
14 * IDENTIFICATION
15 * src/backend/nodes/equalfuncs.c
16 *
17 *-------------------------------------------------------------------------
18 */
19
20#include "postgres.h"
21
22#include "miscadmin.h"
23#include "utils/datum.h"
24
25
26/*
27 * Macros to simplify comparison of different kinds of fields. Use these
28 * wherever possible to reduce the chance for silly typos. Note that these
29 * hard-wire the convention that the local variables in an Equal routine are
30 * named 'a' and 'b'.
31 */
32
33/* Compare a simple scalar field (int, float, bool, enum, etc) */
34#define COMPARE_SCALAR_FIELD(fldname) \
35 do { \
36 if (a->fldname != b->fldname) \
37 return false; \
38 } while (0)
39
40/* Compare a field that is a pointer to some kind of Node or Node tree */
41#define COMPARE_NODE_FIELD(fldname) \
42 do { \
43 if (!equal(a->fldname, b->fldname)) \
44 return false; \
45 } while (0)
46
47/* Compare a field that is a pointer to a Bitmapset */
48#define COMPARE_BITMAPSET_FIELD(fldname) \
49 do { \
50 if (!bms_equal(a->fldname, b->fldname)) \
51 return false; \
52 } while (0)
53
54/* Compare a field that is a pointer to a C string, or perhaps NULL */
55#define COMPARE_STRING_FIELD(fldname) \
56 do { \
57 if (!equalstr(a->fldname, b->fldname)) \
58 return false; \
59 } while (0)
60
61/* Macro for comparing string fields that might be NULL */
62#define equalstr(a, b) \
63 (((a) != NULL && (b) != NULL) ? (strcmp(a, b) == 0) : (a) == (b))
64
65/* Compare a field that is an inline array */
66#define COMPARE_ARRAY_FIELD(fldname) \
67 do { \
68 if (memcmp(a->fldname, b->fldname, sizeof(a->fldname)) != 0) \
69 return false; \
70 } while (0)
71
72/* Compare a field that is a pointer to a simple palloc'd object of size sz */
73#define COMPARE_POINTER_FIELD(fldname, sz) \
74 do { \
75 if (memcmp(a->fldname, b->fldname, (sz)) != 0) \
76 return false; \
77 } while (0)
78
79/* Compare a parse location field (this is a no-op, per note above) */
80#define COMPARE_LOCATION_FIELD(fldname) \
81 ((void) 0)
82
83/* Compare a CoercionForm field (also a no-op, per comment in primnodes.h) */
84#define COMPARE_COERCIONFORM_FIELD(fldname) \
85 ((void) 0)
86
87
88#include "equalfuncs.funcs.c"
89
90
91/*
92 * Support functions for nodes with custom_copy_equal attribute
93 */
94
95static bool
96_equalConst(const Const *a, const Const *b)
97{
98 COMPARE_SCALAR_FIELD(consttype);
99 COMPARE_SCALAR_FIELD(consttypmod);
100 COMPARE_SCALAR_FIELD(constcollid);
101 COMPARE_SCALAR_FIELD(constlen);
102 COMPARE_SCALAR_FIELD(constisnull);
103 COMPARE_SCALAR_FIELD(constbyval);
104 COMPARE_LOCATION_FIELD(location);
105
106 /*
107 * We treat all NULL constants of the same type as equal. Someday this
108 * might need to change? But datumIsEqual doesn't work on nulls, so...
109 */
110 if (a->constisnull)
111 return true;
112 return datumIsEqual(a->constvalue, b->constvalue,
113 a->constbyval, a->constlen);
114}
115
116static bool
118{
119 const ExtensibleNodeMethods *methods;
120
121 COMPARE_STRING_FIELD(extnodename);
122
123 /* At this point, we know extnodename is the same for both nodes. */
124 methods = GetExtensibleNodeMethods(a->extnodename, false);
125
126 /* compare the private fields */
127 if (!methods->nodeEqual(a, b))
128 return false;
129
130 return true;
131}
132
133static bool
135{
136 COMPARE_SCALAR_FIELD(isnull);
137 /* Hack for in-line val field. Also val is not valid if isnull is true */
138 if (!a->isnull &&
139 !equal(&a->val, &b->val))
140 return false;
141 COMPARE_LOCATION_FIELD(location);
142
143 return true;
144}
145
146static bool
148{
149 return bms_equal(a, b);
150}
151
152/*
153 * Lists are handled specially
154 */
155static bool
156_equalList(const List *a, const List *b)
157{
158 const ListCell *item_a;
159 const ListCell *item_b;
160
161 /*
162 * Try to reject by simple scalar checks before grovelling through all the
163 * list elements...
164 */
166 COMPARE_SCALAR_FIELD(length);
167
168 /*
169 * We place the switch outside the loop for the sake of efficiency; this
170 * may not be worth doing...
171 */
172 switch (a->type)
173 {
174 case T_List:
175 forboth(item_a, a, item_b, b)
176 {
177 if (!equal(lfirst(item_a), lfirst(item_b)))
178 return false;
179 }
180 break;
181 case T_IntList:
182 forboth(item_a, a, item_b, b)
183 {
184 if (lfirst_int(item_a) != lfirst_int(item_b))
185 return false;
186 }
187 break;
188 case T_OidList:
189 forboth(item_a, a, item_b, b)
190 {
191 if (lfirst_oid(item_a) != lfirst_oid(item_b))
192 return false;
193 }
194 break;
195 case T_XidList:
196 forboth(item_a, a, item_b, b)
197 {
198 if (lfirst_xid(item_a) != lfirst_xid(item_b))
199 return false;
200 }
201 break;
202 default:
203 elog(ERROR, "unrecognized list node type: %d",
204 (int) a->type);
205 return false; /* keep compiler quiet */
206 }
207
208 /*
209 * If we got here, we should have run out of elements of both lists
210 */
211 Assert(item_a == NULL);
212 Assert(item_b == NULL);
213
214 return true;
215}
216
217
218/*
219 * equal
220 * returns whether two nodes are equal
221 */
222bool
223equal(const void *a, const void *b)
224{
225 bool retval;
226
227 if (a == b)
228 return true;
229
230 /*
231 * note that a!=b, so only one of them can be NULL
232 */
233 if (a == NULL || b == NULL)
234 return false;
235
236 /*
237 * are they the same type of nodes?
238 */
239 if (nodeTag(a) != nodeTag(b))
240 return false;
241
242 /* Guard against stack overflow due to overly complex expressions */
244
245 switch (nodeTag(a))
246 {
247#include "equalfuncs.switch.c"
248
249 case T_List:
250 case T_IntList:
251 case T_OidList:
252 case T_XidList:
253 retval = _equalList(a, b);
254 break;
255
256 default:
257 elog(ERROR, "unrecognized node type: %d",
258 (int) nodeTag(a));
259 retval = false; /* keep compiler quiet */
260 break;
261 }
262
263 return retval;
264}
bool bms_equal(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:142
#define Assert(condition)
Definition: c.h:812
bool datumIsEqual(Datum value1, Datum value2, bool typByVal, int typLen)
Definition: datum.c:223
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
static bool _equalExtensibleNode(const ExtensibleNode *a, const ExtensibleNode *b)
Definition: equalfuncs.c:117
#define COMPARE_LOCATION_FIELD(fldname)
Definition: equalfuncs.c:80
#define COMPARE_SCALAR_FIELD(fldname)
Definition: equalfuncs.c:34
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:223
static bool _equalBitmapset(const Bitmapset *a, const Bitmapset *b)
Definition: equalfuncs.c:147
static bool _equalConst(const Const *a, const Const *b)
Definition: equalfuncs.c:96
#define COMPARE_STRING_FIELD(fldname)
Definition: equalfuncs.c:55
static bool _equalList(const List *a, const List *b)
Definition: equalfuncs.c:156
static bool _equalA_Const(const A_Const *a, const A_Const *b)
Definition: equalfuncs.c:134
const ExtensibleNodeMethods * GetExtensibleNodeMethods(const char *extnodename, bool missing_ok)
Definition: extensible.c:125
int b
Definition: isn.c:69
int a
Definition: isn.c:68
#define nodeTag(nodeptr)
Definition: nodes.h:133
#define lfirst(lc)
Definition: pg_list.h:172
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:518
#define lfirst_int(lc)
Definition: pg_list.h:173
#define lfirst_oid(lc)
Definition: pg_list.h:174
#define lfirst_xid(lc)
Definition: pg_list.h:175
void check_stack_depth(void)
Definition: stack_depth.c:95
bool(* nodeEqual)(const struct ExtensibleNode *a, const struct ExtensibleNode *b)
Definition: extensible.h:68
Definition: pg_list.h:54
const char * type