LCOV - code coverage report
Current view: top level - src/backend/nodes - copyfuncs.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 83.9 % 62 52
Test Date: 2026-02-17 17:20:33 Functions: 80.0 % 5 4
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * copyfuncs.c
       4              :  *    Copy functions for Postgres tree nodes.
       5              :  *
       6              :  *
       7              :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       8              :  * Portions Copyright (c) 1994, Regents of the University of California
       9              :  *
      10              :  * IDENTIFICATION
      11              :  *    src/backend/nodes/copyfuncs.c
      12              :  *
      13              :  *-------------------------------------------------------------------------
      14              :  */
      15              : 
      16              : #include "postgres.h"
      17              : 
      18              : #include "miscadmin.h"
      19              : #include "utils/datum.h"
      20              : 
      21              : 
      22              : /*
      23              :  * Macros to simplify copying of different kinds of fields.  Use these
      24              :  * wherever possible to reduce the chance for silly typos.  Note that these
      25              :  * hard-wire the convention that the local variables in a Copy routine are
      26              :  * named 'newnode' and 'from'.
      27              :  */
      28              : 
      29              : /* Copy a simple scalar field (int, float, bool, enum, etc) */
      30              : #define COPY_SCALAR_FIELD(fldname) \
      31              :     (newnode->fldname = from->fldname)
      32              : 
      33              : /* Copy a field that is a pointer to some kind of Node or Node tree */
      34              : #define COPY_NODE_FIELD(fldname) \
      35              :     (newnode->fldname = copyObjectImpl(from->fldname))
      36              : 
      37              : /* Copy a field that is a pointer to a Bitmapset */
      38              : #define COPY_BITMAPSET_FIELD(fldname) \
      39              :     (newnode->fldname = bms_copy(from->fldname))
      40              : 
      41              : /* Copy a field that is a pointer to a C string, or perhaps NULL */
      42              : #define COPY_STRING_FIELD(fldname) \
      43              :     (newnode->fldname = from->fldname ? pstrdup(from->fldname) : NULL)
      44              : 
      45              : /* Copy a field that is an inline array */
      46              : #define COPY_ARRAY_FIELD(fldname) \
      47              :     memcpy(newnode->fldname, from->fldname, sizeof(newnode->fldname))
      48              : 
      49              : /* Copy a field that is a pointer to a simple palloc'd object of size sz */
      50              : #define COPY_POINTER_FIELD(fldname, sz) \
      51              :     do { \
      52              :         Size    _size = (sz); \
      53              :         if (_size > 0) \
      54              :         { \
      55              :             newnode->fldname = palloc(_size); \
      56              :             memcpy(newnode->fldname, from->fldname, _size); \
      57              :         } \
      58              :     } while (0)
      59              : 
      60              : /* Copy a parse location field (for Copy, this is same as scalar case) */
      61              : #define COPY_LOCATION_FIELD(fldname) \
      62              :     (newnode->fldname = from->fldname)
      63              : 
      64              : 
      65              : #include "copyfuncs.funcs.c"
      66              : 
      67              : 
      68              : /*
      69              :  * Support functions for nodes with custom_copy_equal attribute
      70              :  */
      71              : 
      72              : static Const *
      73      1827081 : _copyConst(const Const *from)
      74              : {
      75      1827081 :     Const      *newnode = makeNode(Const);
      76              : 
      77      1827081 :     COPY_SCALAR_FIELD(consttype);
      78      1827081 :     COPY_SCALAR_FIELD(consttypmod);
      79      1827081 :     COPY_SCALAR_FIELD(constcollid);
      80      1827081 :     COPY_SCALAR_FIELD(constlen);
      81              : 
      82      1827081 :     if (from->constbyval || from->constisnull)
      83              :     {
      84              :         /*
      85              :          * passed by value so just copy the datum. Also, don't try to copy
      86              :          * struct when value is null!
      87              :          */
      88      1265265 :         newnode->constvalue = from->constvalue;
      89              :     }
      90              :     else
      91              :     {
      92              :         /*
      93              :          * passed by reference.  We need a palloc'd copy.
      94              :          */
      95       561816 :         newnode->constvalue = datumCopy(from->constvalue,
      96       561816 :                                         from->constbyval,
      97       561816 :                                         from->constlen);
      98              :     }
      99              : 
     100      1827081 :     COPY_SCALAR_FIELD(constisnull);
     101      1827081 :     COPY_SCALAR_FIELD(constbyval);
     102      1827081 :     COPY_LOCATION_FIELD(location);
     103              : 
     104      1827081 :     return newnode;
     105              : }
     106              : 
     107              : static A_Const *
     108       813302 : _copyA_Const(const A_Const *from)
     109              : {
     110       813302 :     A_Const    *newnode = makeNode(A_Const);
     111              : 
     112       813302 :     COPY_SCALAR_FIELD(isnull);
     113       813302 :     if (!from->isnull)
     114              :     {
     115              :         /* This part must duplicate other _copy*() functions. */
     116       767794 :         COPY_SCALAR_FIELD(val.node.type);
     117       767794 :         switch (nodeTag(&from->val))
     118              :         {
     119       261709 :             case T_Integer:
     120       261709 :                 COPY_SCALAR_FIELD(val.ival.ival);
     121       261709 :                 break;
     122         6440 :             case T_Float:
     123         6440 :                 COPY_STRING_FIELD(val.fval.fval);
     124         6440 :                 break;
     125        37433 :             case T_Boolean:
     126        37433 :                 COPY_SCALAR_FIELD(val.boolval.boolval);
     127        37433 :                 break;
     128       460177 :             case T_String:
     129       460177 :                 COPY_STRING_FIELD(val.sval.sval);
     130       460177 :                 break;
     131         2035 :             case T_BitString:
     132         2035 :                 COPY_STRING_FIELD(val.bsval.bsval);
     133         2035 :                 break;
     134            0 :             default:
     135            0 :                 elog(ERROR, "unrecognized node type: %d",
     136              :                      (int) nodeTag(&from->val));
     137              :                 break;
     138              :         }
     139              :     }
     140              : 
     141       813302 :     COPY_LOCATION_FIELD(location);
     142              : 
     143       813302 :     return newnode;
     144              : }
     145              : 
     146              : static ExtensibleNode *
     147            0 : _copyExtensibleNode(const ExtensibleNode *from)
     148              : {
     149              :     ExtensibleNode *newnode;
     150              :     const ExtensibleNodeMethods *methods;
     151              : 
     152            0 :     methods = GetExtensibleNodeMethods(from->extnodename, false);
     153            0 :     newnode = (ExtensibleNode *) newNode(methods->node_size,
     154              :                                          T_ExtensibleNode);
     155            0 :     COPY_STRING_FIELD(extnodename);
     156              : 
     157              :     /* copy the private fields */
     158            0 :     methods->nodeCopy(newnode, from);
     159              : 
     160            0 :     return newnode;
     161              : }
     162              : 
     163              : static Bitmapset *
     164         1544 : _copyBitmapset(const Bitmapset *from)
     165              : {
     166         1544 :     return bms_copy(from);
     167              : }
     168              : 
     169              : 
     170              : /*
     171              :  * copyObjectImpl -- implementation of copyObject(); see nodes/nodes.h
     172              :  *
     173              :  * Create a copy of a Node tree or list.  This is a "deep" copy: all
     174              :  * substructure is copied too, recursively.
     175              :  */
     176              : void *
     177    111518346 : copyObjectImpl(const void *from)
     178              : {
     179              :     void       *retval;
     180              : 
     181    111518346 :     if (from == NULL)
     182     48578884 :         return NULL;
     183              : 
     184              :     /* Guard against stack overflow due to overly complex expressions */
     185     62939462 :     check_stack_depth();
     186              : 
     187     62939462 :     switch (nodeTag(from))
     188              :     {
     189              : #include "copyfuncs.switch.c"
     190              : 
     191     11329855 :         case T_List:
     192     11329855 :             retval = list_copy_deep(from);
     193     11329855 :             break;
     194              : 
     195              :             /*
     196              :              * Lists of integers, OIDs and XIDs don't need to be deep-copied,
     197              :              * so we perform a shallow copy via list_copy()
     198              :              */
     199       844269 :         case T_IntList:
     200              :         case T_OidList:
     201              :         case T_XidList:
     202       844269 :             retval = list_copy(from);
     203       844269 :             break;
     204              : 
     205            0 :         default:
     206            0 :             elog(ERROR, "unrecognized node type: %d", (int) nodeTag(from));
     207              :             retval = NULL;      /* keep compiler quiet */
     208              :             break;
     209              :     }
     210              : 
     211     62939462 :     return retval;
     212              : }
        

Generated by: LCOV version 2.0-1