postgresql/src/backend/nodes/copyfuncs.c

213 lines
4.8 KiB
C

/*-------------------------------------------------------------------------
*
* 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;
}