Age Owner Branch data TLA 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 : : * 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 WRITE_READ_PARSE_PLAN_TREES
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 *
566 peter@eisentraut.org 182 :CBC 290246 : nullable_string(const char *token, int length)
183 : : {
184 : : /* outToken emits <> for NULL, and pg_strtok makes that an empty string */
185 [ + + ]: 290246 : if (length == 0)
186 : 14509 : return NULL;
187 : : /* outToken emits "" for empty string */
188 [ + + - + : 275737 : if (length == 2 && token[0] == '"' && token[1] == '"')
- - ]
566 peter@eisentraut.org 189 :UBC 0 : return pstrdup("");
190 : : /* otherwise, we must remove protective backslashes added by outToken */
566 peter@eisentraut.org 191 :CBC 275737 : 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 *
5561 tgl@sss.pgh.pa.us 203 : 956927 : _readBitmapset(void)
204 : : {
5421 bruce@momjian.us 205 : 956927 : Bitmapset *result = NULL;
206 : :
207 : : READ_TEMP_LOCALS();
208 : :
5561 tgl@sss.pgh.pa.us 209 : 956927 : token = pg_strtok(&length);
210 [ - + ]: 956927 : if (token == NULL)
5561 tgl@sss.pgh.pa.us 211 [ # # ]:UBC 0 : elog(ERROR, "incomplete Bitmapset structure");
5561 tgl@sss.pgh.pa.us 212 [ + - - + ]:CBC 956927 : if (length != 1 || token[0] != '(')
5561 tgl@sss.pgh.pa.us 213 [ # # ]:UBC 0 : elog(ERROR, "unrecognized token: \"%.*s\"", length, token);
214 : :
5561 tgl@sss.pgh.pa.us 215 :CBC 956927 : token = pg_strtok(&length);
216 [ - + ]: 956927 : if (token == NULL)
5561 tgl@sss.pgh.pa.us 217 [ # # ]:UBC 0 : elog(ERROR, "incomplete Bitmapset structure");
5561 tgl@sss.pgh.pa.us 218 [ + - + - ]:CBC 956927 : if (length != 1 || token[0] != 'b')
5561 tgl@sss.pgh.pa.us 219 [ # # ]:UBC 0 : elog(ERROR, "unrecognized token: \"%.*s\"", length, token);
220 : :
221 : : for (;;)
5561 tgl@sss.pgh.pa.us 222 :CBC 251512 : {
223 : : int val;
224 : : char *endptr;
225 : :
226 : 1208439 : token = pg_strtok(&length);
227 [ - + ]: 1208439 : if (token == NULL)
5561 tgl@sss.pgh.pa.us 228 [ # # ]:UBC 0 : elog(ERROR, "unterminated Bitmapset structure");
5561 tgl@sss.pgh.pa.us 229 [ + + + + ]:CBC 1208439 : if (length == 1 && token[0] == ')')
230 : 956927 : break;
231 : 251512 : val = (int) strtol(token, &endptr, 10);
232 [ - + ]: 251512 : if (endptr != token + length)
5561 tgl@sss.pgh.pa.us 233 [ # # ]:UBC 0 : elog(ERROR, "unrecognized integer: \"%.*s\"", length, token);
5561 tgl@sss.pgh.pa.us 234 :CBC 251512 : result = bms_add_member(result, val);
235 : : }
236 : :
237 : 956927 : 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 *
2984 rhaas@postgresql.org 245 :UBC 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 *
645 peter@eisentraut.org 259 :CBC 237450 : _readConst(void)
260 : : {
261 : 237450 : READ_LOCALS(Const);
262 : :
263 : 237450 : READ_OID_FIELD(consttype);
264 : 237450 : READ_INT_FIELD(consttypmod);
265 : 237450 : READ_OID_FIELD(constcollid);
266 : 237450 : READ_INT_FIELD(constlen);
267 : 237450 : READ_BOOL_FIELD(constbyval);
268 : 237450 : READ_BOOL_FIELD(constisnull);
3256 andres@anarazel.de 269 : 237450 : READ_LOCATION_FIELD(location);
270 : :
645 peter@eisentraut.org 271 : 237450 : token = pg_strtok(&length); /* skip :constvalue */
272 [ + + ]: 237450 : if (local_node->constisnull)
273 : 31911 : token = pg_strtok(&length); /* skip "<>" */
274 : : else
275 : 205539 : local_node->constvalue = readDatum(local_node->constbyval);
276 : :
1168 277 : 237450 : READ_DONE();
278 : : }
279 : :
280 : : static BoolExpr *
645 281 : 16898 : _readBoolExpr(void)
282 : : {
283 : 16898 : READ_LOCALS(BoolExpr);
284 : :
285 : : /* do-it-yourself enum representation */
286 : 16898 : token = pg_strtok(&length); /* skip :boolop */
287 : 16898 : token = pg_strtok(&length); /* get field value */
568 288 [ + + + + ]: 16898 : if (length == 3 && strncmp(token, "and", 3) == 0)
645 289 : 11400 : local_node->boolop = AND_EXPR;
568 290 [ + + + - ]: 5498 : else if (length == 2 && strncmp(token, "or", 2) == 0)
645 291 : 3926 : local_node->boolop = OR_EXPR;
568 292 [ + - + - ]: 1572 : else if (length == 3 && strncmp(token, "not", 3) == 0)
645 293 : 1572 : local_node->boolop = NOT_EXPR;
294 : : else
645 peter@eisentraut.org 295 [ # # ]:UBC 0 : elog(ERROR, "unrecognized boolop \"%.*s\"", length, token);
296 : :
645 peter@eisentraut.org 297 :CBC 16898 : READ_NODE_FIELD(args);
5671 tgl@sss.pgh.pa.us 298 : 16898 : READ_LOCATION_FIELD(location);
299 : :
7811 300 : 16898 : READ_DONE();
301 : : }
302 : :
303 : : static A_Const *
568 peter@eisentraut.org 304 :UBC 0 : _readA_Const(void)
305 : : {
306 : 0 : READ_LOCALS(A_Const);
307 : :
308 : : /* We expect either NULL or :val here */
309 : 0 : token = pg_strtok(&length);
310 [ # # # # ]: 0 : if (length == 4 && strncmp(token, "NULL", 4) == 0)
311 : 0 : local_node->isnull = true;
312 : : else
313 : : {
314 : 0 : union ValUnion *tmp = nodeRead(NULL, 0);
315 : :
316 : : /* To forestall valgrind complaints, copy only the valid data */
392 tgl@sss.pgh.pa.us 317 [ # # # # : 0 : switch (nodeTag(tmp))
# # ]
318 : : {
319 : 0 : case T_Integer:
320 : 0 : memcpy(&local_node->val, tmp, sizeof(Integer));
321 : 0 : break;
322 : 0 : case T_Float:
323 : 0 : memcpy(&local_node->val, tmp, sizeof(Float));
324 : 0 : break;
325 : 0 : case T_Boolean:
326 : 0 : memcpy(&local_node->val, tmp, sizeof(Boolean));
327 : 0 : break;
328 : 0 : case T_String:
329 : 0 : memcpy(&local_node->val, tmp, sizeof(String));
330 : 0 : break;
331 : 0 : case T_BitString:
332 : 0 : memcpy(&local_node->val, tmp, sizeof(BitString));
333 : 0 : break;
334 : 0 : default:
335 [ # # ]: 0 : elog(ERROR, "unrecognized node type: %d",
336 : : (int) nodeTag(tmp));
337 : : break;
338 : : }
339 : : }
340 : :
568 peter@eisentraut.org 341 : 0 : READ_LOCATION_FIELD(location);
342 : :
343 : 0 : READ_DONE();
344 : : }
345 : :
346 : : static RangeTblEntry *
645 peter@eisentraut.org 347 :CBC 68361 : _readRangeTblEntry(void)
348 : : {
349 : 68361 : READ_LOCALS(RangeTblEntry);
350 : :
351 : 68361 : READ_NODE_FIELD(alias);
352 : 68361 : READ_NODE_FIELD(eref);
353 : 68361 : READ_ENUM_FIELD(rtekind, RTEKind);
354 : :
355 [ + + + + : 68361 : switch (local_node->rtekind)
+ + + - +
- ]
356 : : {
357 : 42650 : case RTE_RELATION:
358 : 42650 : READ_OID_FIELD(relid);
38 peter@eisentraut.org 359 :GNC 42650 : READ_BOOL_FIELD(inh);
645 peter@eisentraut.org 360 [ + - - + ]:CBC 42650 : READ_CHAR_FIELD(relkind);
361 : 42650 : READ_INT_FIELD(rellockmode);
495 alvherre@alvh.no-ip. 362 : 42650 : READ_UINT_FIELD(perminfoindex);
40 peter@eisentraut.org 363 :GNC 42650 : READ_NODE_FIELD(tablesample);
645 peter@eisentraut.org 364 :CBC 42650 : break;
365 : 7070 : case RTE_SUBQUERY:
366 : 7070 : READ_NODE_FIELD(subquery);
367 : 7070 : READ_BOOL_FIELD(security_barrier);
368 : : /* we re-use these RELATION fields, too: */
452 tgl@sss.pgh.pa.us 369 : 7070 : READ_OID_FIELD(relid);
38 peter@eisentraut.org 370 :GNC 7070 : READ_BOOL_FIELD(inh);
306 amitlan@postgresql.o 371 [ + + - + ]:CBC 7070 : READ_CHAR_FIELD(relkind);
452 tgl@sss.pgh.pa.us 372 : 7070 : READ_INT_FIELD(rellockmode);
373 : 7070 : READ_UINT_FIELD(perminfoindex);
645 peter@eisentraut.org 374 : 7070 : break;
375 : 12137 : case RTE_JOIN:
376 : 12137 : READ_ENUM_FIELD(jointype, JoinType);
377 : 12137 : READ_INT_FIELD(joinmergedcols);
378 : 12137 : READ_NODE_FIELD(joinaliasvars);
379 : 12137 : READ_NODE_FIELD(joinleftcols);
380 : 12137 : READ_NODE_FIELD(joinrightcols);
381 : 12137 : READ_NODE_FIELD(join_using_alias);
382 : 12137 : break;
383 : 5446 : case RTE_FUNCTION:
384 : 5446 : READ_NODE_FIELD(functions);
385 : 5446 : READ_BOOL_FIELD(funcordinality);
386 : 5446 : break;
387 : 100 : case RTE_TABLEFUNC:
388 : 100 : READ_NODE_FIELD(tablefunc);
389 : : /* The RTE must have a copy of the column type info, if any */
390 [ + - ]: 100 : if (local_node->tablefunc)
391 : : {
392 : 100 : TableFunc *tf = local_node->tablefunc;
393 : :
394 : 100 : local_node->coltypes = tf->coltypes;
395 : 100 : local_node->coltypmods = tf->coltypmods;
396 : 100 : local_node->colcollations = tf->colcollations;
397 : : }
398 : 100 : break;
399 : 657 : case RTE_VALUES:
400 : 657 : READ_NODE_FIELD(values_lists);
401 : 657 : READ_NODE_FIELD(coltypes);
402 : 657 : READ_NODE_FIELD(coltypmods);
403 : 657 : READ_NODE_FIELD(colcollations);
404 : 657 : break;
405 : 265 : case RTE_CTE:
406 : 265 : READ_STRING_FIELD(ctename);
407 : 265 : READ_UINT_FIELD(ctelevelsup);
408 : 265 : READ_BOOL_FIELD(self_reference);
409 : 265 : READ_NODE_FIELD(coltypes);
410 : 265 : READ_NODE_FIELD(coltypmods);
411 : 265 : READ_NODE_FIELD(colcollations);
412 : 265 : break;
645 peter@eisentraut.org 413 :UBC 0 : case RTE_NAMEDTUPLESTORE:
414 : 0 : READ_STRING_FIELD(enrname);
415 : 0 : READ_FLOAT_FIELD(enrtuples);
416 : 0 : READ_NODE_FIELD(coltypes);
417 : 0 : READ_NODE_FIELD(coltypmods);
418 : 0 : READ_NODE_FIELD(colcollations);
419 : : /* we re-use these RELATION fields, too: */
452 tgl@sss.pgh.pa.us 420 : 0 : READ_OID_FIELD(relid);
645 peter@eisentraut.org 421 : 0 : break;
645 peter@eisentraut.org 422 :CBC 36 : case RTE_RESULT:
423 : : /* no extra fields */
424 : 36 : break;
645 peter@eisentraut.org 425 :UBC 0 : default:
426 [ # # ]: 0 : elog(ERROR, "unrecognized RTE kind: %d",
427 : : (int) local_node->rtekind);
428 : : break;
429 : : }
430 : :
645 peter@eisentraut.org 431 :CBC 68361 : READ_BOOL_FIELD(lateral);
432 : 68361 : READ_BOOL_FIELD(inFromCl);
433 : 68361 : READ_NODE_FIELD(securityQuals);
434 : :
7811 tgl@sss.pgh.pa.us 435 : 68361 : READ_DONE();
436 : : }
437 : :
438 : : static A_Expr *
568 peter@eisentraut.org 439 :UBC 0 : _readA_Expr(void)
440 : : {
441 : 0 : READ_LOCALS(A_Expr);
442 : :
443 : 0 : token = pg_strtok(&length);
444 : :
445 [ # # # # ]: 0 : if (length == 3 && strncmp(token, "ANY", 3) == 0)
446 : : {
447 : 0 : local_node->kind = AEXPR_OP_ANY;
448 : 0 : READ_NODE_FIELD(name);
449 : : }
450 [ # # # # ]: 0 : else if (length == 3 && strncmp(token, "ALL", 3) == 0)
451 : : {
452 : 0 : local_node->kind = AEXPR_OP_ALL;
453 : 0 : READ_NODE_FIELD(name);
454 : : }
455 [ # # # # ]: 0 : else if (length == 8 && strncmp(token, "DISTINCT", 8) == 0)
456 : : {
457 : 0 : local_node->kind = AEXPR_DISTINCT;
458 : 0 : READ_NODE_FIELD(name);
459 : : }
460 [ # # # # ]: 0 : else if (length == 12 && strncmp(token, "NOT_DISTINCT", 12) == 0)
461 : : {
462 : 0 : local_node->kind = AEXPR_NOT_DISTINCT;
463 : 0 : READ_NODE_FIELD(name);
464 : : }
465 [ # # # # ]: 0 : else if (length == 6 && strncmp(token, "NULLIF", 6) == 0)
466 : : {
467 : 0 : local_node->kind = AEXPR_NULLIF;
468 : 0 : READ_NODE_FIELD(name);
469 : : }
470 [ # # # # ]: 0 : else if (length == 2 && strncmp(token, "IN", 2) == 0)
471 : : {
472 : 0 : local_node->kind = AEXPR_IN;
473 : 0 : READ_NODE_FIELD(name);
474 : : }
475 [ # # # # ]: 0 : else if (length == 4 && strncmp(token, "LIKE", 4) == 0)
476 : : {
477 : 0 : local_node->kind = AEXPR_LIKE;
478 : 0 : READ_NODE_FIELD(name);
479 : : }
480 [ # # # # ]: 0 : else if (length == 5 && strncmp(token, "ILIKE", 5) == 0)
481 : : {
482 : 0 : local_node->kind = AEXPR_ILIKE;
483 : 0 : READ_NODE_FIELD(name);
484 : : }
485 [ # # # # ]: 0 : else if (length == 7 && strncmp(token, "SIMILAR", 7) == 0)
486 : : {
487 : 0 : local_node->kind = AEXPR_SIMILAR;
488 : 0 : READ_NODE_FIELD(name);
489 : : }
490 [ # # # # ]: 0 : else if (length == 7 && strncmp(token, "BETWEEN", 7) == 0)
491 : : {
492 : 0 : local_node->kind = AEXPR_BETWEEN;
493 : 0 : READ_NODE_FIELD(name);
494 : : }
495 [ # # # # ]: 0 : else if (length == 11 && strncmp(token, "NOT_BETWEEN", 11) == 0)
496 : : {
497 : 0 : local_node->kind = AEXPR_NOT_BETWEEN;
498 : 0 : READ_NODE_FIELD(name);
499 : : }
500 [ # # # # ]: 0 : else if (length == 11 && strncmp(token, "BETWEEN_SYM", 11) == 0)
501 : : {
502 : 0 : local_node->kind = AEXPR_BETWEEN_SYM;
503 : 0 : READ_NODE_FIELD(name);
504 : : }
505 [ # # # # ]: 0 : else if (length == 15 && strncmp(token, "NOT_BETWEEN_SYM", 15) == 0)
506 : : {
507 : 0 : local_node->kind = AEXPR_NOT_BETWEEN_SYM;
508 : 0 : READ_NODE_FIELD(name);
509 : : }
510 [ # # # # ]: 0 : else if (length == 5 && strncmp(token, ":name", 5) == 0)
511 : : {
512 : 0 : local_node->kind = AEXPR_OP;
513 : 0 : local_node->name = nodeRead(NULL, 0);
514 : : }
515 : : else
516 [ # # ]: 0 : elog(ERROR, "unrecognized A_Expr kind: \"%.*s\"", length, token);
517 : :
518 : 0 : READ_NODE_FIELD(lexpr);
519 : 0 : READ_NODE_FIELD(rexpr);
520 : 0 : READ_LOCATION_FIELD(location);
521 : :
522 : 0 : READ_DONE();
523 : : }
524 : :
525 : : static ExtensibleNode *
645 526 : 0 : _readExtensibleNode(void)
527 : : {
528 : : const ExtensibleNodeMethods *methods;
529 : : ExtensibleNode *local_node;
530 : : const char *extnodename;
531 : :
532 : : READ_TEMP_LOCALS();
533 : :
534 : 0 : token = pg_strtok(&length); /* skip :extnodename */
535 : 0 : token = pg_strtok(&length); /* get extnodename */
536 : :
537 : 0 : extnodename = nullable_string(token, length);
538 [ # # ]: 0 : if (!extnodename)
539 [ # # ]: 0 : elog(ERROR, "extnodename has to be supplied");
540 : 0 : methods = GetExtensibleNodeMethods(extnodename, false);
541 : :
542 [ # # # # : 0 : local_node = (ExtensibleNode *) newNode(methods->node_size,
# # ]
543 : : T_ExtensibleNode);
544 : 0 : local_node->extnodename = extnodename;
545 : :
546 : : /* deserialize the private fields */
547 : 0 : methods->nodeRead(local_node);
548 : :
7811 tgl@sss.pgh.pa.us 549 : 0 : READ_DONE();
550 : : }
551 : :
552 : :
553 : : /*
554 : : * parseNodeString
555 : : *
556 : : * Given a character string representing a node tree, parseNodeString creates
557 : : * the internal node structure.
558 : : *
559 : : * The string to be read must already have been loaded into pg_strtok().
560 : : */
561 : : Node *
7811 tgl@sss.pgh.pa.us 562 :CBC 1990287 : parseNodeString(void)
563 : : {
564 : : READ_TEMP_LOCALS();
565 : :
566 : : /* Guard against stack overflow due to overly complex expressions */
1952 567 : 1990287 : check_stack_depth();
568 : :
8498 569 : 1990287 : token = pg_strtok(&length);
570 : :
571 : : #define MATCH(tokname, namelen) \
572 : : (length == namelen && memcmp(token, tokname, namelen) == 0)
573 : :
574 : : #include "readfuncs.switch.c"
575 : :
305 noah@leadboat.com 576 [ # # ]:UBC 0 : elog(ERROR, "badly formatted node string \"%.32s\"...", token);
577 : : return NULL; /* keep compiler quiet */
578 : : }
579 : :
580 : :
581 : : /*
582 : : * readDatum
583 : : *
584 : : * Given a string representation of a constant, recreate the appropriate
585 : : * Datum. The string representation embeds length info, but not byValue,
586 : : * so we must be told that.
587 : : */
588 : : Datum
8498 tgl@sss.pgh.pa.us 589 :CBC 205539 : readDatum(bool typbyval)
590 : : {
591 : : Size length,
592 : : i;
593 : : int tokenLength;
594 : : const char *token;
595 : : Datum res;
596 : : char *s;
597 : :
598 : : /*
599 : : * read the actual length of the value
600 : : */
601 : 205539 : token = pg_strtok(&tokenLength);
8497 602 : 205539 : length = atoui(token);
603 : :
8321 604 : 205539 : token = pg_strtok(&tokenLength); /* read the '[' */
605 [ + - - + ]: 205539 : if (token == NULL || token[0] != '[')
3734 tgl@sss.pgh.pa.us 606 [ # # # # ]:UBC 0 : elog(ERROR, "expected \"[\" to start datum, but got \"%s\"; length = %zu",
607 : : token ? token : "[NULL]", length);
608 : :
8498 tgl@sss.pgh.pa.us 609 [ + + ]:CBC 205539 : if (typbyval)
610 : : {
8497 611 [ - + ]: 152394 : if (length > (Size) sizeof(Datum))
3734 tgl@sss.pgh.pa.us 612 [ # # ]:UBC 0 : elog(ERROR, "byval datum but length = %zu", length);
8857 tgl@sss.pgh.pa.us 613 :CBC 152394 : res = (Datum) 0;
9716 bruce@momjian.us 614 : 152394 : s = (char *) (&res);
8497 tgl@sss.pgh.pa.us 615 [ + + ]: 1371546 : for (i = 0; i < (Size) sizeof(Datum); i++)
616 : : {
8498 617 : 1219152 : token = pg_strtok(&tokenLength);
9716 bruce@momjian.us 618 : 1219152 : s[i] = (char) atoi(token);
619 : : }
620 : : }
621 [ - + ]: 53145 : else if (length <= 0)
8857 tgl@sss.pgh.pa.us 622 :UBC 0 : res = (Datum) NULL;
623 : : else
624 : : {
9716 bruce@momjian.us 625 :CBC 53145 : s = (char *) palloc(length);
626 [ + + ]: 925517 : for (i = 0; i < length; i++)
627 : : {
8498 tgl@sss.pgh.pa.us 628 : 872372 : token = pg_strtok(&tokenLength);
9716 bruce@momjian.us 629 : 872372 : s[i] = (char) atoi(token);
630 : : }
631 : 53145 : res = PointerGetDatum(s);
632 : : }
633 : :
8321 tgl@sss.pgh.pa.us 634 : 205539 : token = pg_strtok(&tokenLength); /* read the ']' */
8498 635 [ + - - + ]: 205539 : if (token == NULL || token[0] != ']')
3734 tgl@sss.pgh.pa.us 636 [ # # # # ]:UBC 0 : elog(ERROR, "expected \"]\" to end datum, but got \"%s\"; length = %zu",
637 : : token ? token : "[NULL]", length);
638 : :
9357 bruce@momjian.us 639 :CBC 205539 : return res;
640 : : }
641 : :
642 : : /*
643 : : * common implementation for scalar-array-reading functions
644 : : *
645 : : * The data format is either "<>" for a NULL pointer (in which case numCols
646 : : * is ignored) or "(item item item)" where the number of items must equal
647 : : * numCols. The convfunc must be okay with stopping at whitespace or a
648 : : * right parenthesis, since pg_strtok won't null-terminate the token.
649 : : */
650 : : #define READ_SCALAR_ARRAY(fnname, datatype, convfunc) \
651 : : datatype * \
652 : : fnname(int numCols) \
653 : : { \
654 : : datatype *vals; \
655 : : READ_TEMP_LOCALS(); \
656 : : token = pg_strtok(&length); \
657 : : if (token == NULL) \
658 : : elog(ERROR, "incomplete scalar array"); \
659 : : if (length == 0) \
660 : : return NULL; /* it was "<>", so return NULL pointer */ \
661 : : if (length != 1 || token[0] != '(') \
662 : : elog(ERROR, "unrecognized token: \"%.*s\"", length, token); \
663 : : vals = (datatype *) palloc(numCols * sizeof(datatype)); \
664 : : for (int i = 0; i < numCols; i++) \
665 : : { \
666 : : token = pg_strtok(&length); \
667 : : if (token == NULL || token[0] == ')') \
668 : : elog(ERROR, "incomplete scalar array"); \
669 : : vals[i] = convfunc(token); \
670 : : } \
671 : : token = pg_strtok(&length); \
672 : : if (token == NULL || length != 1 || token[0] != ')') \
673 : : elog(ERROR, "incomplete scalar array"); \
674 : : return vals; \
675 : : }
676 : :
677 : : /*
678 : : * Note: these functions are exported in nodes.h for possible use by
679 : : * extensions, so don't mess too much with their names or API.
680 : : */
634 tgl@sss.pgh.pa.us 681 [ - + - - : 1660 : READ_SCALAR_ARRAY(readAttrNumberCols, int16, atoi)
+ + + - -
+ - - + -
- + - - +
+ + - + -
- + - - ]
682 [ - + - - : 4166 : READ_SCALAR_ARRAY(readOidCols, Oid, atooid)
+ + + - -
+ - - + -
- + - - +
+ + - + -
- + - - ]
683 : : /* outfuncs.c has writeIndexCols, but we don't yet need that here */
684 : : /* READ_SCALAR_ARRAY(readIndexCols, Index, atoui) */
685 [ - + - - : 1572 : READ_SCALAR_ARRAY(readIntCols, int, atoi)
- + + - -
+ - - + -
- + - - +
+ + - + -
- + - - ]
686 [ - + - - : 506 : READ_SCALAR_ARRAY(readBoolCols, bool, strtobool)
- + + - -
+ - - + -
- + - - +
+ + - + -
- + - - ]
|