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-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 *
1076 peter@eisentraut.org 188 :CBC 437794 : nullable_string(const char *token, int length)
189 : : {
190 : : /* outToken emits <> for NULL, and pg_strtok makes that an empty string */
191 [ + + ]: 437794 : if (length == 0)
192 : 91117 : return NULL;
193 : : /* outToken emits "" for empty string */
194 [ + + - + : 346677 : if (length == 2 && token[0] == '"' && token[1] == '"')
- - ]
1076 peter@eisentraut.org 195 :UBC 0 : return pstrdup("");
196 : : /* otherwise, we must remove protective backslashes added by outToken */
1076 peter@eisentraut.org 197 :CBC 346677 : 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 *
6071 tgl@sss.pgh.pa.us 209 : 1207933 : _readBitmapset(void)
210 : : {
5931 bruce@momjian.us 211 : 1207933 : Bitmapset *result = NULL;
212 : :
213 : : READ_TEMP_LOCALS();
214 : :
6071 tgl@sss.pgh.pa.us 215 : 1207933 : token = pg_strtok(&length);
216 [ - + ]: 1207933 : if (token == NULL)
6071 tgl@sss.pgh.pa.us 217 [ # # ]:UBC 0 : elog(ERROR, "incomplete Bitmapset structure");
6071 tgl@sss.pgh.pa.us 218 [ + - - + ]:CBC 1207933 : if (length != 1 || token[0] != '(')
6071 tgl@sss.pgh.pa.us 219 [ # # ]:UBC 0 : elog(ERROR, "unrecognized token: \"%.*s\"", length, token);
220 : :
6071 tgl@sss.pgh.pa.us 221 :CBC 1207933 : token = pg_strtok(&length);
222 [ - + ]: 1207933 : if (token == NULL)
6071 tgl@sss.pgh.pa.us 223 [ # # ]:UBC 0 : elog(ERROR, "incomplete Bitmapset structure");
6071 tgl@sss.pgh.pa.us 224 [ + - + - ]:CBC 1207933 : if (length != 1 || token[0] != 'b')
6071 tgl@sss.pgh.pa.us 225 [ # # ]:UBC 0 : elog(ERROR, "unrecognized token: \"%.*s\"", length, token);
226 : :
227 : : for (;;)
6071 tgl@sss.pgh.pa.us 228 :CBC 314273 : {
229 : : int val;
230 : : char *endptr;
231 : :
232 : 1522206 : token = pg_strtok(&length);
233 [ - + ]: 1522206 : if (token == NULL)
6071 tgl@sss.pgh.pa.us 234 [ # # ]:UBC 0 : elog(ERROR, "unterminated Bitmapset structure");
6071 tgl@sss.pgh.pa.us 235 [ + + + + ]:CBC 1522206 : if (length == 1 && token[0] == ')')
236 : 1207933 : break;
237 : 314273 : val = (int) strtol(token, &endptr, 10);
238 [ - + ]: 314273 : if (endptr != token + length)
6071 tgl@sss.pgh.pa.us 239 [ # # ]:UBC 0 : elog(ERROR, "unrecognized integer: \"%.*s\"", length, token);
6071 tgl@sss.pgh.pa.us 240 :CBC 314273 : result = bms_add_member(result, val);
241 : : }
242 : :
243 : 1207933 : 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 *
3494 rhaas@postgresql.org 251 :UBC 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 *
1155 peter@eisentraut.org 265 :CBC 268413 : _readConst(void)
266 : : {
267 : 268413 : READ_LOCALS(Const);
268 : :
269 : 268413 : READ_OID_FIELD(consttype);
270 : 268413 : READ_INT_FIELD(consttypmod);
271 : 268413 : READ_OID_FIELD(constcollid);
272 : 268413 : READ_INT_FIELD(constlen);
273 : 268413 : READ_BOOL_FIELD(constbyval);
274 : 268413 : READ_BOOL_FIELD(constisnull);
3766 andres@anarazel.de 275 [ - + ]: 268413 : READ_LOCATION_FIELD(location);
276 : :
1155 peter@eisentraut.org 277 : 268413 : token = pg_strtok(&length); /* skip :constvalue */
278 [ + + ]: 268413 : if (local_node->constisnull)
279 : 36907 : token = pg_strtok(&length); /* skip "<>" */
280 : : else
281 : 231506 : local_node->constvalue = readDatum(local_node->constbyval);
282 : :
1678 283 : 268413 : READ_DONE();
284 : : }
285 : :
286 : : static BoolExpr *
1155 287 : 20475 : _readBoolExpr(void)
288 : : {
289 : 20475 : READ_LOCALS(BoolExpr);
290 : :
291 : : /* do-it-yourself enum representation */
292 : 20475 : token = pg_strtok(&length); /* skip :boolop */
293 : 20475 : token = pg_strtok(&length); /* get field value */
1078 294 [ + + + + ]: 20475 : if (length == 3 && strncmp(token, "and", 3) == 0)
1155 295 : 13209 : local_node->boolop = AND_EXPR;
1078 296 [ + + + - ]: 7266 : else if (length == 2 && strncmp(token, "or", 2) == 0)
1155 297 : 5143 : local_node->boolop = OR_EXPR;
1078 298 [ + - + - ]: 2123 : else if (length == 3 && strncmp(token, "not", 3) == 0)
1155 299 : 2123 : local_node->boolop = NOT_EXPR;
300 : : else
1155 peter@eisentraut.org 301 [ # # ]:UBC 0 : elog(ERROR, "unrecognized boolop \"%.*s\"", length, token);
302 : :
1155 peter@eisentraut.org 303 :CBC 20475 : READ_NODE_FIELD(args);
6181 tgl@sss.pgh.pa.us 304 [ - + ]: 20475 : READ_LOCATION_FIELD(location);
305 : :
8321 306 : 20475 : READ_DONE();
307 : : }
308 : :
309 : : static A_Const *
1078 peter@eisentraut.org 310 :UBC 0 : _readA_Const(void)
311 : : {
312 : 0 : READ_LOCALS(A_Const);
313 : :
314 : : /* We expect either NULL or :val here */
315 : 0 : token = pg_strtok(&length);
316 [ # # # # ]: 0 : if (length == 4 && strncmp(token, "NULL", 4) == 0)
317 : 0 : local_node->isnull = true;
318 : : else
319 : : {
320 : 0 : union ValUnion *tmp = nodeRead(NULL, 0);
321 : :
322 : : /* To forestall valgrind complaints, copy only the valid data */
902 tgl@sss.pgh.pa.us 323 [ # # # # : 0 : switch (nodeTag(tmp))
# # ]
324 : : {
325 : 0 : case T_Integer:
326 : 0 : memcpy(&local_node->val, tmp, sizeof(Integer));
327 : 0 : break;
328 : 0 : case T_Float:
329 : 0 : memcpy(&local_node->val, tmp, sizeof(Float));
330 : 0 : break;
331 : 0 : case T_Boolean:
332 : 0 : memcpy(&local_node->val, tmp, sizeof(Boolean));
333 : 0 : break;
334 : 0 : case T_String:
335 : 0 : memcpy(&local_node->val, tmp, sizeof(String));
336 : 0 : break;
337 : 0 : case T_BitString:
338 : 0 : memcpy(&local_node->val, tmp, sizeof(BitString));
339 : 0 : break;
340 : 0 : default:
341 [ # # ]: 0 : elog(ERROR, "unrecognized node type: %d",
342 : : (int) nodeTag(tmp));
343 : : break;
344 : : }
345 : : }
346 : :
1078 peter@eisentraut.org 347 [ # # ]: 0 : READ_LOCATION_FIELD(location);
348 : :
349 : 0 : READ_DONE();
350 : : }
351 : :
352 : : static RangeTblEntry *
1155 peter@eisentraut.org 353 :CBC 83312 : _readRangeTblEntry(void)
354 : : {
355 : 83312 : READ_LOCALS(RangeTblEntry);
356 : :
357 : 83312 : READ_NODE_FIELD(alias);
358 : 83312 : READ_NODE_FIELD(eref);
359 : 83312 : READ_ENUM_FIELD(rtekind, RTEKind);
360 : :
361 [ + + + + : 83312 : switch (local_node->rtekind)
+ + + - +
+ - ]
362 : : {
363 : 51045 : case RTE_RELATION:
364 : 51045 : READ_OID_FIELD(relid);
548 365 : 51045 : READ_BOOL_FIELD(inh);
1155 366 [ + - - + ]: 51045 : READ_CHAR_FIELD(relkind);
367 : 51045 : READ_INT_FIELD(rellockmode);
1005 alvherre@alvh.no-ip. 368 : 51045 : READ_UINT_FIELD(perminfoindex);
550 peter@eisentraut.org 369 : 51045 : READ_NODE_FIELD(tablesample);
1155 370 : 51045 : break;
371 : 8900 : case RTE_SUBQUERY:
372 : 8900 : READ_NODE_FIELD(subquery);
373 : 8900 : READ_BOOL_FIELD(security_barrier);
374 : : /* we re-use these RELATION fields, too: */
962 tgl@sss.pgh.pa.us 375 : 8900 : READ_OID_FIELD(relid);
548 peter@eisentraut.org 376 : 8900 : READ_BOOL_FIELD(inh);
816 amitlan@postgresql.o 377 [ + + - + ]: 8900 : READ_CHAR_FIELD(relkind);
962 tgl@sss.pgh.pa.us 378 : 8900 : READ_INT_FIELD(rellockmode);
379 : 8900 : READ_UINT_FIELD(perminfoindex);
1155 peter@eisentraut.org 380 : 8900 : break;
381 : 14848 : case RTE_JOIN:
382 : 14848 : READ_ENUM_FIELD(jointype, JoinType);
383 : 14848 : READ_INT_FIELD(joinmergedcols);
384 : 14848 : READ_NODE_FIELD(joinaliasvars);
385 : 14848 : READ_NODE_FIELD(joinleftcols);
386 : 14848 : READ_NODE_FIELD(joinrightcols);
387 : 14848 : READ_NODE_FIELD(join_using_alias);
388 : 14848 : break;
389 : 6455 : case RTE_FUNCTION:
390 : 6455 : READ_NODE_FIELD(functions);
391 : 6455 : READ_BOOL_FIELD(funcordinality);
392 : 6455 : break;
393 : 139 : case RTE_TABLEFUNC:
394 : 139 : READ_NODE_FIELD(tablefunc);
395 : : /* The RTE must have a copy of the column type info, if any */
396 [ + - ]: 139 : if (local_node->tablefunc)
397 : : {
398 : 139 : TableFunc *tf = local_node->tablefunc;
399 : :
400 : 139 : local_node->coltypes = tf->coltypes;
401 : 139 : local_node->coltypmods = tf->coltypmods;
402 : 139 : local_node->colcollations = tf->colcollations;
403 : : }
404 : 139 : break;
405 : 669 : case RTE_VALUES:
406 : 669 : READ_NODE_FIELD(values_lists);
407 : 669 : READ_NODE_FIELD(coltypes);
408 : 669 : READ_NODE_FIELD(coltypmods);
409 : 669 : READ_NODE_FIELD(colcollations);
410 : 669 : break;
411 : 265 : case RTE_CTE:
412 : 265 : READ_STRING_FIELD(ctename);
413 : 265 : READ_UINT_FIELD(ctelevelsup);
414 : 265 : READ_BOOL_FIELD(self_reference);
415 : 265 : READ_NODE_FIELD(coltypes);
416 : 265 : READ_NODE_FIELD(coltypmods);
417 : 265 : READ_NODE_FIELD(colcollations);
418 : 265 : break;
1155 peter@eisentraut.org 419 :UBC 0 : case RTE_NAMEDTUPLESTORE:
420 : 0 : READ_STRING_FIELD(enrname);
421 : 0 : READ_FLOAT_FIELD(enrtuples);
422 : 0 : READ_NODE_FIELD(coltypes);
423 : 0 : READ_NODE_FIELD(coltypmods);
424 : 0 : READ_NODE_FIELD(colcollations);
425 : : /* we re-use these RELATION fields, too: */
962 tgl@sss.pgh.pa.us 426 : 0 : READ_OID_FIELD(relid);
1155 peter@eisentraut.org 427 : 0 : break;
1155 peter@eisentraut.org 428 :CBC 57 : case RTE_RESULT:
429 : : /* no extra fields */
430 : 57 : break;
361 rguo@postgresql.org 431 : 934 : case RTE_GROUP:
432 : 934 : READ_NODE_FIELD(groupexprs);
433 : 934 : break;
1155 peter@eisentraut.org 434 :UBC 0 : default:
435 [ # # ]: 0 : elog(ERROR, "unrecognized RTE kind: %d",
436 : : (int) local_node->rtekind);
437 : : break;
438 : : }
439 : :
1155 peter@eisentraut.org 440 :CBC 83312 : READ_BOOL_FIELD(lateral);
441 : 83312 : READ_BOOL_FIELD(inFromCl);
442 : 83312 : READ_NODE_FIELD(securityQuals);
443 : :
8321 tgl@sss.pgh.pa.us 444 : 83312 : READ_DONE();
445 : : }
446 : :
447 : : static A_Expr *
1078 peter@eisentraut.org 448 :UBC 0 : _readA_Expr(void)
449 : : {
450 : 0 : READ_LOCALS(A_Expr);
451 : :
452 : 0 : token = pg_strtok(&length);
453 : :
454 [ # # # # ]: 0 : if (length == 3 && strncmp(token, "ANY", 3) == 0)
455 : : {
456 : 0 : local_node->kind = AEXPR_OP_ANY;
457 : 0 : READ_NODE_FIELD(name);
458 : : }
459 [ # # # # ]: 0 : else if (length == 3 && strncmp(token, "ALL", 3) == 0)
460 : : {
461 : 0 : local_node->kind = AEXPR_OP_ALL;
462 : 0 : READ_NODE_FIELD(name);
463 : : }
464 [ # # # # ]: 0 : else if (length == 8 && strncmp(token, "DISTINCT", 8) == 0)
465 : : {
466 : 0 : local_node->kind = AEXPR_DISTINCT;
467 : 0 : READ_NODE_FIELD(name);
468 : : }
469 [ # # # # ]: 0 : else if (length == 12 && strncmp(token, "NOT_DISTINCT", 12) == 0)
470 : : {
471 : 0 : local_node->kind = AEXPR_NOT_DISTINCT;
472 : 0 : READ_NODE_FIELD(name);
473 : : }
474 [ # # # # ]: 0 : else if (length == 6 && strncmp(token, "NULLIF", 6) == 0)
475 : : {
476 : 0 : local_node->kind = AEXPR_NULLIF;
477 : 0 : READ_NODE_FIELD(name);
478 : : }
479 [ # # # # ]: 0 : else if (length == 2 && strncmp(token, "IN", 2) == 0)
480 : : {
481 : 0 : local_node->kind = AEXPR_IN;
482 : 0 : READ_NODE_FIELD(name);
483 : : }
484 [ # # # # ]: 0 : else if (length == 4 && strncmp(token, "LIKE", 4) == 0)
485 : : {
486 : 0 : local_node->kind = AEXPR_LIKE;
487 : 0 : READ_NODE_FIELD(name);
488 : : }
489 [ # # # # ]: 0 : else if (length == 5 && strncmp(token, "ILIKE", 5) == 0)
490 : : {
491 : 0 : local_node->kind = AEXPR_ILIKE;
492 : 0 : READ_NODE_FIELD(name);
493 : : }
494 [ # # # # ]: 0 : else if (length == 7 && strncmp(token, "SIMILAR", 7) == 0)
495 : : {
496 : 0 : local_node->kind = AEXPR_SIMILAR;
497 : 0 : READ_NODE_FIELD(name);
498 : : }
499 [ # # # # ]: 0 : else if (length == 7 && strncmp(token, "BETWEEN", 7) == 0)
500 : : {
501 : 0 : local_node->kind = AEXPR_BETWEEN;
502 : 0 : READ_NODE_FIELD(name);
503 : : }
504 [ # # # # ]: 0 : else if (length == 11 && strncmp(token, "NOT_BETWEEN", 11) == 0)
505 : : {
506 : 0 : local_node->kind = AEXPR_NOT_BETWEEN;
507 : 0 : READ_NODE_FIELD(name);
508 : : }
509 [ # # # # ]: 0 : else if (length == 11 && strncmp(token, "BETWEEN_SYM", 11) == 0)
510 : : {
511 : 0 : local_node->kind = AEXPR_BETWEEN_SYM;
512 : 0 : READ_NODE_FIELD(name);
513 : : }
514 [ # # # # ]: 0 : else if (length == 15 && strncmp(token, "NOT_BETWEEN_SYM", 15) == 0)
515 : : {
516 : 0 : local_node->kind = AEXPR_NOT_BETWEEN_SYM;
517 : 0 : READ_NODE_FIELD(name);
518 : : }
519 [ # # # # ]: 0 : else if (length == 5 && strncmp(token, ":name", 5) == 0)
520 : : {
521 : 0 : local_node->kind = AEXPR_OP;
522 : 0 : local_node->name = nodeRead(NULL, 0);
523 : : }
524 : : else
525 [ # # ]: 0 : elog(ERROR, "unrecognized A_Expr kind: \"%.*s\"", length, token);
526 : :
527 : 0 : READ_NODE_FIELD(lexpr);
528 : 0 : READ_NODE_FIELD(rexpr);
86 alvherre@kurilemu.de 529 [ # # ]: 0 : READ_LOCATION_FIELD(rexpr_list_start);
530 [ # # ]: 0 : READ_LOCATION_FIELD(rexpr_list_end);
1078 peter@eisentraut.org 531 [ # # ]: 0 : READ_LOCATION_FIELD(location);
532 : :
533 : 0 : READ_DONE();
534 : : }
535 : :
536 : : static ExtensibleNode *
1155 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 : :
8321 tgl@sss.pgh.pa.us 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 *
8321 tgl@sss.pgh.pa.us 573 :CBC 2433626 : parseNodeString(void)
574 : : {
575 : : READ_TEMP_LOCALS();
576 : :
577 : : /* Guard against stack overflow due to overly complex expressions */
2462 578 : 2433626 : check_stack_depth();
579 : :
9008 580 : 2433626 : 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 : :
815 noah@leadboat.com 587 [ # # ]:UBC 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
9008 tgl@sss.pgh.pa.us 600 :CBC 231506 : 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 : 231506 : token = pg_strtok(&tokenLength);
9007 613 : 231506 : length = atoui(token);
614 : :
8831 615 : 231506 : token = pg_strtok(&tokenLength); /* read the '[' */
616 [ + - - + ]: 231506 : if (token == NULL || token[0] != '[')
4244 tgl@sss.pgh.pa.us 617 [ # # # # ]:UBC 0 : elog(ERROR, "expected \"[\" to start datum, but got \"%s\"; length = %zu",
618 : : token ? token : "[NULL]", length);
619 : :
9008 tgl@sss.pgh.pa.us 620 [ + + ]:CBC 231506 : if (typbyval)
621 : : {
9007 622 [ - + ]: 170250 : if (length > (Size) sizeof(Datum))
4244 tgl@sss.pgh.pa.us 623 [ # # ]:UBC 0 : elog(ERROR, "byval datum but length = %zu", length);
9367 tgl@sss.pgh.pa.us 624 :CBC 170250 : res = (Datum) 0;
10226 bruce@momjian.us 625 : 170250 : s = (char *) (&res);
9007 tgl@sss.pgh.pa.us 626 [ + + ]: 1532250 : for (i = 0; i < (Size) sizeof(Datum); i++)
627 : : {
9008 628 : 1362000 : token = pg_strtok(&tokenLength);
10226 bruce@momjian.us 629 : 1362000 : s[i] = (char) atoi(token);
630 : : }
631 : : }
632 [ - + ]: 61256 : else if (length <= 0)
29 tgl@sss.pgh.pa.us 633 :UNC 0 : res = (Datum) 0;
634 : : else
635 : : {
10226 bruce@momjian.us 636 :CBC 61256 : s = (char *) palloc(length);
637 [ + + ]: 2061809 : for (i = 0; i < length; i++)
638 : : {
9008 tgl@sss.pgh.pa.us 639 : 2000553 : token = pg_strtok(&tokenLength);
10226 bruce@momjian.us 640 : 2000553 : s[i] = (char) atoi(token);
641 : : }
642 : 61256 : res = PointerGetDatum(s);
643 : : }
644 : :
8831 tgl@sss.pgh.pa.us 645 : 231506 : token = pg_strtok(&tokenLength); /* read the ']' */
9008 646 [ + - - + ]: 231506 : if (token == NULL || token[0] != ']')
4244 tgl@sss.pgh.pa.us 647 [ # # # # ]:UBC 0 : elog(ERROR, "expected \"]\" to end datum, but got \"%s\"; length = %zu",
648 : : token ? token : "[NULL]", length);
649 : :
9867 bruce@momjian.us 650 :CBC 231506 : 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 : : */
1144 tgl@sss.pgh.pa.us 692 [ - + - - : 1665 : READ_SCALAR_ARRAY(readAttrNumberCols, int16, atoi)
+ + + - -
+ - - + -
- + - - +
+ + - + -
- + - - ]
693 [ - + - - : 4176 : 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 [ - + - - : 2322 : READ_SCALAR_ARRAY(readIntCols, int, atoi)
- + + - -
+ - - + -
- + - - +
+ + - + -
- + - - ]
697 [ - + - - : 530 : READ_SCALAR_ARRAY(readBoolCols, bool, strtobool)
- + + - -
+ - - + -
- + - - +
+ + - + -
- + - - ]
|