1 /*-------------------------------------------------------------------------
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
15 * src/backend/nodes/equalfuncs.c
17 *-------------------------------------------------------------------------
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
33 /* Compare a simple scalar field (int, float, bool, enum, etc) */
34 #define COMPARE_SCALAR_FIELD(fldname) \
36 if (a->fldname != b->fldname) \
40 /* Compare a field that is a pointer to some kind of Node or Node tree */
41 #define COMPARE_NODE_FIELD(fldname) \
43 if (!equal(a->fldname, b->fldname)) \
47 /* Compare a field that is a pointer to a Bitmapset */
48 #define COMPARE_BITMAPSET_FIELD(fldname) \
50 if (!bms_equal(a->fldname, b->fldname)) \
54 /* Compare a field that is a pointer to a C string, or perhaps NULL */
55 #define COMPARE_STRING_FIELD(fldname) \
57 if (!equalstr(a->fldname, b->fldname)) \
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) \
68 if (memcmp(a->fldname, b->fldname, sizeof(a->fldname)) != 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) \
75 if (memcmp(a->fldname, b->fldname, (sz)) != 0) \
79 /* Compare a parse location field (this is a no-op, per note above) */
80 #define COMPARE_LOCATION_FIELD(fldname) \
83 /* Compare a CoercionForm field (also a no-op, per comment in primnodes.h) */
84 #define COMPARE_COERCIONFORM_FIELD(fldname) \
88 #include "equalfuncs.funcs.c"
92 * Support functions for nodes with custom_copy_equal attribute
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...
112 return datumIsEqual(a
->constvalue
, b
->constvalue
,
113 a
->constbyval
, a
->constlen
);
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
))
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 */
139 !equal(&a
->val
, &b
->val
))
141 COMPARE_LOCATION_FIELD(location
);
147 _equalBitmapset(const Bitmapset
*a
, const Bitmapset
*b
)
149 return bms_equal(a
, b
);
153 * Lists are handled specially
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
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...
175 forboth(item_a
, a
, item_b
, b
)
177 if (!equal(lfirst(item_a
), lfirst(item_b
)))
182 forboth(item_a
, a
, item_b
, b
)
184 if (lfirst_int(item_a
) != lfirst_int(item_b
))
189 forboth(item_a
, a
, item_b
, b
)
191 if (lfirst_oid(item_a
) != lfirst_oid(item_b
))
196 forboth(item_a
, a
, item_b
, b
)
198 if (lfirst_xid(item_a
) != lfirst_xid(item_b
))
203 elog(ERROR
, "unrecognized list node type: %d",
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
);
220 * returns whether two nodes are equal
223 equal(const void *a
, const void *b
)
231 * note that a!=b, so only one of them can be NULL
233 if (a
== NULL
|| b
== NULL
)
237 * are they the same type of nodes?
239 if (nodeTag(a
) != nodeTag(b
))
242 /* Guard against stack overflow due to overly complex expressions */
247 #include "equalfuncs.switch.c"
253 retval
= _equalList(a
, b
);
257 elog(ERROR
, "unrecognized node type: %d",
259 retval
= false; /* keep compiler quiet */