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