Revert commit 66c0185a3 and follow-on patches.
[pgsql.git] / src / backend / nodes / equalfuncs.c
blob7caae4d48b050804a9f885f599209eab66836d6c
1 /*-------------------------------------------------------------------------
3 * equalfuncs.c
4 * Equality functions to compare node trees.
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.
11 * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
12 * Portions Copyright (c) 1994, Regents of the University of California
14 * IDENTIFICATION
15 * src/backend/nodes/equalfuncs.c
17 *-------------------------------------------------------------------------
20 #include "postgres.h"
22 #include "miscadmin.h"
23 #include "utils/datum.h"
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'.
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)
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)
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)
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)
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))
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)
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)
79 /* Compare a parse location field (this is a no-op, per note above) */
80 #define COMPARE_LOCATION_FIELD(fldname) \
81 ((void) 0)
83 /* Compare a CoercionForm field (also a no-op, per comment in primnodes.h) */
84 #define COMPARE_COERCIONFORM_FIELD(fldname) \
85 ((void) 0)
88 #include "equalfuncs.funcs.c"
92 * Support functions for nodes with custom_copy_equal attribute
95 static bool
96 _equalConst(const Const *a, const Const *b)
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);
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...
110 if (a->constisnull)
111 return true;
112 return datumIsEqual(a->constvalue, b->constvalue,
113 a->constbyval, a->constlen);
116 static bool
117 _equalExtensibleNode(const ExtensibleNode *a, const ExtensibleNode *b)
119 const ExtensibleNodeMethods *methods;
121 COMPARE_STRING_FIELD(extnodename);
123 /* At this point, we know extnodename is the same for both nodes. */
124 methods = GetExtensibleNodeMethods(a->extnodename, false);
126 /* compare the private fields */
127 if (!methods->nodeEqual(a, b))
128 return false;
130 return true;
133 static bool
134 _equalA_Const(const A_Const *a, const A_Const *b)
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);
143 return true;
146 static bool
147 _equalBitmapset(const Bitmapset *a, const Bitmapset *b)
149 return bms_equal(a, b);
153 * Lists are handled specially
155 static bool
156 _equalList(const List *a, const List *b)
158 const ListCell *item_a;
159 const ListCell *item_b;
162 * Try to reject by simple scalar checks before grovelling through all the
163 * list elements...
165 COMPARE_SCALAR_FIELD(type);
166 COMPARE_SCALAR_FIELD(length);
169 * We place the switch outside the loop for the sake of efficiency; this
170 * may not be worth doing...
172 switch (a->type)
174 case T_List:
175 forboth(item_a, a, item_b, b)
177 if (!equal(lfirst(item_a), lfirst(item_b)))
178 return false;
180 break;
181 case T_IntList:
182 forboth(item_a, a, item_b, b)
184 if (lfirst_int(item_a) != lfirst_int(item_b))
185 return false;
187 break;
188 case T_OidList:
189 forboth(item_a, a, item_b, b)
191 if (lfirst_oid(item_a) != lfirst_oid(item_b))
192 return false;
194 break;
195 case T_XidList:
196 forboth(item_a, a, item_b, b)
198 if (lfirst_xid(item_a) != lfirst_xid(item_b))
199 return false;
201 break;
202 default:
203 elog(ERROR, "unrecognized list node type: %d",
204 (int) a->type);
205 return false; /* keep compiler quiet */
209 * If we got here, we should have run out of elements of both lists
211 Assert(item_a == NULL);
212 Assert(item_b == NULL);
214 return true;
219 * equal
220 * returns whether two nodes are equal
222 bool
223 equal(const void *a, const void *b)
225 bool retval;
227 if (a == b)
228 return true;
231 * note that a!=b, so only one of them can be NULL
233 if (a == NULL || b == NULL)
234 return false;
237 * are they the same type of nodes?
239 if (nodeTag(a) != nodeTag(b))
240 return false;
242 /* Guard against stack overflow due to overly complex expressions */
243 check_stack_depth();
245 switch (nodeTag(a))
247 #include "equalfuncs.switch.c"
249 case T_List:
250 case T_IntList:
251 case T_OidList:
252 case T_XidList:
253 retval = _equalList(a, b);
254 break;
256 default:
257 elog(ERROR, "unrecognized node type: %d",
258 (int) nodeTag(a));
259 retval = false; /* keep compiler quiet */
260 break;
263 return retval;