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