213 lines
4.8 KiB
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;
|
|
}
|