Age Owner Branch data TLA 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
4512 peter_e@gmx.net 96 :CBC 78850 : _equalConst(const Const *a, const Const *b)
97 : : {
7811 tgl@sss.pgh.pa.us 98 [ + + ]: 78850 : COMPARE_SCALAR_FIELD(consttype);
6238 99 [ + + ]: 64625 : COMPARE_SCALAR_FIELD(consttypmod);
4814 peter_e@gmx.net 100 [ + + ]: 64615 : COMPARE_SCALAR_FIELD(constcollid);
7811 tgl@sss.pgh.pa.us 101 [ - + ]: 61878 : COMPARE_SCALAR_FIELD(constlen);
102 [ + + ]: 61878 : COMPARE_SCALAR_FIELD(constisnull);
103 [ - + ]: 61744 : 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 : : */
8878 110 [ + + ]: 61744 : if (a->constisnull)
111 : 5956 : return true;
8677 112 : 55788 : return datumIsEqual(a->constvalue, b->constvalue,
113 : 55788 : a->constbyval, a->constlen);
114 : : }
115 : :
116 : : static bool
645 peter@eisentraut.org 117 :UBC 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 : :
5302 tgl@sss.pgh.pa.us 130 : 0 : return true;
131 : : }
132 : :
133 : : static bool
645 peter@eisentraut.org 134 :CBC 81 : _equalA_Const(const A_Const *a, const A_Const *b)
135 : : {
392 tgl@sss.pgh.pa.us 136 [ - + ]: 81 : COMPARE_SCALAR_FIELD(isnull);
137 : : /* Hack for in-line val field. Also val is not valid if isnull is true */
138 [ + - ]: 81 : if (!a->isnull &&
645 peter@eisentraut.org 139 [ - + ]: 81 : !equal(&a->val, &b->val))
7794 tgl@sss.pgh.pa.us 140 :UBC 0 : return false;
141 : : COMPARE_LOCATION_FIELD(location);
142 : :
7794 tgl@sss.pgh.pa.us 143 :CBC 81 : return true;
144 : : }
145 : :
146 : : static bool
518 147 : 19916 : _equalBitmapset(const Bitmapset *a, const Bitmapset *b)
148 : : {
149 : 19916 : return bms_equal(a, b);
150 : : }
151 : :
152 : : /*
153 : : * Lists are handled specially
154 : : */
155 : : static bool
645 peter@eisentraut.org 156 : 2083924 : _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 [ - + ]: 2083924 : COMPARE_SCALAR_FIELD(type);
166 [ + + ]: 2083924 : 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 [ + + + - : 2025927 : switch (a->type)
- ]
173 : : {
174 : 194456 : case T_List:
175 [ + - + + : 484795 : forboth(item_a, a, item_b, b)
+ - + + +
+ + - +
+ ]
176 : : {
177 [ + + ]: 363831 : if (!equal(lfirst(item_a), lfirst(item_b)))
178 : 73492 : return false;
179 : : }
180 : 120964 : break;
181 : 2805 : case T_IntList:
182 [ + - + + : 9458 : forboth(item_a, a, item_b, b)
+ - + + +
+ + - +
+ ]
183 : : {
184 [ + + ]: 6661 : if (lfirst_int(item_a) != lfirst_int(item_b))
185 : 8 : return false;
186 : : }
187 : 2797 : break;
188 : 1828666 : case T_OidList:
189 [ + - + + : 3373911 : forboth(item_a, a, item_b, b)
+ - + + +
+ + - +
+ ]
190 : : {
191 [ + + ]: 1889976 : if (lfirst_oid(item_a) != lfirst_oid(item_b))
192 : 344731 : return false;
193 : : }
194 : 1483935 : break;
642 alvherre@alvh.no-ip. 195 :UBC 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;
645 peter@eisentraut.org 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 : : */
645 peter@eisentraut.org 211 [ - + ]:CBC 1607696 : Assert(item_a == NULL);
212 [ - + ]: 1607696 : Assert(item_b == NULL);
213 : :
7902 tgl@sss.pgh.pa.us 214 : 1607696 : return true;
215 : : }
216 : :
217 : :
218 : : /*
219 : : * equal
220 : : * returns whether two nodes are equal
221 : : */
222 : : bool
645 peter@eisentraut.org 223 : 5959804 : equal(const void *a, const void *b)
224 : : {
225 : : bool retval;
226 : :
227 [ + + ]: 5959804 : if (a == b)
228 : 159544 : return true;
229 : :
230 : : /*
231 : : * note that a!=b, so only one of them can be NULL
232 : : */
233 [ + + + + ]: 5800260 : if (a == NULL || b == NULL)
234 : 99830 : return false;
235 : :
236 : : /*
237 : : * are they the same type of nodes?
238 : : */
239 [ + + ]: 5700430 : if (nodeTag(a) != nodeTag(b))
240 : 771422 : return false;
241 : :
242 : : /* Guard against stack overflow due to overly complex expressions */
243 : 4929008 : check_stack_depth();
244 : :
245 [ + + - - : 4929008 : switch (nodeTag(a))
+ + + + +
+ - + + -
+ - + + +
+ + - + -
+ + - + +
+ + + + +
+ + + + -
- - - - -
- - - - -
+ + - + -
- - - - +
+ + + - +
+ + - + +
+ - - - -
- - - - -
+ - - - -
- - - - +
- - - - -
- - - - +
+ + - + +
- + - - -
- - - + -
- - - - -
- - - - -
- - - - -
- - - - -
- - - + -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
+ - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- + + - -
- + - + -
- + - +
- ]
246 : : {
247 : : #include "equalfuncs.switch.c"
248 : :
9715 bruce@momjian.us 249 : 2083924 : case T_List:
250 : : case T_IntList:
251 : : case T_OidList:
252 : : case T_XidList:
7263 neilc@samurai.com 253 : 2083924 : retval = _equalList(a, b);
9715 bruce@momjian.us 254 : 2083924 : break;
255 : :
9715 bruce@momjian.us 256 :UBC 0 : default:
7572 tgl@sss.pgh.pa.us 257 [ # # ]: 0 : elog(ERROR, "unrecognized node type: %d",
258 : : (int) nodeTag(a));
259 : : retval = false; /* keep compiler quiet */
260 : : break;
261 : : }
262 : :
9716 bruce@momjian.us 263 :CBC 4929008 : return retval;
264 : : }
|