/*------------------------------------------------------------------------- * * copyfuncs.c * Copy functions for Postgres tree nodes. * * * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION * src/backend/nodes/copyfuncs.c * *------------------------------------------------------------------------- */ #include "postgres.h" #include "miscadmin.h" #include "utils/datum.h" /* * Macros to simplify copying of different kinds of fields. Use these * wherever possible to reduce the chance for silly typos. Note that these * hard-wire the convention that the local variables in a Copy routine are * named 'newnode' and 'from'. */ /* Copy a simple scalar field (int, float, bool, enum, etc) */ #define COPY_SCALAR_FIELD(fldname) \ (newnode->fldname = from->fldname) /* Copy a field that is a pointer to some kind of Node or Node tree */ #define COPY_NODE_FIELD(fldname) \ (newnode->fldname = copyObjectImpl(from->fldname)) /* Copy a field that is a pointer to a Bitmapset */ #define COPY_BITMAPSET_FIELD(fldname) \ (newnode->fldname = bms_copy(from->fldname)) /* Copy a field that is a pointer to a C string, or perhaps NULL */ #define COPY_STRING_FIELD(fldname) \ (newnode->fldname = from->fldname ? pstrdup(from->fldname) : (char *) NULL) /* Copy a field that is an inline array */ #define COPY_ARRAY_FIELD(fldname) \ memcpy(newnode->fldname, from->fldname, sizeof(newnode->fldname)) /* Copy a field that is a pointer to a simple palloc'd object of size sz */ #define COPY_POINTER_FIELD(fldname, sz) \ do { \ Size _size = (sz); \ if (_size > 0) \ { \ newnode->fldname = palloc(_size); \ memcpy(newnode->fldname, from->fldname, _size); \ } \ } while (0) /* Copy a parse location field (for Copy, this is same as scalar case) */ #define COPY_LOCATION_FIELD(fldname) \ (newnode->fldname = from->fldname) #include "copyfuncs.funcs.c" /* * Support functions for nodes with custom_copy_equal attribute */ static Const * _copyConst(const Const *from) { Const *newnode = makeNode(Const); COPY_SCALAR_FIELD(consttype); COPY_SCALAR_FIELD(consttypmod); COPY_SCALAR_FIELD(constcollid); COPY_SCALAR_FIELD(constlen); if (from->constbyval || from->constisnull) { /* * passed by value so just copy the datum. Also, don't try to copy * struct when value is null! */ newnode->constvalue = from->constvalue; } else { /* * passed by reference. We need a palloc'd copy. */ newnode->constvalue = datumCopy(from->constvalue, from->constbyval, from->constlen); } COPY_SCALAR_FIELD(constisnull); COPY_SCALAR_FIELD(constbyval); COPY_LOCATION_FIELD(location); return newnode; } static A_Const * _copyA_Const(const A_Const *from) { A_Const *newnode = makeNode(A_Const); COPY_SCALAR_FIELD(isnull); if (!from->isnull) { /* This part must duplicate other _copy*() functions. */ COPY_SCALAR_FIELD(val.node.type); switch (nodeTag(&from->val)) { case T_Integer: COPY_SCALAR_FIELD(val.ival.ival); break; case T_Float: COPY_STRING_FIELD(val.fval.fval); break; case T_Boolean: COPY_SCALAR_FIELD(val.boolval.boolval); break; case T_String: COPY_STRING_FIELD(val.sval.sval); break; case T_BitString: COPY_STRING_FIELD(val.bsval.bsval); break; default: elog(ERROR, "unrecognized node type: %d", (int) nodeTag(&from->val)); break; } } COPY_LOCATION_FIELD(location); return newnode; } static ExtensibleNode * _copyExtensibleNode(const ExtensibleNode *from) { ExtensibleNode *newnode; const ExtensibleNodeMethods *methods; methods = GetExtensibleNodeMethods(from->extnodename, false); newnode = (ExtensibleNode *) newNode(methods->node_size, T_ExtensibleNode); COPY_STRING_FIELD(extnodename); /* copy the private fields */ methods->nodeCopy(newnode, from); return newnode; } static Bitmapset * _copyBitmapset(const Bitmapset *from) { return bms_copy(from); } /* * copyObjectImpl -- implementation of copyObject(); see nodes/nodes.h * * Create a copy of a Node tree or list. This is a "deep" copy: all * substructure is copied too, recursively. */ void * copyObjectImpl(const void *from) { void *retval; if (from == NULL) return NULL; /* Guard against stack overflow due to overly complex expressions */ check_stack_depth(); switch (nodeTag(from)) { #include "copyfuncs.switch.c" case T_List: retval = list_copy_deep(from); break; /* * Lists of integers, OIDs and XIDs don't need to be deep-copied, * so we perform a shallow copy via list_copy() */ case T_IntList: case T_OidList: case T_XidList: retval = list_copy(from); break; default: elog(ERROR, "unrecognized node type: %d", (int) nodeTag(from)); retval = 0; /* keep compiler quiet */ break; } return retval; }