LCOV - code coverage report
Current view: top level - src/backend/nodes - equalfuncs.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 51 67 76.1 %
Date: 2024-04-20 15:11:32 Functions: 5 6 83.3 %
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-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     2184496 : _equalConst(const Const *a, const Const *b)
      97             : {
      98     2184496 :     COMPARE_SCALAR_FIELD(consttype);
      99     2156690 :     COMPARE_SCALAR_FIELD(consttypmod);
     100     2156670 :     COMPARE_SCALAR_FIELD(constcollid);
     101     2151080 :     COMPARE_SCALAR_FIELD(constlen);
     102     2151080 :     COMPARE_SCALAR_FIELD(constisnull);
     103     2150806 :     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     2150806 :     if (a->constisnull)
     111      122170 :         return true;
     112     2028636 :     return datumIsEqual(a->constvalue, b->constvalue,
     113     2028636 :                         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     2561414 : _equalA_Const(const A_Const *a, const A_Const *b)
     135             : {
     136     2561414 :     COMPARE_SCALAR_FIELD(isnull);
     137             :     /* Hack for in-line val field.  Also val is not valid if isnull is true */
     138     2561414 :     if (!a->isnull &&
     139     2418158 :         !equal(&a->val, &b->val))
     140           0 :         return false;
     141             :     COMPARE_LOCATION_FIELD(location);
     142             : 
     143     2561414 :     return true;
     144             : }
     145             : 
     146             : static bool
     147       40062 : _equalBitmapset(const Bitmapset *a, const Bitmapset *b)
     148             : {
     149       40062 :     return bms_equal(a, b);
     150             : }
     151             : 
     152             : /*
     153             :  * Lists are handled specially
     154             :  */
     155             : static bool
     156    26376512 : _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    26376512 :     COMPARE_SCALAR_FIELD(type);
     166    26376512 :     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    26259666 :     switch (a->type)
     173             :     {
     174    22068800 :         case T_List:
     175    77553890 :             forboth(item_a, a, item_b, b)
     176             :             {
     177    55635798 :                 if (!equal(lfirst(item_a), lfirst(item_b)))
     178      150708 :                     return false;
     179             :             }
     180    21918092 :             break;
     181      367118 :         case T_IntList:
     182     6634880 :             forboth(item_a, a, item_b, b)
     183             :             {
     184     6267778 :                 if (lfirst_int(item_a) != lfirst_int(item_b))
     185          16 :                     return false;
     186             :             }
     187      367102 :             break;
     188     3823748 :         case T_OidList:
     189     7271232 :             forboth(item_a, a, item_b, b)
     190             :             {
     191     4131536 :                 if (lfirst_oid(item_a) != lfirst_oid(item_b))
     192      684052 :                     return false;
     193             :             }
     194     3139696 :             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    25424890 :     return true;
     215             : }
     216             : 
     217             : 
     218             : /*
     219             :  * equal
     220             :  *    returns whether two nodes are equal
     221             :  */
     222             : bool
     223   192991372 : equal(const void *a, const void *b)
     224             : {
     225             :     bool        retval;
     226             : 
     227   192991372 :     if (a == b)
     228    81984004 :         return true;
     229             : 
     230             :     /*
     231             :      * note that a!=b, so only one of them can be NULL
     232             :      */
     233   111007368 :     if (a == NULL || b == NULL)
     234      197682 :         return false;
     235             : 
     236             :     /*
     237             :      * are they the same type of nodes?
     238             :      */
     239   110809686 :     if (nodeTag(a) != nodeTag(b))
     240     1541976 :         return false;
     241             : 
     242             :     /* Guard against stack overflow due to overly complex expressions */
     243   109267710 :     check_stack_depth();
     244             : 
     245   109267710 :     switch (nodeTag(a))
     246             :     {
     247             : #include "equalfuncs.switch.c"
     248             : 
     249    26376512 :         case T_List:
     250             :         case T_IntList:
     251             :         case T_OidList:
     252             :         case T_XidList:
     253    26376512 :             retval = _equalList(a, b);
     254    26376512 :             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   109267710 :     return retval;
     264             : }

Generated by: LCOV version 1.14