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