Line data Source code
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 :
95 : static bool
96 2320422 : _equalConst(const Const *a, const Const *b)
97 : {
98 2320422 : COMPARE_SCALAR_FIELD(consttype);
99 2290740 : COMPARE_SCALAR_FIELD(consttypmod);
100 2290720 : COMPARE_SCALAR_FIELD(constcollid);
101 2284926 : COMPARE_SCALAR_FIELD(constlen);
102 2284926 : COMPARE_SCALAR_FIELD(constisnull);
103 2284772 : 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 2284772 : if (a->constisnull)
111 131162 : return true;
112 2153610 : return datumIsEqual(a->constvalue, b->constvalue,
113 2153610 : a->constbyval, a->constlen);
114 : }
115 :
116 : static bool
117 0 : _equalExtensibleNode(const ExtensibleNode *a, const ExtensibleNode *b)
118 : {
119 : const ExtensibleNodeMethods *methods;
120 :
121 0 : COMPARE_STRING_FIELD(extnodename);
122 :
123 : /* At this point, we know extnodename is the same for both nodes. */
124 0 : methods = GetExtensibleNodeMethods(a->extnodename, false);
125 :
126 : /* compare the private fields */
127 0 : if (!methods->nodeEqual(a, b))
128 0 : return false;
129 :
130 0 : return true;
131 : }
132 :
133 : static bool
134 2715414 : _equalA_Const(const A_Const *a, const A_Const *b)
135 : {
136 2715414 : COMPARE_SCALAR_FIELD(isnull);
137 : /* Hack for in-line val field. Also val is not valid if isnull is true */
138 2715414 : if (!a->isnull &&
139 2557342 : !equal(&a->val, &b->val))
140 0 : return false;
141 : COMPARE_LOCATION_FIELD(location);
142 :
143 2715414 : return true;
144 : }
145 :
146 : static bool
147 43172 : _equalBitmapset(const Bitmapset *a, const Bitmapset *b)
148 : {
149 43172 : return bms_equal(a, b);
150 : }
151 :
152 : /*
153 : * Lists are handled specially
154 : */
155 : static bool
156 28059138 : _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 : */
165 28059138 : COMPARE_SCALAR_FIELD(type);
166 28059138 : 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 27938734 : switch (a->type)
173 : {
174 23448112 : case T_List:
175 79522932 : forboth(item_a, a, item_b, b)
176 : {
177 56259128 : if (!equal(lfirst(item_a), lfirst(item_b)))
178 184308 : return false;
179 : }
180 23263804 : break;
181 371468 : case T_IntList:
182 5883934 : forboth(item_a, a, item_b, b)
183 : {
184 5512482 : if (lfirst_int(item_a) != lfirst_int(item_b))
185 16 : return false;
186 : }
187 371452 : break;
188 4119154 : case T_OidList:
189 7777460 : forboth(item_a, a, item_b, b)
190 : {
191 4449926 : if (lfirst_oid(item_a) != lfirst_oid(item_b))
192 791620 : return false;
193 : }
194 3327534 : break;
195 0 : case T_XidList:
196 0 : forboth(item_a, a, item_b, b)
197 : {
198 0 : if (lfirst_xid(item_a) != lfirst_xid(item_b))
199 0 : return false;
200 : }
201 0 : break;
202 0 : default:
203 0 : 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 26962790 : return true;
215 : }
216 :
217 :
218 : /*
219 : * equal
220 : * returns whether two nodes are equal
221 : */
222 : bool
223 202483674 : equal(const void *a, const void *b)
224 : {
225 : bool retval;
226 :
227 202483674 : if (a == b)
228 87202398 : return true;
229 :
230 : /*
231 : * note that a!=b, so only one of them can be NULL
232 : */
233 115281276 : if (a == NULL || b == NULL)
234 201822 : return false;
235 :
236 : /*
237 : * are they the same type of nodes?
238 : */
239 115079454 : if (nodeTag(a) != nodeTag(b))
240 1751394 : return false;
241 :
242 : /* Guard against stack overflow due to overly complex expressions */
243 113328060 : check_stack_depth();
244 :
245 113328060 : switch (nodeTag(a))
246 : {
247 : #include "equalfuncs.switch.c"
248 :
249 28059138 : case T_List:
250 : case T_IntList:
251 : case T_OidList:
252 : case T_XidList:
253 28059138 : retval = _equalList(a, b);
254 28059138 : break;
255 :
256 0 : default:
257 0 : elog(ERROR, "unrecognized node type: %d",
258 : (int) nodeTag(a));
259 : retval = false; /* keep compiler quiet */
260 : break;
261 : }
262 :
263 113328060 : return retval;
264 : }
|