1/*-------------------------------------------------------------------------
4 * Reader functions for Postgres tree nodes.
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/nodes/readfuncs.c
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.
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.
25 *-------------------------------------------------------------------------
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
43/* Macros for declaring appropriate local variables */
45/* A few guys need only local_node */
46 #define READ_LOCALS_NO_FIELDS(nodeTypeName) \
47 nodeTypeName *local_node = makeNode(nodeTypeName)
49/* And a few guys need only the pg_strtok support fields */
50 #define READ_TEMP_LOCALS() \
54/* ... but most need both */
55 #define READ_LOCALS(nodeTypeName) \
56 READ_LOCALS_NO_FIELDS(nodeTypeName); \
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)
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)
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)
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)
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)
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)
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])
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)
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)
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)
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)
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
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" */
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)
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()
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)
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)
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)
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)
173 #define READ_DONE() \
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.)
183 #define atoui(x) ((unsigned int) strtoul((x), NULL, 10))
185 #define strtobool(x) ((*(x) == 't') ? true : false)
190 /* outToken emits <> for NULL, and pg_strtok makes that an empty string */
193 /* outToken emits "" for empty string */
194 if (length == 2 &&
token[0] ==
'"' &&
token[1] ==
'"')
196 /* otherwise, we must remove protective backslashes added by outToken */
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.
217 elog(
ERROR,
"incomplete Bitmapset structure");
218 if (length != 1 ||
token[0] !=
'(')
223 elog(
ERROR,
"incomplete Bitmapset structure");
224 if (length != 1 ||
token[0] !=
'b')
234 elog(
ERROR,
"unterminated Bitmapset structure");
235 if (length == 1 &&
token[0] ==
')')
237 val = (int) strtol(
token, &endptr, 10);
238 if (endptr !=
token + length)
247 * We export this function for use by extensions that define extensible nodes.
248 * That's somewhat historical, though, because calling nodeRead() will work.
256#include "readfuncs.funcs.c"
260 * Support functions for nodes with custom_read_write attribute or
261 * special_read_write attribute
278 if (local_node->constisnull)
281 local_node->constvalue =
readDatum(local_node->constbyval);
291 /* do-it-yourself enum representation */
294 if (length == 3 && strncmp(
token,
"and", 3) == 0)
296 else if (length == 2 && strncmp(
token,
"or", 2) == 0)
298 else if (length == 3 && strncmp(
token,
"not", 3) == 0)
314 /* We expect either NULL or :val here */
316 if (length == 4 && strncmp(
token,
"NULL", 4) == 0)
317 local_node->isnull =
true;
322 /* To forestall valgrind complaints, copy only the valid data */
326 memcpy(&local_node->val, tmp,
sizeof(
Integer));
329 memcpy(&local_node->val, tmp,
sizeof(
Float));
332 memcpy(&local_node->val, tmp,
sizeof(
Boolean));
335 memcpy(&local_node->val, tmp,
sizeof(
String));
338 memcpy(&local_node->val, tmp,
sizeof(
BitString));
341 elog(
ERROR,
"unrecognized node type: %d",
361 switch (local_node->rtekind)
374 /* we re-use these RELATION fields, too: */
395 /* The RTE must have a copy of the column type info, if any */
396 if (local_node->tablefunc)
400 local_node->coltypes = tf->coltypes;
401 local_node->coltypmods = tf->coltypmods;
402 local_node->colcollations = tf->colcollations;
425 /* we re-use these RELATION fields, too: */
429 /* no extra fields */
436 (
int) local_node->rtekind);
454 if (length == 3 && strncmp(
token,
"ANY", 3) == 0)
459 else if (length == 3 && strncmp(
token,
"ALL", 3) == 0)
464 else if (length == 8 && strncmp(
token,
"DISTINCT", 8) == 0)
469 else if (length == 12 && strncmp(
token,
"NOT_DISTINCT", 12) == 0)
474 else if (length == 6 && strncmp(
token,
"NULLIF", 6) == 0)
479 else if (length == 2 && strncmp(
token,
"IN", 2) == 0)
484 else if (length == 4 && strncmp(
token,
"LIKE", 4) == 0)
489 else if (length == 5 && strncmp(
token,
"ILIKE", 5) == 0)
494 else if (length == 7 && strncmp(
token,
"SIMILAR", 7) == 0)
499 else if (length == 7 && strncmp(
token,
"BETWEEN", 7) == 0)
504 else if (length == 11 && strncmp(
token,
"NOT_BETWEEN", 11) == 0)
509 else if (length == 11 && strncmp(
token,
"BETWEEN_SYM", 11) == 0)
514 else if (length == 15 && strncmp(
token,
"NOT_BETWEEN_SYM", 15) == 0)
519 else if (length == 5 && strncmp(
token,
":name", 5) == 0)
522 local_node->name =
nodeRead(NULL, 0);
541 const char *extnodename;
550 elog(
ERROR,
"extnodename has to be supplied");
557 /* deserialize the private fields */
567 * Given a character string representing a node tree, parseNodeString creates
568 * the internal node structure.
570 * The string to be read must already have been loaded into pg_strtok().
577 /* Guard against stack overflow due to overly complex expressions */
582#define MATCH(tokname, namelen) \
583 (length == namelen && memcmp(token, tokname, namelen) == 0)
585#include "readfuncs.switch.c"
588 return NULL;
/* keep compiler quiet */
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.
610 * read the actual length of the value
617 elog(
ERROR,
"expected \"[\" to start datum, but got \"%s\"; length = %zu",
623 elog(
ERROR,
"byval datum but length = %zu", length);
629 s[
i] = (char) atoi(
token);
632 else if (length <= 0)
636 s = (
char *)
palloc(length);
637 for (
i = 0;
i < length;
i++)
640 s[
i] = (char) atoi(
token);
647 elog(
ERROR,
"expected \"]\" to end datum, but got \"%s\"; length = %zu",
654 * common implementation for scalar-array-reading functions
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.
661 #define READ_SCALAR_ARRAY(fnname, datatype, convfunc) \
666 READ_TEMP_LOCALS(); \
667 token = pg_strtok(&length); \
669 elog(ERROR, "incomplete scalar array"); \
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++) \
677 token = pg_strtok(&length); \
678 if (token == NULL || token[0] == ')') \
679 elog(ERROR, "incomplete scalar array"); \
680 vals[i] = convfunc(token); \
682 token = pg_strtok(&length); \
683 if (token == NULL || length != 1 || token[0] != ')') \
684 elog(ERROR, "incomplete scalar array"); \
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.
694/* outfuncs.c has writeIndexCols, but we don't yet need that here */
695/* READ_SCALAR_ARRAY(readIndexCols, Index, atoui) */
Bitmapset * bms_add_member(Bitmapset *a, int x)
const ExtensibleNodeMethods * GetExtensibleNodeMethods(const char *extnodename, bool missing_ok)
char * pstrdup(const char *in)
int * readIntCols(int numCols)
static Node * newNode(size_t size, NodeTag tag)
Oid * readOidCols(int numCols)
int16 * readAttrNumberCols(int numCols)
bool * readBoolCols(int numCols)
static Datum PointerGetDatum(const void *X)
char * debackslash(const char *token, int length)
void * nodeRead(const char *token, int tok_len)
const char * pg_strtok(int *length)
#define READ_INT_FIELD(fldname)
#define READ_UINT_FIELD(fldname)
#define READ_NODE_FIELD(fldname)
static ExtensibleNode * _readExtensibleNode(void)
#define READ_CHAR_FIELD(fldname)
static char * nullable_string(const char *token, int length)
#define READ_SCALAR_ARRAY(fnname, datatype, convfunc)
Node * parseNodeString(void)
#define READ_OID_FIELD(fldname)
#define READ_LOCATION_FIELD(fldname)
static Bitmapset * _readBitmapset(void)
static A_Const * _readA_Const(void)
static Const * _readConst(void)
#define READ_STRING_FIELD(fldname)
#define READ_FLOAT_FIELD(fldname)
Datum readDatum(bool typbyval)
#define READ_BOOL_FIELD(fldname)
static BoolExpr * _readBoolExpr(void)
#define READ_ENUM_FIELD(fldname, enumtype)
#define READ_TEMP_LOCALS()
static A_Expr * _readA_Expr(void)
Bitmapset * readBitmapset(void)
#define READ_LOCALS(nodeTypeName)
static RangeTblEntry * _readRangeTblEntry(void)
static const struct fns functions
void check_stack_depth(void)
void(* nodeRead)(struct ExtensibleNode *node)