/src/postgres/src/backend/nodes/readfuncs.c
Line | Count | Source |
1 | | /*------------------------------------------------------------------------- |
2 | | * |
3 | | * readfuncs.c |
4 | | * Reader functions for Postgres tree nodes. |
5 | | * |
6 | | * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group |
7 | | * Portions Copyright (c) 1994, Regents of the University of California |
8 | | * |
9 | | * |
10 | | * IDENTIFICATION |
11 | | * src/backend/nodes/readfuncs.c |
12 | | * |
13 | | * NOTES |
14 | | * Parse location fields are written out by outfuncs.c, but only for |
15 | | * debugging use. When reading a location field, we normally discard |
16 | | * the stored value and set the location field to -1 (ie, "unknown"). |
17 | | * This is because nodes coming from a stored rule should not be thought |
18 | | * to have a known location in the current query's text. |
19 | | * |
20 | | * However, if restore_location_fields is true, we do restore location |
21 | | * fields from the string. This is currently intended only for use by the |
22 | | * debug_write_read_parse_plan_trees test code, which doesn't want to cause |
23 | | * any change in the node contents. |
24 | | * |
25 | | *------------------------------------------------------------------------- |
26 | | */ |
27 | | #include "postgres.h" |
28 | | |
29 | | #include "miscadmin.h" |
30 | | #include "nodes/bitmapset.h" |
31 | | #include "nodes/readfuncs.h" |
32 | | |
33 | | |
34 | | /* |
35 | | * Macros to simplify reading of different kinds of fields. Use these |
36 | | * wherever possible to reduce the chance for silly typos. Note that these |
37 | | * hard-wire conventions about the names of the local variables in a Read |
38 | | * routine. |
39 | | */ |
40 | | |
41 | | /* Macros for declaring appropriate local variables */ |
42 | | |
43 | | /* A few guys need only local_node */ |
44 | | #define READ_LOCALS_NO_FIELDS(nodeTypeName) \ |
45 | 0 | nodeTypeName *local_node = makeNode(nodeTypeName) |
46 | | |
47 | | /* And a few guys need only the pg_strtok support fields */ |
48 | | #define READ_TEMP_LOCALS() \ |
49 | 0 | const char *token; \ |
50 | 0 | int length |
51 | | |
52 | | /* ... but most need both */ |
53 | | #define READ_LOCALS(nodeTypeName) \ |
54 | 0 | READ_LOCALS_NO_FIELDS(nodeTypeName); \ |
55 | 0 | READ_TEMP_LOCALS() |
56 | | |
57 | | /* Read an integer field (anything written as ":fldname %d") */ |
58 | | #define READ_INT_FIELD(fldname) \ |
59 | 0 | token = pg_strtok(ctx, &length); /* skip :fldname */ \ |
60 | 0 | token = pg_strtok(ctx, &length); /* get field value */ \ |
61 | 0 | local_node->fldname = atoi(token) |
62 | | |
63 | | /* Read an unsigned integer field (anything written as ":fldname %u") */ |
64 | | #define READ_UINT_FIELD(fldname) \ |
65 | 0 | token = pg_strtok(ctx, &length); /* skip :fldname */ \ |
66 | 0 | token = pg_strtok(ctx, &length); /* get field value */ \ |
67 | 0 | local_node->fldname = atoui(token) |
68 | | |
69 | | /* Read a signed integer field (anything written using INT64_FORMAT) */ |
70 | | #define READ_INT64_FIELD(fldname) \ |
71 | 0 | token = pg_strtok(ctx, &length); /* skip :fldname */ \ |
72 | 0 | token = pg_strtok(ctx, &length); /* get field value */ \ |
73 | 0 | local_node->fldname = strtoi64(token, NULL, 10) |
74 | | |
75 | | /* Read an unsigned integer field (anything written using UINT64_FORMAT) */ |
76 | | #define READ_UINT64_FIELD(fldname) \ |
77 | 0 | token = pg_strtok(ctx, &length); /* skip :fldname */ \ |
78 | 0 | token = pg_strtok(ctx, &length); /* get field value */ \ |
79 | 0 | local_node->fldname = strtou64(token, NULL, 10) |
80 | | |
81 | | /* Read a long integer field (anything written as ":fldname %ld") */ |
82 | | #define READ_LONG_FIELD(fldname) \ |
83 | 0 | token = pg_strtok(ctx, &length); /* skip :fldname */ \ |
84 | 0 | token = pg_strtok(ctx, &length); /* get field value */ \ |
85 | 0 | local_node->fldname = atol(token) |
86 | | |
87 | | /* Read an OID field (don't hard-wire assumption that OID is same as uint) */ |
88 | | #define READ_OID_FIELD(fldname) \ |
89 | 0 | token = pg_strtok(ctx, &length); /* skip :fldname */ \ |
90 | 0 | token = pg_strtok(ctx, &length); /* get field value */ \ |
91 | 0 | local_node->fldname = atooid(token) |
92 | | |
93 | | /* Read a char field (ie, one ascii character) */ |
94 | | #define READ_CHAR_FIELD(fldname) \ |
95 | 0 | token = pg_strtok(ctx, &length); /* skip :fldname */ \ |
96 | 0 | token = pg_strtok(ctx, &length); /* get field value */ \ |
97 | 0 | /* avoid overhead of calling debackslash() for one char */ \ |
98 | 0 | local_node->fldname = (length == 0) ? '\0' : (token[0] == '\\' ? token[1] : token[0]) |
99 | | |
100 | | /* Read an enumerated-type field that was written as an integer code */ |
101 | | #define READ_ENUM_FIELD(fldname, enumtype) \ |
102 | 0 | token = pg_strtok(ctx, &length); /* skip :fldname */ \ |
103 | 0 | token = pg_strtok(ctx, &length); /* get field value */ \ |
104 | 0 | local_node->fldname = (enumtype) atoi(token) |
105 | | |
106 | | /* Read a float field */ |
107 | | #define READ_FLOAT_FIELD(fldname) \ |
108 | 0 | token = pg_strtok(ctx, &length); /* skip :fldname */ \ |
109 | 0 | token = pg_strtok(ctx, &length); /* get field value */ \ |
110 | 0 | local_node->fldname = atof(token) |
111 | | |
112 | | /* Read a boolean field */ |
113 | | #define READ_BOOL_FIELD(fldname) \ |
114 | 0 | token = pg_strtok(ctx, &length); /* skip :fldname */ \ |
115 | 0 | token = pg_strtok(ctx, &length); /* get field value */ \ |
116 | 0 | local_node->fldname = strtobool(token) |
117 | | |
118 | | /* Read a character-string field */ |
119 | | #define READ_STRING_FIELD(fldname) \ |
120 | 0 | token = pg_strtok(ctx, &length); /* skip :fldname */ \ |
121 | 0 | token = pg_strtok(ctx, &length); /* get field value */ \ |
122 | 0 | local_node->fldname = nullable_string(token, length) |
123 | | |
124 | | /* Read a parse location field (and possibly throw away the value) */ |
125 | | #ifdef DEBUG_NODE_TESTS_ENABLED |
126 | | #define READ_LOCATION_FIELD(fldname) \ |
127 | | token = pg_strtok(ctx, &length); /* skip :fldname */ \ |
128 | | token = pg_strtok(ctx, &length); /* get field value */ \ |
129 | | local_node->fldname = ctx->restore_location_fields ? atoi(token) : -1 |
130 | | #else |
131 | | #define READ_LOCATION_FIELD(fldname) \ |
132 | 0 | token = pg_strtok(ctx, &length); /* skip :fldname */ \ |
133 | 0 | token = pg_strtok(ctx, &length); /* get field value */ \ |
134 | 0 | (void) token; /* in case not used elsewhere */ \ |
135 | 0 | local_node->fldname = -1 /* set field to "unknown" */ |
136 | | #endif |
137 | | |
138 | | /* Read a Node field */ |
139 | | #define READ_NODE_FIELD(fldname) \ |
140 | 0 | token = pg_strtok(ctx, &length); /* skip :fldname */ \ |
141 | 0 | (void) token; /* in case not used elsewhere */ \ |
142 | 0 | local_node->fldname = nodeRead(ctx, NULL, 0) |
143 | | |
144 | | /* Read a bitmapset field */ |
145 | | #define READ_BITMAPSET_FIELD(fldname) \ |
146 | 0 | token = pg_strtok(ctx, &length); /* skip :fldname */ \ |
147 | 0 | (void) token; /* in case not used elsewhere */ \ |
148 | 0 | local_node->fldname = _readBitmapset(ctx) |
149 | | |
150 | | /* Read an attribute number array */ |
151 | | #define READ_ATTRNUMBER_ARRAY(fldname, len) \ |
152 | 0 | token = pg_strtok(ctx, &length); /* skip :fldname */ \ |
153 | 0 | local_node->fldname = readAttrNumberCols(ctx, len) |
154 | | |
155 | | /* Read an oid array */ |
156 | | #define READ_OID_ARRAY(fldname, len) \ |
157 | 0 | token = pg_strtok(ctx, &length); /* skip :fldname */ \ |
158 | 0 | local_node->fldname = readOidCols(ctx, len) |
159 | | |
160 | | /* Read an int array */ |
161 | | #define READ_INT_ARRAY(fldname, len) \ |
162 | 0 | token = pg_strtok(ctx, &length); /* skip :fldname */ \ |
163 | 0 | local_node->fldname = readIntCols(ctx, len) |
164 | | |
165 | | /* Read a bool array */ |
166 | | #define READ_BOOL_ARRAY(fldname, len) \ |
167 | 0 | token = pg_strtok(ctx, &length); /* skip :fldname */ \ |
168 | 0 | local_node->fldname = readBoolCols(ctx, len) |
169 | | |
170 | | /* Routine exit */ |
171 | | #define READ_DONE() \ |
172 | 0 | return local_node |
173 | | |
174 | | |
175 | | /* |
176 | | * NOTE: use atoi() to read values written with %d, or atoui() to read |
177 | | * values written with %u in outfuncs.c. An exception is OID values, |
178 | | * for which use atooid(). (As of 7.1, outfuncs.c writes OIDs as %u, |
179 | | * but this will probably change in the future.) |
180 | | */ |
181 | 0 | #define atoui(x) ((unsigned int) strtoul((x), NULL, 10)) |
182 | | |
183 | 0 | #define strtobool(x) ((*(x) == 't') ? true : false) |
184 | | |
185 | | static char * |
186 | | nullable_string(const char *token, int length) |
187 | 0 | { |
188 | | /* outToken emits <> for NULL, and pg_strtok makes that an empty string */ |
189 | 0 | if (length == 0) |
190 | 0 | return NULL; |
191 | | /* outToken emits "" for empty string */ |
192 | 0 | if (length == 2 && token[0] == '"' && token[1] == '"') |
193 | 0 | return pstrdup(""); |
194 | | /* otherwise, we must remove protective backslashes added by outToken */ |
195 | 0 | return debackslash(token, length); |
196 | 0 | } |
197 | | |
198 | | |
199 | | /* |
200 | | * _readBitmapset |
201 | | * |
202 | | * Note: this code is used in contexts where we know that a Bitmapset |
203 | | * is expected. There is equivalent code in nodeRead() that can read a |
204 | | * Bitmapset when we come across one in other contexts. |
205 | | */ |
206 | | static Bitmapset * |
207 | | _readBitmapset(ReadNodeContext *ctx) |
208 | 0 | { |
209 | 0 | Bitmapset *result = NULL; |
210 | |
|
211 | 0 | READ_TEMP_LOCALS(); |
212 | |
|
213 | 0 | token = pg_strtok(ctx, &length); |
214 | 0 | if (token == NULL) |
215 | 0 | elog(ERROR, "incomplete Bitmapset structure"); |
216 | 0 | if (length != 1 || token[0] != '(') |
217 | 0 | elog(ERROR, "unrecognized token: \"%.*s\"", length, token); |
218 | | |
219 | 0 | token = pg_strtok(ctx, &length); |
220 | 0 | if (token == NULL) |
221 | 0 | elog(ERROR, "incomplete Bitmapset structure"); |
222 | 0 | if (length != 1 || token[0] != 'b') |
223 | 0 | elog(ERROR, "unrecognized token: \"%.*s\"", length, token); |
224 | | |
225 | 0 | for (;;) |
226 | 0 | { |
227 | 0 | int val; |
228 | 0 | char *endptr; |
229 | |
|
230 | 0 | token = pg_strtok(ctx, &length); |
231 | 0 | if (token == NULL) |
232 | 0 | elog(ERROR, "unterminated Bitmapset structure"); |
233 | 0 | if (length == 1 && token[0] == ')') |
234 | 0 | break; |
235 | 0 | val = (int) strtol(token, &endptr, 10); |
236 | 0 | if (endptr != token + length) |
237 | 0 | elog(ERROR, "unrecognized integer: \"%.*s\"", length, token); |
238 | 0 | result = bms_add_member(result, val); |
239 | 0 | } |
240 | | |
241 | 0 | return result; |
242 | 0 | } |
243 | | |
244 | | /* |
245 | | * We export this function for use by extensions that define extensible nodes. |
246 | | * That's somewhat historical, though, because calling nodeRead() will work. |
247 | | */ |
248 | | Bitmapset * |
249 | | readBitmapset(ReadNodeContext *ctx) |
250 | 0 | { |
251 | 0 | return _readBitmapset(ctx); |
252 | 0 | } |
253 | | |
254 | | #include "readfuncs.funcs.c" |
255 | | |
256 | | |
257 | | /* |
258 | | * Support functions for nodes with custom_read_write attribute or |
259 | | * special_read_write attribute |
260 | | */ |
261 | | |
262 | | static Const * |
263 | | _readConst(ReadNodeContext *ctx) |
264 | 0 | { |
265 | 0 | READ_LOCALS(Const); |
266 | |
|
267 | 0 | READ_OID_FIELD(consttype); |
268 | 0 | READ_INT_FIELD(consttypmod); |
269 | 0 | READ_OID_FIELD(constcollid); |
270 | 0 | READ_INT_FIELD(constlen); |
271 | 0 | READ_BOOL_FIELD(constbyval); |
272 | 0 | READ_BOOL_FIELD(constisnull); |
273 | 0 | READ_LOCATION_FIELD(location); |
274 | |
|
275 | 0 | token = pg_strtok(ctx, &length); /* skip :constvalue */ |
276 | 0 | if (local_node->constisnull) |
277 | 0 | token = pg_strtok(ctx, &length); /* skip "<>" */ |
278 | 0 | else |
279 | 0 | local_node->constvalue = readDatum(ctx, local_node->constbyval); |
280 | |
|
281 | 0 | READ_DONE(); |
282 | 0 | } |
283 | | |
284 | | static BoolExpr * |
285 | | _readBoolExpr(ReadNodeContext *ctx) |
286 | 0 | { |
287 | 0 | READ_LOCALS(BoolExpr); |
288 | | |
289 | | /* do-it-yourself enum representation */ |
290 | 0 | token = pg_strtok(ctx, &length); /* skip :boolop */ |
291 | 0 | token = pg_strtok(ctx, &length); /* get field value */ |
292 | 0 | if (length == 3 && strncmp(token, "and", 3) == 0) |
293 | 0 | local_node->boolop = AND_EXPR; |
294 | 0 | else if (length == 2 && strncmp(token, "or", 2) == 0) |
295 | 0 | local_node->boolop = OR_EXPR; |
296 | 0 | else if (length == 3 && strncmp(token, "not", 3) == 0) |
297 | 0 | local_node->boolop = NOT_EXPR; |
298 | 0 | else |
299 | 0 | elog(ERROR, "unrecognized boolop \"%.*s\"", length, token); |
300 | | |
301 | 0 | READ_NODE_FIELD(args); |
302 | 0 | READ_LOCATION_FIELD(location); |
303 | |
|
304 | 0 | READ_DONE(); |
305 | 0 | } |
306 | | |
307 | | static A_Const * |
308 | | _readA_Const(ReadNodeContext *ctx) |
309 | 0 | { |
310 | 0 | READ_LOCALS(A_Const); |
311 | | |
312 | | /* We expect either NULL or :val here */ |
313 | 0 | token = pg_strtok(ctx, &length); |
314 | 0 | if (length == 4 && strncmp(token, "NULL", 4) == 0) |
315 | 0 | local_node->isnull = true; |
316 | 0 | else |
317 | 0 | { |
318 | 0 | union ValUnion *tmp = nodeRead(ctx, NULL, 0); |
319 | | |
320 | | /* To forestall valgrind complaints, copy only the valid data */ |
321 | 0 | switch (nodeTag(tmp)) |
322 | 0 | { |
323 | 0 | case T_Integer: |
324 | 0 | memcpy(&local_node->val, tmp, sizeof(Integer)); |
325 | 0 | break; |
326 | 0 | case T_Float: |
327 | 0 | memcpy(&local_node->val, tmp, sizeof(Float)); |
328 | 0 | break; |
329 | 0 | case T_Boolean: |
330 | 0 | memcpy(&local_node->val, tmp, sizeof(Boolean)); |
331 | 0 | break; |
332 | 0 | case T_String: |
333 | 0 | memcpy(&local_node->val, tmp, sizeof(String)); |
334 | 0 | break; |
335 | 0 | case T_BitString: |
336 | 0 | memcpy(&local_node->val, tmp, sizeof(BitString)); |
337 | 0 | break; |
338 | 0 | default: |
339 | 0 | elog(ERROR, "unrecognized node type: %d", |
340 | 0 | (int) nodeTag(tmp)); |
341 | 0 | break; |
342 | 0 | } |
343 | 0 | } |
344 | | |
345 | 0 | READ_LOCATION_FIELD(location); |
346 | |
|
347 | 0 | READ_DONE(); |
348 | 0 | } |
349 | | |
350 | | static RangeTblEntry * |
351 | | _readRangeTblEntry(ReadNodeContext *ctx) |
352 | 0 | { |
353 | 0 | READ_LOCALS(RangeTblEntry); |
354 | |
|
355 | 0 | READ_NODE_FIELD(alias); |
356 | 0 | READ_NODE_FIELD(eref); |
357 | 0 | READ_ENUM_FIELD(rtekind, RTEKind); |
358 | |
|
359 | 0 | switch (local_node->rtekind) |
360 | 0 | { |
361 | 0 | case RTE_RELATION: |
362 | 0 | READ_OID_FIELD(relid); |
363 | 0 | READ_BOOL_FIELD(inh); |
364 | 0 | READ_CHAR_FIELD(relkind); |
365 | 0 | READ_INT_FIELD(rellockmode); |
366 | 0 | READ_UINT_FIELD(perminfoindex); |
367 | 0 | READ_NODE_FIELD(tablesample); |
368 | 0 | break; |
369 | 0 | case RTE_SUBQUERY: |
370 | 0 | READ_NODE_FIELD(subquery); |
371 | 0 | READ_BOOL_FIELD(security_barrier); |
372 | | /* we re-use these RELATION fields, too: */ |
373 | 0 | READ_OID_FIELD(relid); |
374 | 0 | READ_BOOL_FIELD(inh); |
375 | 0 | READ_CHAR_FIELD(relkind); |
376 | 0 | READ_INT_FIELD(rellockmode); |
377 | 0 | READ_UINT_FIELD(perminfoindex); |
378 | 0 | break; |
379 | 0 | case RTE_JOIN: |
380 | 0 | READ_ENUM_FIELD(jointype, JoinType); |
381 | 0 | READ_INT_FIELD(joinmergedcols); |
382 | 0 | READ_NODE_FIELD(joinaliasvars); |
383 | 0 | READ_NODE_FIELD(joinleftcols); |
384 | 0 | READ_NODE_FIELD(joinrightcols); |
385 | 0 | READ_NODE_FIELD(join_using_alias); |
386 | 0 | break; |
387 | 0 | case RTE_FUNCTION: |
388 | 0 | READ_NODE_FIELD(functions); |
389 | 0 | READ_BOOL_FIELD(funcordinality); |
390 | 0 | break; |
391 | 0 | case RTE_TABLEFUNC: |
392 | 0 | READ_NODE_FIELD(tablefunc); |
393 | | /* The RTE must have a copy of the column type info, if any */ |
394 | 0 | if (local_node->tablefunc) |
395 | 0 | { |
396 | 0 | TableFunc *tf = local_node->tablefunc; |
397 | |
|
398 | 0 | local_node->coltypes = tf->coltypes; |
399 | 0 | local_node->coltypmods = tf->coltypmods; |
400 | 0 | local_node->colcollations = tf->colcollations; |
401 | 0 | } |
402 | 0 | break; |
403 | 0 | case RTE_VALUES: |
404 | 0 | READ_NODE_FIELD(values_lists); |
405 | 0 | READ_NODE_FIELD(coltypes); |
406 | 0 | READ_NODE_FIELD(coltypmods); |
407 | 0 | READ_NODE_FIELD(colcollations); |
408 | 0 | break; |
409 | 0 | case RTE_CTE: |
410 | 0 | READ_STRING_FIELD(ctename); |
411 | 0 | READ_UINT_FIELD(ctelevelsup); |
412 | 0 | READ_BOOL_FIELD(self_reference); |
413 | 0 | READ_NODE_FIELD(coltypes); |
414 | 0 | READ_NODE_FIELD(coltypmods); |
415 | 0 | READ_NODE_FIELD(colcollations); |
416 | 0 | break; |
417 | 0 | case RTE_NAMEDTUPLESTORE: |
418 | 0 | READ_STRING_FIELD(enrname); |
419 | 0 | READ_FLOAT_FIELD(enrtuples); |
420 | 0 | READ_NODE_FIELD(coltypes); |
421 | 0 | READ_NODE_FIELD(coltypmods); |
422 | 0 | READ_NODE_FIELD(colcollations); |
423 | | /* we re-use these RELATION fields, too: */ |
424 | 0 | READ_OID_FIELD(relid); |
425 | 0 | break; |
426 | 0 | case RTE_RESULT: |
427 | | /* no extra fields */ |
428 | 0 | break; |
429 | 0 | case RTE_GROUP: |
430 | 0 | READ_NODE_FIELD(groupexprs); |
431 | 0 | break; |
432 | 0 | default: |
433 | 0 | elog(ERROR, "unrecognized RTE kind: %d", |
434 | 0 | (int) local_node->rtekind); |
435 | 0 | break; |
436 | 0 | } |
437 | | |
438 | 0 | READ_BOOL_FIELD(lateral); |
439 | 0 | READ_BOOL_FIELD(inFromCl); |
440 | 0 | READ_NODE_FIELD(securityQuals); |
441 | |
|
442 | 0 | READ_DONE(); |
443 | 0 | } |
444 | | |
445 | | static A_Expr * |
446 | | _readA_Expr(ReadNodeContext *ctx) |
447 | 0 | { |
448 | 0 | READ_LOCALS(A_Expr); |
449 | |
|
450 | 0 | token = pg_strtok(ctx, &length); |
451 | |
|
452 | 0 | if (length == 3 && strncmp(token, "ANY", 3) == 0) |
453 | 0 | { |
454 | 0 | local_node->kind = AEXPR_OP_ANY; |
455 | 0 | READ_NODE_FIELD(name); |
456 | 0 | } |
457 | 0 | else if (length == 3 && strncmp(token, "ALL", 3) == 0) |
458 | 0 | { |
459 | 0 | local_node->kind = AEXPR_OP_ALL; |
460 | 0 | READ_NODE_FIELD(name); |
461 | 0 | } |
462 | 0 | else if (length == 8 && strncmp(token, "DISTINCT", 8) == 0) |
463 | 0 | { |
464 | 0 | local_node->kind = AEXPR_DISTINCT; |
465 | 0 | READ_NODE_FIELD(name); |
466 | 0 | } |
467 | 0 | else if (length == 12 && strncmp(token, "NOT_DISTINCT", 12) == 0) |
468 | 0 | { |
469 | 0 | local_node->kind = AEXPR_NOT_DISTINCT; |
470 | 0 | READ_NODE_FIELD(name); |
471 | 0 | } |
472 | 0 | else if (length == 6 && strncmp(token, "NULLIF", 6) == 0) |
473 | 0 | { |
474 | 0 | local_node->kind = AEXPR_NULLIF; |
475 | 0 | READ_NODE_FIELD(name); |
476 | 0 | } |
477 | 0 | else if (length == 2 && strncmp(token, "IN", 2) == 0) |
478 | 0 | { |
479 | 0 | local_node->kind = AEXPR_IN; |
480 | 0 | READ_NODE_FIELD(name); |
481 | 0 | } |
482 | 0 | else if (length == 4 && strncmp(token, "LIKE", 4) == 0) |
483 | 0 | { |
484 | 0 | local_node->kind = AEXPR_LIKE; |
485 | 0 | READ_NODE_FIELD(name); |
486 | 0 | } |
487 | 0 | else if (length == 5 && strncmp(token, "ILIKE", 5) == 0) |
488 | 0 | { |
489 | 0 | local_node->kind = AEXPR_ILIKE; |
490 | 0 | READ_NODE_FIELD(name); |
491 | 0 | } |
492 | 0 | else if (length == 7 && strncmp(token, "SIMILAR", 7) == 0) |
493 | 0 | { |
494 | 0 | local_node->kind = AEXPR_SIMILAR; |
495 | 0 | READ_NODE_FIELD(name); |
496 | 0 | } |
497 | 0 | else if (length == 7 && strncmp(token, "BETWEEN", 7) == 0) |
498 | 0 | { |
499 | 0 | local_node->kind = AEXPR_BETWEEN; |
500 | 0 | READ_NODE_FIELD(name); |
501 | 0 | } |
502 | 0 | else if (length == 11 && strncmp(token, "NOT_BETWEEN", 11) == 0) |
503 | 0 | { |
504 | 0 | local_node->kind = AEXPR_NOT_BETWEEN; |
505 | 0 | READ_NODE_FIELD(name); |
506 | 0 | } |
507 | 0 | else if (length == 11 && strncmp(token, "BETWEEN_SYM", 11) == 0) |
508 | 0 | { |
509 | 0 | local_node->kind = AEXPR_BETWEEN_SYM; |
510 | 0 | READ_NODE_FIELD(name); |
511 | 0 | } |
512 | 0 | else if (length == 15 && strncmp(token, "NOT_BETWEEN_SYM", 15) == 0) |
513 | 0 | { |
514 | 0 | local_node->kind = AEXPR_NOT_BETWEEN_SYM; |
515 | 0 | READ_NODE_FIELD(name); |
516 | 0 | } |
517 | 0 | else if (length == 5 && strncmp(token, ":name", 5) == 0) |
518 | 0 | { |
519 | 0 | local_node->kind = AEXPR_OP; |
520 | 0 | local_node->name = nodeRead(ctx, NULL, 0); |
521 | 0 | } |
522 | 0 | else |
523 | 0 | elog(ERROR, "unrecognized A_Expr kind: \"%.*s\"", length, token); |
524 | | |
525 | 0 | READ_NODE_FIELD(lexpr); |
526 | 0 | READ_NODE_FIELD(rexpr); |
527 | 0 | READ_LOCATION_FIELD(rexpr_list_start); |
528 | 0 | READ_LOCATION_FIELD(rexpr_list_end); |
529 | 0 | READ_LOCATION_FIELD(location); |
530 | |
|
531 | 0 | READ_DONE(); |
532 | 0 | } |
533 | | |
534 | | static ExtensibleNode * |
535 | | _readExtensibleNode(ReadNodeContext *ctx) |
536 | 0 | { |
537 | 0 | const ExtensibleNodeMethods *methods; |
538 | 0 | ExtensibleNode *local_node; |
539 | 0 | const char *extnodename; |
540 | |
|
541 | 0 | READ_TEMP_LOCALS(); |
542 | |
|
543 | 0 | token = pg_strtok(ctx, &length); /* skip :extnodename */ |
544 | 0 | token = pg_strtok(ctx, &length); /* get extnodename */ |
545 | |
|
546 | 0 | extnodename = nullable_string(token, length); |
547 | 0 | if (!extnodename) |
548 | 0 | elog(ERROR, "extnodename has to be supplied"); |
549 | 0 | methods = GetExtensibleNodeMethods(extnodename, false); |
550 | |
|
551 | 0 | local_node = (ExtensibleNode *) newNode(methods->node_size, |
552 | 0 | T_ExtensibleNode); |
553 | 0 | local_node->extnodename = extnodename; |
554 | | |
555 | | /* deserialize the private fields */ |
556 | 0 | methods->nodeRead(ctx, local_node); |
557 | |
|
558 | 0 | READ_DONE(); |
559 | 0 | } |
560 | | |
561 | | |
562 | | /* |
563 | | * parseNodeString |
564 | | * |
565 | | * Given a character string representing a node tree, parseNodeString creates |
566 | | * the internal node structure. |
567 | | */ |
568 | | Node * |
569 | | parseNodeString(ReadNodeContext *ctx) |
570 | 0 | { |
571 | 0 | READ_TEMP_LOCALS(); |
572 | | |
573 | | /* Guard against stack overflow due to overly complex expressions */ |
574 | 0 | check_stack_depth(); |
575 | |
|
576 | 0 | token = pg_strtok(ctx, &length); |
577 | |
|
578 | 0 | #define MATCH(tokname, namelen) \ |
579 | 0 | (length == namelen && memcmp(token, tokname, namelen) == 0) |
580 | |
|
581 | 0 | #include "readfuncs.switch.c" |
582 | | |
583 | 0 | elog(ERROR, "badly formatted node string \"%.32s\"...", token); |
584 | 0 | return NULL; /* keep compiler quiet */ |
585 | 0 | } |
586 | | |
587 | | |
588 | | /* |
589 | | * readDatum |
590 | | * |
591 | | * Given a string representation of a constant, recreate the appropriate |
592 | | * Datum. The string representation embeds length info, but not byValue, |
593 | | * so we must be told that. |
594 | | */ |
595 | | Datum |
596 | | readDatum(ReadNodeContext *ctx, bool typbyval) |
597 | 0 | { |
598 | 0 | Size length; |
599 | 0 | int tokenLength; |
600 | 0 | const char *token; |
601 | 0 | Datum res; |
602 | 0 | char *s; |
603 | | |
604 | | /* |
605 | | * read the actual length of the value |
606 | | */ |
607 | 0 | token = pg_strtok(ctx, &tokenLength); |
608 | 0 | length = atoui(token); |
609 | |
|
610 | 0 | token = pg_strtok(ctx, &tokenLength); /* read the '[' */ |
611 | 0 | if (token == NULL || token[0] != '[') |
612 | 0 | elog(ERROR, "expected \"[\" to start datum, but got \"%s\"; length = %zu", |
613 | 0 | token ? token : "[NULL]", length); |
614 | | |
615 | 0 | if (typbyval) |
616 | 0 | { |
617 | 0 | if (length > (Size) sizeof(Datum)) |
618 | 0 | elog(ERROR, "byval datum but length = %zu", length); |
619 | 0 | res = (Datum) 0; |
620 | 0 | s = (char *) (&res); |
621 | 0 | for (Size i = 0; i < (Size) sizeof(Datum); i++) |
622 | 0 | { |
623 | 0 | token = pg_strtok(ctx, &tokenLength); |
624 | 0 | s[i] = (char) atoi(token); |
625 | 0 | } |
626 | 0 | } |
627 | 0 | else if (length <= 0) |
628 | 0 | res = (Datum) 0; |
629 | 0 | else |
630 | 0 | { |
631 | 0 | s = (char *) palloc(length); |
632 | 0 | for (Size i = 0; i < length; i++) |
633 | 0 | { |
634 | 0 | token = pg_strtok(ctx, &tokenLength); |
635 | 0 | s[i] = (char) atoi(token); |
636 | 0 | } |
637 | 0 | res = PointerGetDatum(s); |
638 | 0 | } |
639 | | |
640 | 0 | token = pg_strtok(ctx, &tokenLength); /* read the ']' */ |
641 | 0 | if (token == NULL || token[0] != ']') |
642 | 0 | elog(ERROR, "expected \"]\" to end datum, but got \"%s\"; length = %zu", |
643 | 0 | token ? token : "[NULL]", length); |
644 | | |
645 | 0 | return res; |
646 | 0 | } |
647 | | |
648 | | /* |
649 | | * common implementation for scalar-array-reading functions |
650 | | * |
651 | | * The data format is either "<>" for a NULL pointer (in which case numCols |
652 | | * is ignored) or "(item item item)" where the number of items must equal |
653 | | * numCols. The convfunc must be okay with stopping at whitespace or a |
654 | | * right parenthesis, since pg_strtok won't null-terminate the token. |
655 | | */ |
656 | | #define READ_SCALAR_ARRAY(fnname, datatype, convfunc) \ |
657 | | datatype * \ |
658 | 0 | fnname(ReadNodeContext *ctx, int numCols) \ |
659 | 0 | { \ |
660 | 0 | datatype *vals; \ |
661 | 0 | READ_TEMP_LOCALS(); \ |
662 | 0 | token = pg_strtok(ctx, &length); \ |
663 | 0 | if (token == NULL) \ |
664 | 0 | elog(ERROR, "incomplete scalar array"); \ |
665 | 0 | if (length == 0) \ |
666 | 0 | return NULL; /* it was "<>", so return NULL pointer */ \ |
667 | 0 | if (length != 1 || token[0] != '(') \ |
668 | 0 | elog(ERROR, "unrecognized token: \"%.*s\"", length, token); \ |
669 | 0 | vals = palloc_array(datatype, numCols); \ |
670 | 0 | for (int i = 0; i < numCols; i++) \ |
671 | 0 | { \ |
672 | 0 | token = pg_strtok(ctx, &length); \ |
673 | 0 | if (token == NULL || token[0] == ')') \ |
674 | 0 | elog(ERROR, "incomplete scalar array"); \ |
675 | 0 | vals[i] = convfunc(token); \ |
676 | 0 | } \ |
677 | 0 | token = pg_strtok(ctx, &length); \ |
678 | 0 | if (token == NULL || length != 1 || token[0] != ')') \ |
679 | 0 | elog(ERROR, "incomplete scalar array"); \ |
680 | 0 | return vals; \ |
681 | 0 | } |
682 | | |
683 | | /* |
684 | | * Note: these functions are exported in nodes.h for possible use by |
685 | | * extensions, so don't mess too much with their names or API. |
686 | | */ |
687 | 0 | READ_SCALAR_ARRAY(readAttrNumberCols, int16, atoi) |
688 | 0 | READ_SCALAR_ARRAY(readOidCols, Oid, atooid) |
689 | | /* outfuncs.c has writeIndexCols, but we don't yet need that here */ |
690 | | /* READ_SCALAR_ARRAY(readIndexCols, Index, atoui) */ |
691 | 0 | READ_SCALAR_ARRAY(readIntCols, int, atoi) |
692 | 0 | READ_SCALAR_ARRAY(readBoolCols, bool, strtobool) |