| /*------------------------------------------------------------------------- |
| * |
| * copyfuncs.c |
| * Copy functions for Postgres tree nodes. |
| * |
| * NOTE: we currently support copying all node types found in parse and |
| * plan trees. We do not support copying executor state trees; there |
| * is no need for that, and no point in maintaining all the code that |
| * would be needed. We also do not support copying Path trees, mainly |
| * because the circular linkages between RelOptInfo and Path nodes can't |
| * be handled easily in a simple depth-first traversal. |
| * |
| * |
| * Portions Copyright (c) 2012-Present VMware, Inc. or its affiliates. |
| * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group |
| * Portions Copyright (c) 1994, Regents of the University of California |
| * |
| * IDENTIFICATION |
| * src/backend/nodes/copyfuncs.c |
| * |
| *------------------------------------------------------------------------- |
| */ |
| |
| #include "postgres.h" |
| |
| #include "catalog/gp_distribution_policy.h" |
| #include "catalog/heap.h" |
| #include "miscadmin.h" |
| #include "nodes/altertablenodes.h" |
| #include "nodes/extensible.h" |
| #include "nodes/pathnodes.h" |
| #include "nodes/plannodes.h" |
| #include "utils/datum.h" |
| #include "cdb/cdbgang.h" |
| #include "utils/rel.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) |
| |
| #define COPY_BINARY_FIELD(fldname, sz) \ |
| do { \ |
| Size _size = (sz); \ |
| memcpy(&newnode->fldname, &from->fldname, _size); \ |
| } while (0) |
| |
| /* Copy a field that is a varlena datum */ |
| #define COPY_VARLENA_FIELD(fldname, len) \ |
| do { \ |
| if (from->fldname) \ |
| { \ |
| newnode->fldname = (bytea *) DatumGetPointer( \ |
| datumCopy(PointerGetDatum(from->fldname), false, len)); \ |
| } \ |
| } while (0) |
| |
| /* Copy a parse location field (for Copy, this is same as scalar case) */ |
| #define COPY_LOCATION_FIELD(fldname) \ |
| (newnode->fldname = from->fldname) |
| |
| |
| /* **************************************************************** |
| * plannodes.h copy functions |
| * **************************************************************** |
| */ |
| #include "copyfuncs.funcs.c" |
| |
| |
| 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; |
| } |