LCOV - code coverage report
Current view: top level - src/backend/nodes - equalfuncs.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 76.1 % 67 51
Test Date: 2026-07-08 06:15:42 Functions: 83.3 % 6 5
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 85.6 % 411 352

             Branch data     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                 :     1723102 : _equalConst(const Const *a, const Const *b)
      97                 :             : {
      98         [ +  + ]:     1723102 :     COMPARE_SCALAR_FIELD(consttype);
      99         [ +  + ]:     1701624 :     COMPARE_SCALAR_FIELD(consttypmod);
     100         [ +  + ]:     1701612 :     COMPARE_SCALAR_FIELD(constcollid);
     101         [ -  + ]:     1696305 :     COMPARE_SCALAR_FIELD(constlen);
     102         [ +  + ]:     1696305 :     COMPARE_SCALAR_FIELD(constisnull);
     103         [ -  + ]:     1696133 :     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         [ +  + ]:     1696133 :     if (a->constisnull)
     111                 :      105125 :         return true;
     112                 :     1591008 :     return datumIsEqual(a->constvalue, b->constvalue,
     113                 :     1591008 :                         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                 :     1894170 : _equalA_Const(const A_Const *a, const A_Const *b)
     135                 :             : {
     136         [ -  + ]:     1894170 :     COMPARE_SCALAR_FIELD(isnull);
     137                 :             :     /* Hack for in-line val field.  Also val is not valid if isnull is true */
     138         [ +  + ]:     1894170 :     if (!a->isnull &&
     139         [ -  + ]:     1783842 :         !equal(&a->val, &b->val))
     140                 :           0 :         return false;
     141                 :             :     COMPARE_LOCATION_FIELD(location);
     142                 :             : 
     143                 :     1894170 :     return true;
     144                 :             : }
     145                 :             : 
     146                 :             : static bool
     147                 :       55599 : _equalBitmapset(const Bitmapset *a, const Bitmapset *b)
     148                 :             : {
     149                 :       55599 :     return bms_equal(a, b);
     150                 :             : }
     151                 :             : 
     152                 :             : /*
     153                 :             :  * Lists are handled specially
     154                 :             :  */
     155                 :             : static bool
     156                 :    20636862 : _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         [ -  + ]:    20636862 :     COMPARE_SCALAR_FIELD(type);
     166         [ +  + ]:    20636862 :     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   [ +  +  +  -  :    20514818 :     switch (a->type)
                      - ]
     173                 :             :     {
     174                 :    16430193 :         case T_List:
     175   [ +  -  +  +  :    57443364 :             forboth(item_a, a, item_b, b)
          +  -  +  +  +  
             +  +  -  +  
                      + ]
     176                 :             :             {
     177         [ +  + ]:    41165323 :                 if (!equal(lfirst(item_a), lfirst(item_b)))
     178                 :      152152 :                     return false;
     179                 :             :             }
     180                 :    16278041 :             break;
     181                 :      306015 :         case T_IntList:
     182   [ +  -  +  +  :     4799396 :             forboth(item_a, a, item_b, b)
          +  -  +  +  +  
             +  +  -  +  
                      + ]
     183                 :             :             {
     184         [ +  + ]:     4493392 :                 if (lfirst_int(item_a) != lfirst_int(item_b))
     185                 :          11 :                     return false;
     186                 :             :             }
     187                 :      306004 :             break;
     188                 :     3778610 :         case T_OidList:
     189   [ +  -  +  +  :     7171942 :             forboth(item_a, a, item_b, b)
          +  -  +  +  +  
             +  +  -  +  
                      + ]
     190                 :             :             {
     191         [ +  + ]:     4117457 :                 if (lfirst_oid(item_a) != lfirst_oid(item_b))
     192                 :      724125 :                     return false;
     193                 :             :             }
     194                 :     3054485 :             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                 :    19638530 :     return true;
     215                 :             : }
     216                 :             : 
     217                 :             : 
     218                 :             : /*
     219                 :             :  * equal
     220                 :             :  *    returns whether two nodes are equal
     221                 :             :  */
     222                 :             : bool
     223                 :   149724352 : equal(const void *a, const void *b)
     224                 :             : {
     225                 :             :     bool        retval;
     226                 :             : 
     227         [ +  + ]:   149724352 :     if (a == b)
     228                 :    63928457 :         return true;
     229                 :             : 
     230                 :             :     /*
     231                 :             :      * note that a!=b, so only one of them can be NULL
     232                 :             :      */
     233   [ +  +  +  + ]:    85795895 :     if (a == NULL || b == NULL)
     234                 :      130613 :         return false;
     235                 :             : 
     236                 :             :     /*
     237                 :             :      * are they the same type of nodes?
     238                 :             :      */
     239         [ +  + ]:    85665282 :     if (nodeTag(a) != nodeTag(b))
     240                 :     1588995 :         return false;
     241                 :             : 
     242                 :             :     /* Guard against stack overflow due to overly complex expressions */
     243                 :    84076287 :     check_stack_depth();
     244                 :             : 
     245   [ +  +  +  +  :    84076287 :     switch (nodeTag(a))
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  -  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          -  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  -  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  -  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  -  +  +  
          +  +  +  +  -  
          -  +  +  -  -  
          -  +  -  -  -  
          +  -  +  +  +  
             +  +  +  - ]
     246                 :             :     {
     247                 :             : #include "equalfuncs.switch.c"
     248                 :             : 
     249                 :    20636862 :         case T_List:
     250                 :             :         case T_IntList:
     251                 :             :         case T_OidList:
     252                 :             :         case T_XidList:
     253                 :    20636862 :             retval = _equalList(a, b);
     254                 :    20636862 :             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                 :    84076287 :     return retval;
     264                 :             : }
        

Generated by: LCOV version 2.0-1