LCOV - differential code coverage report
Current view: top level - src/backend/nodes - equalfuncs.c (source / functions) Coverage Total Hit UNC UIC GBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 76.8 % 69 53 5 11 2 45 4 2 5 6 9 45
Current Date: 2023-04-08 15:15:32 Functions: 83.3 % 6 5 1 4 1 1 1 4
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           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-2023, 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 ECB             : #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 GIC       60014 : _equalConst(const Const *a, const Const *b)
      97 ECB             : {
      98 CBC       60014 :     COMPARE_SCALAR_FIELD(consttype);
      99 GIC       50471 :     COMPARE_SCALAR_FIELD(consttypmod);
     100 CBC       50461 :     COMPARE_SCALAR_FIELD(constcollid);
     101 GBC       48097 :     COMPARE_SCALAR_FIELD(constlen);
     102           48097 :     COMPARE_SCALAR_FIELD(constisnull);
     103 GIC       48023 :     COMPARE_SCALAR_FIELD(constbyval);
     104 EUB             :     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 GIC       48023 :     if (a->constisnull)
     111             598 :         return true;
     112           47425 :     return datumIsEqual(a->constvalue, b->constvalue,
     113           47425 :                         a->constbyval, a->constlen);
     114                 : }
     115                 : 
     116                 : static bool
     117 UIC           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 GIC          75 : _equalA_Const(const A_Const *a, const A_Const *b)
     135                 : {
     136 GNC          75 :     COMPARE_SCALAR_FIELD(isnull);
     137                 :     /* Hack for in-line val field.  Also val is not valid if isnull is true */
     138              75 :     if (!a->isnull &&
     139 GIC          75 :         !equal(&a->val, &b->val))
     140 UIC           0 :         return false;
     141                 :     COMPARE_LOCATION_FIELD(location);
     142                 : 
     143 GIC          75 :     return true;
     144                 : }
     145                 : 
     146                 : static bool
     147 GNC       17226 : _equalBitmapset(const Bitmapset *a, const Bitmapset *b)
     148                 : {
     149           17226 :     return bms_equal(a, b);
     150                 : }
     151                 : 
     152                 : /*
     153                 :  * Lists are handled specially
     154                 :  */
     155                 : static bool
     156 GIC     1608669 : _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         1608669 :     COMPARE_SCALAR_FIELD(type);
     166         1608669 :     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         1561184 :     switch (a->type)
     173                 :     {
     174          162133 :         case T_List:
     175          399909 :             forboth(item_a, a, item_b, b)
     176                 :             {
     177          295952 :                 if (!equal(lfirst(item_a), lfirst(item_b)))
     178           58176 :                     return false;
     179                 :             }
     180          103957 :             break;
     181             195 :         case T_IntList:
     182            1628 :             forboth(item_a, a, item_b, b)
     183                 :             {
     184            1441 :                 if (lfirst_int(item_a) != lfirst_int(item_b))
     185               8 :                     return false;
     186                 :             }
     187             187 :             break;
     188         1398856 :         case T_OidList:
     189         2579886 :             forboth(item_a, a, item_b, b)
     190                 :             {
     191         1422420 :                 if (lfirst_oid(item_a) != lfirst_oid(item_b))
     192          241390 :                     return false;
     193                 :             }
     194         1157466 :             break;
     195 UNC           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 UIC           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 GIC     1261610 :     Assert(item_a == NULL);
     212         1261610 :     Assert(item_b == NULL);
     213                 : 
     214         1261610 :     return true;
     215                 : }
     216                 : 
     217                 : 
     218                 : /*
     219                 :  * equal
     220                 :  *    returns whether two nodes are equal
     221                 :  */
     222                 : bool
     223         4694945 : equal(const void *a, const void *b)
     224                 : {
     225                 :     bool        retval;
     226                 : 
     227         4694945 :     if (a == b)
     228          129538 :         return true;
     229                 : 
     230                 :     /*
     231                 :      * note that a!=b, so only one of them can be NULL
     232                 :      */
     233         4565407 :     if (a == NULL || b == NULL)
     234           94194 :         return false;
     235                 : 
     236                 :     /*
     237                 :      * are they the same type of nodes?
     238                 :      */
     239         4471213 :     if (nodeTag(a) != nodeTag(b))
     240          614878 :         return false;
     241                 : 
     242                 :     /* Guard against stack overflow due to overly complex expressions */
     243         3856335 :     check_stack_depth();
     244                 : 
     245         3856335 :     switch (nodeTag(a))
     246                 :     {
     247                 : #include "equalfuncs.switch.c"
     248                 : 
     249         1608669 :         case T_List:
     250                 :         case T_IntList:
     251                 :         case T_OidList:
     252                 :         case T_XidList:
     253         1608669 :             retval = _equalList(a, b);
     254         1608669 :             break;
     255                 : 
     256 UIC           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 GIC     3856335 :     return retval;
     264                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a