LCOV - code coverage report
Current view: top level - src/backend/nodes - equalfuncs.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 76.1 % 67 51
Test Date: 2026-02-17 17:20:33 Functions: 83.3 % 6 5
Legend: Lines:     hit not hit

            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-2026, 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      1312319 : _equalConst(const Const *a, const Const *b)
      97              : {
      98      1312319 :     COMPARE_SCALAR_FIELD(consttype);
      99      1296336 :     COMPARE_SCALAR_FIELD(consttypmod);
     100      1296326 :     COMPARE_SCALAR_FIELD(constcollid);
     101      1293108 :     COMPARE_SCALAR_FIELD(constlen);
     102      1293108 :     COMPARE_SCALAR_FIELD(constisnull);
     103      1292976 :     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      1292976 :     if (a->constisnull)
     111        79048 :         return true;
     112      1213928 :     return datumIsEqual(a->constvalue, b->constvalue,
     113      1213928 :                         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      1503755 : _equalA_Const(const A_Const *a, const A_Const *b)
     135              : {
     136      1503755 :     COMPARE_SCALAR_FIELD(isnull);
     137              :     /* Hack for in-line val field.  Also val is not valid if isnull is true */
     138      1503755 :     if (!a->isnull &&
     139      1415671 :         !equal(&a->val, &b->val))
     140            0 :         return false;
     141              :     COMPARE_LOCATION_FIELD(location);
     142              : 
     143      1503755 :     return true;
     144              : }
     145              : 
     146              : static bool
     147        33069 : _equalBitmapset(const Bitmapset *a, const Bitmapset *b)
     148              : {
     149        33069 :     return bms_equal(a, b);
     150              : }
     151              : 
     152              : /*
     153              :  * Lists are handled specially
     154              :  */
     155              : static bool
     156     16120091 : _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     16120091 :     COMPARE_SCALAR_FIELD(type);
     166     16120091 :     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     16039233 :     switch (a->type)
     173              :     {
     174     13162564 :         case T_List:
     175     46115839 :             forboth(item_a, a, item_b, b)
     176              :             {
     177     33058873 :                 if (!equal(lfirst(item_a), lfirst(item_b)))
     178       105598 :                     return false;
     179              :             }
     180     13056966 :             break;
     181       240694 :         case T_IntList:
     182      3849195 :             forboth(item_a, a, item_b, b)
     183              :             {
     184      3608509 :                 if (lfirst_int(item_a) != lfirst_int(item_b))
     185            8 :                     return false;
     186              :             }
     187       240686 :             break;
     188      2635975 :         case T_OidList:
     189      4973750 :             forboth(item_a, a, item_b, b)
     190              :             {
     191      2889774 :                 if (lfirst_oid(item_a) != lfirst_oid(item_b))
     192       551999 :                     return false;
     193              :             }
     194      2083976 :             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     15381628 :     return true;
     215              : }
     216              : 
     217              : 
     218              : /*
     219              :  * equal
     220              :  *    returns whether two nodes are equal
     221              :  */
     222              : bool
     223    116200661 : equal(const void *a, const void *b)
     224              : {
     225              :     bool        retval;
     226              : 
     227    116200661 :     if (a == b)
     228     48820308 :         return true;
     229              : 
     230              :     /*
     231              :      * note that a!=b, so only one of them can be NULL
     232              :      */
     233     67380353 :     if (a == NULL || b == NULL)
     234        91418 :         return false;
     235              : 
     236              :     /*
     237              :      * are they the same type of nodes?
     238              :      */
     239     67288935 :     if (nodeTag(a) != nodeTag(b))
     240      1052910 :         return false;
     241              : 
     242              :     /* Guard against stack overflow due to overly complex expressions */
     243     66236025 :     check_stack_depth();
     244              : 
     245     66236025 :     switch (nodeTag(a))
     246              :     {
     247              : #include "equalfuncs.switch.c"
     248              : 
     249     16120091 :         case T_List:
     250              :         case T_IntList:
     251              :         case T_OidList:
     252              :         case T_XidList:
     253     16120091 :             retval = _equalList(a, b);
     254     16120091 :             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     66236025 :     return retval;
     264              : }
        

Generated by: LCOV version 2.0-1