Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * copyfuncs.c
4 : : * Copy functions for Postgres tree nodes.
5 : : *
6 : : *
7 : : * Portions Copyright (c) 1996-2024, 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) : (char *) 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 *
645 peter@eisentraut.org 73 :CBC 361645 : _copyConst(const Const *from)
74 : : {
75 : 361645 : Const *newnode = makeNode(Const);
76 : :
77 : 361645 : COPY_SCALAR_FIELD(consttype);
78 : 361645 : COPY_SCALAR_FIELD(consttypmod);
79 : 361645 : COPY_SCALAR_FIELD(constcollid);
80 : 361645 : COPY_SCALAR_FIELD(constlen);
81 : :
82 [ + + + + ]: 361645 : 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 : 263318 : newnode->constvalue = from->constvalue;
89 : : }
90 : : else
91 : : {
92 : : /*
93 : : * passed by reference. We need a palloc'd copy.
94 : : */
95 : 98327 : newnode->constvalue = datumCopy(from->constvalue,
96 : 98327 : from->constbyval,
97 : 98327 : from->constlen);
98 : : }
99 : :
100 : 361645 : COPY_SCALAR_FIELD(constisnull);
101 : 361645 : COPY_SCALAR_FIELD(constbyval);
102 : 361645 : COPY_LOCATION_FIELD(location);
103 : :
6935 tgl@sss.pgh.pa.us 104 : 361645 : return newnode;
105 : : }
106 : :
107 : : static A_Const *
645 peter@eisentraut.org 108 : 52660 : _copyA_Const(const A_Const *from)
109 : : {
110 : 52660 : A_Const *newnode = makeNode(A_Const);
111 : :
112 : 52660 : COPY_SCALAR_FIELD(isnull);
113 [ + + ]: 52660 : if (!from->isnull)
114 : : {
115 : : /* This part must duplicate other _copy*() functions. */
116 : 51299 : COPY_SCALAR_FIELD(val.node.type);
117 [ + + + + : 51299 : switch (nodeTag(&from->val))
- - ]
118 : : {
119 : 27907 : case T_Integer:
120 : 27907 : COPY_SCALAR_FIELD(val.ival.ival);
121 : 27907 : break;
122 : 156 : case T_Float:
123 [ + - ]: 156 : COPY_STRING_FIELD(val.fval.fval);
124 : 156 : break;
125 : 1057 : case T_Boolean:
126 : 1057 : COPY_SCALAR_FIELD(val.boolval.boolval);
127 : 1057 : break;
128 : 22179 : case T_String:
129 [ + - ]: 22179 : COPY_STRING_FIELD(val.sval.sval);
130 : 22179 : break;
645 peter@eisentraut.org 131 :UBC 0 : case T_BitString:
132 [ # # ]: 0 : COPY_STRING_FIELD(val.bsval.bsval);
133 : 0 : break;
134 : 0 : default:
135 [ # # ]: 0 : elog(ERROR, "unrecognized node type: %d",
136 : : (int) nodeTag(&from->val));
137 : : break;
138 : : }
139 : : }
140 : :
645 peter@eisentraut.org 141 :CBC 52660 : COPY_LOCATION_FIELD(location);
142 : :
6935 tgl@sss.pgh.pa.us 143 : 52660 : return newnode;
144 : : }
145 : :
146 : : static ExtensibleNode *
645 peter@eisentraut.org 147 :UBC 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 : :
3119 rhaas@postgresql.org 160 : 0 : return newnode;
161 : : }
162 : :
163 : : static Bitmapset *
518 tgl@sss.pgh.pa.us 164 : 0 : _copyBitmapset(const Bitmapset *from)
165 : : {
166 : 0 : 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 *
645 peter@eisentraut.org 177 :CBC 18059174 : copyObjectImpl(const void *from)
178 : : {
179 : : void *retval;
180 : :
181 [ + + ]: 18059174 : if (from == NULL)
182 : 7396775 : return NULL;
183 : :
184 : : /* Guard against stack overflow due to overly complex expressions */
185 : 10662399 : check_stack_depth();
186 : :
187 [ + + + + : 10662399 : switch (nodeTag(from))
+ + + + +
+ + + + +
+ + + + +
+ + - + +
+ + + + +
+ + + + +
- + + + +
+ + + + +
+ + + + -
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + -
+ + + + +
+ - + - +
+ + - + +
+ + + + +
+ + + + +
+ + + + -
+ + + + +
- + - - -
- - + - -
- + + - -
- - + + +
+ + + + -
+ + + + +
- + + + +
+ + + + -
+ + - - -
+ + + + +
- + + + +
- - - + +
- + - - -
- - - - +
+ + + + +
+ + + + +
+ + - - +
+ + - + +
+ + + + -
+ + - - +
+ - - + +
+ + + + -
- - - - -
- - + + +
+ + - - -
+ + + + +
- + - - -
- + - - -
- - + - -
- - + - +
- + + + +
+ + - - -
+ + + + +
+ + + + +
+ + + + -
+ - + + +
+ + + + +
- + + + +
- + - + +
+ + + + +
+ - - + +
+ + - + +
+ - ]
188 : : {
189 : : #include "copyfuncs.switch.c"
190 : :
191 : 1590364 : case T_List:
192 : 1590364 : retval = list_copy_deep(from);
193 : 1590364 : 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 : : */
7263 neilc@samurai.com 199 : 131649 : case T_IntList:
200 : : case T_OidList:
201 : : case T_XidList:
202 : 131649 : retval = list_copy(from);
8854 tgl@sss.pgh.pa.us 203 : 131649 : break;
204 : :
9715 bruce@momjian.us 205 :UBC 0 : default:
7572 tgl@sss.pgh.pa.us 206 [ # # ]: 0 : elog(ERROR, "unrecognized node type: %d", (int) nodeTag(from));
207 : : retval = 0; /* keep compiler quiet */
208 : : break;
209 : : }
210 : :
9716 bruce@momjian.us 211 :CBC 10662399 : return retval;
212 : : }
|