PostgreSQL Source Code  git master
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 
95 static 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 
116 static 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 
133 static bool
134 _equalA_Const(const A_Const *a, const A_Const *b)
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 
146 static bool
148 {
149  return bms_equal(a, b);
150 }
151 
152 /*
153  * Lists are handled specially
154  */
155 static 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  */
222 bool
223 equal(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
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:224
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:70
int a
Definition: isn.c:69
Assert(fmt[strlen(fmt) - 1] !='\n')
#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: postgres.c:3531
bool(* nodeEqual)(const struct ExtensibleNode *a, const struct ExtensibleNode *b)
Definition: extensible.h:68
Definition: pg_list.h:54
const char * type