aboutsummaryrefslogtreecommitdiffstats
path: root/yql/essentials/parser/pg_wrapper/postgresql/src/backend/nodes/readfuncs.c
diff options
context:
space:
mode:
authorvvvv <vvvv@yandex-team.com>2024-11-07 12:29:36 +0300
committervvvv <vvvv@yandex-team.com>2024-11-07 13:49:47 +0300
commitd4c258e9431675bab6745c8638df6e3dfd4dca6b (patch)
treeb5efcfa11351152a4c872fccaea35749141c0b11 /yql/essentials/parser/pg_wrapper/postgresql/src/backend/nodes/readfuncs.c
parent13a4f274caef5cfdaf0263b24e4d6bdd5521472b (diff)
downloadydb-d4c258e9431675bab6745c8638df6e3dfd4dca6b.tar.gz
Moved other yql/essentials libs YQL-19206
init commit_hash:7d4c435602078407bbf20dd3c32f9c90d2bbcbc0
Diffstat (limited to 'yql/essentials/parser/pg_wrapper/postgresql/src/backend/nodes/readfuncs.c')
-rw-r--r--yql/essentials/parser/pg_wrapper/postgresql/src/backend/nodes/readfuncs.c822
1 files changed, 822 insertions, 0 deletions
diff --git a/yql/essentials/parser/pg_wrapper/postgresql/src/backend/nodes/readfuncs.c b/yql/essentials/parser/pg_wrapper/postgresql/src/backend/nodes/readfuncs.c
new file mode 100644
index 00000000000..97e43cbb49c
--- /dev/null
+++ b/yql/essentials/parser/pg_wrapper/postgresql/src/backend/nodes/readfuncs.c
@@ -0,0 +1,822 @@
+/*-------------------------------------------------------------------------
+ *
+ * readfuncs.c
+ * Reader functions for Postgres tree nodes.
+ *
+ * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * src/backend/nodes/readfuncs.c
+ *
+ * NOTES
+ * Parse location fields are written out by outfuncs.c, but only for
+ * debugging use. When reading a location field, we normally discard
+ * the stored value and set the location field to -1 (ie, "unknown").
+ * This is because nodes coming from a stored rule should not be thought
+ * to have a known location in the current query's text.
+ *
+ * However, if restore_location_fields is true, we do restore location
+ * fields from the string. This is currently intended only for use by the
+ * WRITE_READ_PARSE_PLAN_TREES test code, which doesn't want to cause
+ * any change in the node contents.
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include <math.h>
+
+#include "miscadmin.h"
+#include "nodes/bitmapset.h"
+#include "nodes/readfuncs.h"
+
+
+/*
+ * Macros to simplify reading of different kinds of fields. Use these
+ * wherever possible to reduce the chance for silly typos. Note that these
+ * hard-wire conventions about the names of the local variables in a Read
+ * routine.
+ */
+
+/* Macros for declaring appropriate local variables */
+
+/* A few guys need only local_node */
+#define READ_LOCALS_NO_FIELDS(nodeTypeName) \
+ nodeTypeName *local_node = makeNode(nodeTypeName)
+
+/* And a few guys need only the pg_strtok support fields */
+#define READ_TEMP_LOCALS() \
+ const char *token; \
+ int length
+
+/* ... but most need both */
+#define READ_LOCALS(nodeTypeName) \
+ READ_LOCALS_NO_FIELDS(nodeTypeName); \
+ READ_TEMP_LOCALS()
+
+/* Read an integer field (anything written as ":fldname %d") */
+#define READ_INT_FIELD(fldname) \
+ token = pg_strtok(&length); /* skip :fldname */ \
+ token = pg_strtok(&length); /* get field value */ \
+ local_node->fldname = atoi(token)
+
+/* Read an unsigned integer field (anything written as ":fldname %u") */
+#define READ_UINT_FIELD(fldname) \
+ token = pg_strtok(&length); /* skip :fldname */ \
+ token = pg_strtok(&length); /* get field value */ \
+ local_node->fldname = atoui(token)
+
+/* Read an unsigned integer field (anything written using UINT64_FORMAT) */
+#define READ_UINT64_FIELD(fldname) \
+ token = pg_strtok(&length); /* skip :fldname */ \
+ token = pg_strtok(&length); /* get field value */ \
+ local_node->fldname = strtou64(token, NULL, 10)
+
+/* Read a long integer field (anything written as ":fldname %ld") */
+#define READ_LONG_FIELD(fldname) \
+ token = pg_strtok(&length); /* skip :fldname */ \
+ token = pg_strtok(&length); /* get field value */ \
+ local_node->fldname = atol(token)
+
+/* Read an OID field (don't hard-wire assumption that OID is same as uint) */
+#define READ_OID_FIELD(fldname) \
+ token = pg_strtok(&length); /* skip :fldname */ \
+ token = pg_strtok(&length); /* get field value */ \
+ local_node->fldname = atooid(token)
+
+/* Read a char field (ie, one ascii character) */
+#define READ_CHAR_FIELD(fldname) \
+ token = pg_strtok(&length); /* skip :fldname */ \
+ token = pg_strtok(&length); /* get field value */ \
+ /* avoid overhead of calling debackslash() for one char */ \
+ local_node->fldname = (length == 0) ? '\0' : (token[0] == '\\' ? token[1] : token[0])
+
+/* Read an enumerated-type field that was written as an integer code */
+#define READ_ENUM_FIELD(fldname, enumtype) \
+ token = pg_strtok(&length); /* skip :fldname */ \
+ token = pg_strtok(&length); /* get field value */ \
+ local_node->fldname = (enumtype) atoi(token)
+
+/* Read a float field */
+#define READ_FLOAT_FIELD(fldname) \
+ token = pg_strtok(&length); /* skip :fldname */ \
+ token = pg_strtok(&length); /* get field value */ \
+ local_node->fldname = atof(token)
+
+/* Read a boolean field */
+#define READ_BOOL_FIELD(fldname) \
+ token = pg_strtok(&length); /* skip :fldname */ \
+ token = pg_strtok(&length); /* get field value */ \
+ local_node->fldname = strtobool(token)
+
+/* Read a character-string field */
+#define READ_STRING_FIELD(fldname) \
+ token = pg_strtok(&length); /* skip :fldname */ \
+ token = pg_strtok(&length); /* get field value */ \
+ local_node->fldname = nullable_string(token, length)
+
+/* Read a parse location field (and possibly throw away the value) */
+#ifdef WRITE_READ_PARSE_PLAN_TREES
+#define READ_LOCATION_FIELD(fldname) \
+ token = pg_strtok(&length); /* skip :fldname */ \
+ token = pg_strtok(&length); /* get field value */ \
+ local_node->fldname = restore_location_fields ? atoi(token) : -1
+#else
+#define READ_LOCATION_FIELD(fldname) \
+ token = pg_strtok(&length); /* skip :fldname */ \
+ token = pg_strtok(&length); /* get field value */ \
+ (void) token; /* in case not used elsewhere */ \
+ local_node->fldname = -1 /* set field to "unknown" */
+#endif
+
+/* Read a Node field */
+#define READ_NODE_FIELD(fldname) \
+ token = pg_strtok(&length); /* skip :fldname */ \
+ (void) token; /* in case not used elsewhere */ \
+ local_node->fldname = nodeRead(NULL, 0)
+
+/* Read a bitmapset field */
+#define READ_BITMAPSET_FIELD(fldname) \
+ token = pg_strtok(&length); /* skip :fldname */ \
+ (void) token; /* in case not used elsewhere */ \
+ local_node->fldname = _readBitmapset()
+
+/* Read an attribute number array */
+#define READ_ATTRNUMBER_ARRAY(fldname, len) \
+ token = pg_strtok(&length); /* skip :fldname */ \
+ local_node->fldname = readAttrNumberCols(len)
+
+/* Read an oid array */
+#define READ_OID_ARRAY(fldname, len) \
+ token = pg_strtok(&length); /* skip :fldname */ \
+ local_node->fldname = readOidCols(len)
+
+/* Read an int array */
+#define READ_INT_ARRAY(fldname, len) \
+ token = pg_strtok(&length); /* skip :fldname */ \
+ local_node->fldname = readIntCols(len)
+
+/* Read a bool array */
+#define READ_BOOL_ARRAY(fldname, len) \
+ token = pg_strtok(&length); /* skip :fldname */ \
+ local_node->fldname = readBoolCols(len)
+
+/* Routine exit */
+#define READ_DONE() \
+ return local_node
+
+
+/*
+ * NOTE: use atoi() to read values written with %d, or atoui() to read
+ * values written with %u in outfuncs.c. An exception is OID values,
+ * for which use atooid(). (As of 7.1, outfuncs.c writes OIDs as %u,
+ * but this will probably change in the future.)
+ */
+#define atoui(x) ((unsigned int) strtoul((x), NULL, 10))
+
+#define strtobool(x) ((*(x) == 't') ? true : false)
+
+static char *
+nullable_string(const char *token, int length)
+{
+ /* outToken emits <> for NULL, and pg_strtok makes that an empty string */
+ if (length == 0)
+ return NULL;
+ /* outToken emits "" for empty string */
+ if (length == 2 && token[0] == '"' && token[1] == '"')
+ return pstrdup("");
+ /* otherwise, we must remove protective backslashes added by outToken */
+ return debackslash(token, length);
+}
+
+
+/*
+ * _readBitmapset
+ *
+ * Note: this code is used in contexts where we know that a Bitmapset
+ * is expected. There is equivalent code in nodeRead() that can read a
+ * Bitmapset when we come across one in other contexts.
+ */
+static Bitmapset *
+_readBitmapset(void)
+{
+ Bitmapset *result = NULL;
+
+ READ_TEMP_LOCALS();
+
+ token = pg_strtok(&length);
+ if (token == NULL)
+ elog(ERROR, "incomplete Bitmapset structure");
+ if (length != 1 || token[0] != '(')
+ elog(ERROR, "unrecognized token: \"%.*s\"", length, token);
+
+ token = pg_strtok(&length);
+ if (token == NULL)
+ elog(ERROR, "incomplete Bitmapset structure");
+ if (length != 1 || token[0] != 'b')
+ elog(ERROR, "unrecognized token: \"%.*s\"", length, token);
+
+ for (;;)
+ {
+ int val;
+ char *endptr;
+
+ token = pg_strtok(&length);
+ if (token == NULL)
+ elog(ERROR, "unterminated Bitmapset structure");
+ if (length == 1 && token[0] == ')')
+ break;
+ val = (int) strtol(token, &endptr, 10);
+ if (endptr != token + length)
+ elog(ERROR, "unrecognized integer: \"%.*s\"", length, token);
+ result = bms_add_member(result, val);
+ }
+
+ return result;
+}
+
+/*
+ * We export this function for use by extensions that define extensible nodes.
+ * That's somewhat historical, though, because calling nodeRead() will work.
+ */
+Bitmapset *
+readBitmapset(void)
+{
+ return _readBitmapset();
+}
+
+#include "readfuncs.funcs.c"
+
+
+/*
+ * Support functions for nodes with custom_read_write attribute or
+ * special_read_write attribute
+ */
+
+static Const *
+_readConst(void)
+{
+ READ_LOCALS(Const);
+
+ READ_OID_FIELD(consttype);
+ READ_INT_FIELD(consttypmod);
+ READ_OID_FIELD(constcollid);
+ READ_INT_FIELD(constlen);
+ READ_BOOL_FIELD(constbyval);
+ READ_BOOL_FIELD(constisnull);
+ READ_LOCATION_FIELD(location);
+
+ token = pg_strtok(&length); /* skip :constvalue */
+ if (local_node->constisnull)
+ token = pg_strtok(&length); /* skip "<>" */
+ else
+ local_node->constvalue = readDatum(local_node->constbyval);
+
+ READ_DONE();
+}
+
+static BoolExpr *
+_readBoolExpr(void)
+{
+ READ_LOCALS(BoolExpr);
+
+ /* do-it-yourself enum representation */
+ token = pg_strtok(&length); /* skip :boolop */
+ token = pg_strtok(&length); /* get field value */
+ if (length == 3 && strncmp(token, "and", 3) == 0)
+ local_node->boolop = AND_EXPR;
+ else if (length == 2 && strncmp(token, "or", 2) == 0)
+ local_node->boolop = OR_EXPR;
+ else if (length == 3 && strncmp(token, "not", 3) == 0)
+ local_node->boolop = NOT_EXPR;
+ else
+ elog(ERROR, "unrecognized boolop \"%.*s\"", length, token);
+
+ READ_NODE_FIELD(args);
+ READ_LOCATION_FIELD(location);
+
+ READ_DONE();
+}
+
+static A_Const *
+_readA_Const(void)
+{
+ READ_LOCALS(A_Const);
+
+ /* We expect either NULL or :val here */
+ token = pg_strtok(&length);
+ if (length == 4 && strncmp(token, "NULL", 4) == 0)
+ local_node->isnull = true;
+ else
+ {
+ union ValUnion *tmp = nodeRead(NULL, 0);
+
+ /* To forestall valgrind complaints, copy only the valid data */
+ switch (nodeTag(tmp))
+ {
+ case T_Integer:
+ memcpy(&local_node->val, tmp, sizeof(Integer));
+ break;
+ case T_Float:
+ memcpy(&local_node->val, tmp, sizeof(Float));
+ break;
+ case T_Boolean:
+ memcpy(&local_node->val, tmp, sizeof(Boolean));
+ break;
+ case T_String:
+ memcpy(&local_node->val, tmp, sizeof(String));
+ break;
+ case T_BitString:
+ memcpy(&local_node->val, tmp, sizeof(BitString));
+ break;
+ default:
+ elog(ERROR, "unrecognized node type: %d",
+ (int) nodeTag(tmp));
+ break;
+ }
+ }
+
+ READ_LOCATION_FIELD(location);
+
+ READ_DONE();
+}
+
+/*
+ * _readConstraint
+ */
+static Constraint *
+_readConstraint(void)
+{
+ READ_LOCALS(Constraint);
+
+ READ_STRING_FIELD(conname);
+ READ_BOOL_FIELD(deferrable);
+ READ_BOOL_FIELD(initdeferred);
+ READ_LOCATION_FIELD(location);
+
+ token = pg_strtok(&length); /* skip :contype */
+ token = pg_strtok(&length); /* get field value */
+ if (length == 4 && strncmp(token, "NULL", 4) == 0)
+ local_node->contype = CONSTR_NULL;
+ else if (length == 8 && strncmp(token, "NOT_NULL", 8) == 0)
+ local_node->contype = CONSTR_NOTNULL;
+ else if (length == 7 && strncmp(token, "DEFAULT", 7) == 0)
+ local_node->contype = CONSTR_DEFAULT;
+ else if (length == 8 && strncmp(token, "IDENTITY", 8) == 0)
+ local_node->contype = CONSTR_IDENTITY;
+ else if (length == 9 && strncmp(token, "GENERATED", 9) == 0)
+ local_node->contype = CONSTR_GENERATED;
+ else if (length == 5 && strncmp(token, "CHECK", 5) == 0)
+ local_node->contype = CONSTR_CHECK;
+ else if (length == 11 && strncmp(token, "PRIMARY_KEY", 11) == 0)
+ local_node->contype = CONSTR_PRIMARY;
+ else if (length == 6 && strncmp(token, "UNIQUE", 6) == 0)
+ local_node->contype = CONSTR_UNIQUE;
+ else if (length == 9 && strncmp(token, "EXCLUSION", 9) == 0)
+ local_node->contype = CONSTR_EXCLUSION;
+ else if (length == 11 && strncmp(token, "FOREIGN_KEY", 11) == 0)
+ local_node->contype = CONSTR_FOREIGN;
+ else if (length == 15 && strncmp(token, "ATTR_DEFERRABLE", 15) == 0)
+ local_node->contype = CONSTR_ATTR_DEFERRABLE;
+ else if (length == 19 && strncmp(token, "ATTR_NOT_DEFERRABLE", 19) == 0)
+ local_node->contype = CONSTR_ATTR_NOT_DEFERRABLE;
+ else if (length == 13 && strncmp(token, "ATTR_DEFERRED", 13) == 0)
+ local_node->contype = CONSTR_ATTR_DEFERRED;
+ else if (length == 14 && strncmp(token, "ATTR_IMMEDIATE", 14) == 0)
+ local_node->contype = CONSTR_ATTR_IMMEDIATE;
+
+ switch (local_node->contype)
+ {
+ case CONSTR_NULL:
+ case CONSTR_NOTNULL:
+ /* no extra fields */
+ break;
+
+ case CONSTR_DEFAULT:
+ READ_NODE_FIELD(raw_expr);
+ READ_STRING_FIELD(cooked_expr);
+ break;
+
+ case CONSTR_IDENTITY:
+ READ_NODE_FIELD(options);
+ READ_CHAR_FIELD(generated_when);
+ break;
+
+ case CONSTR_GENERATED:
+ READ_NODE_FIELD(raw_expr);
+ READ_STRING_FIELD(cooked_expr);
+ READ_CHAR_FIELD(generated_when);
+ break;
+
+ case CONSTR_CHECK:
+ READ_BOOL_FIELD(is_no_inherit);
+ READ_NODE_FIELD(raw_expr);
+ READ_STRING_FIELD(cooked_expr);
+ READ_BOOL_FIELD(skip_validation);
+ READ_BOOL_FIELD(initially_valid);
+ break;
+
+ case CONSTR_PRIMARY:
+ READ_NODE_FIELD(keys);
+ READ_NODE_FIELD(including);
+ READ_NODE_FIELD(options);
+ READ_STRING_FIELD(indexname);
+ READ_STRING_FIELD(indexspace);
+ READ_BOOL_FIELD(reset_default_tblspc);
+ /* access_method and where_clause not currently used */
+ break;
+
+ case CONSTR_UNIQUE:
+ READ_BOOL_FIELD(nulls_not_distinct);
+ READ_NODE_FIELD(keys);
+ READ_NODE_FIELD(including);
+ READ_NODE_FIELD(options);
+ READ_STRING_FIELD(indexname);
+ READ_STRING_FIELD(indexspace);
+ READ_BOOL_FIELD(reset_default_tblspc);
+ /* access_method and where_clause not currently used */
+ break;
+
+ case CONSTR_EXCLUSION:
+ READ_NODE_FIELD(exclusions);
+ READ_NODE_FIELD(including);
+ READ_NODE_FIELD(options);
+ READ_STRING_FIELD(indexname);
+ READ_STRING_FIELD(indexspace);
+ READ_BOOL_FIELD(reset_default_tblspc);
+ READ_STRING_FIELD(access_method);
+ READ_NODE_FIELD(where_clause);
+ break;
+
+ case CONSTR_FOREIGN:
+ READ_NODE_FIELD(pktable);
+ READ_NODE_FIELD(fk_attrs);
+ READ_NODE_FIELD(pk_attrs);
+ READ_CHAR_FIELD(fk_matchtype);
+ READ_CHAR_FIELD(fk_upd_action);
+ READ_CHAR_FIELD(fk_del_action);
+ READ_NODE_FIELD(fk_del_set_cols);
+ READ_NODE_FIELD(old_conpfeqop);
+ READ_OID_FIELD(old_pktable_oid);
+ READ_BOOL_FIELD(skip_validation);
+ READ_BOOL_FIELD(initially_valid);
+ break;
+
+ case CONSTR_ATTR_DEFERRABLE:
+ case CONSTR_ATTR_NOT_DEFERRABLE:
+ case CONSTR_ATTR_DEFERRED:
+ case CONSTR_ATTR_IMMEDIATE:
+ /* no extra fields */
+ break;
+
+ default:
+ elog(ERROR, "unrecognized ConstrType: %d", (int) local_node->contype);
+ break;
+ }
+
+ READ_DONE();
+}
+
+static RangeTblEntry *
+_readRangeTblEntry(void)
+{
+ READ_LOCALS(RangeTblEntry);
+
+ /* put alias + eref first to make dump more legible */
+ READ_NODE_FIELD(alias);
+ READ_NODE_FIELD(eref);
+ READ_ENUM_FIELD(rtekind, RTEKind);
+
+ switch (local_node->rtekind)
+ {
+ case RTE_RELATION:
+ READ_OID_FIELD(relid);
+ READ_CHAR_FIELD(relkind);
+ READ_INT_FIELD(rellockmode);
+ READ_NODE_FIELD(tablesample);
+ READ_UINT_FIELD(perminfoindex);
+ break;
+ case RTE_SUBQUERY:
+ READ_NODE_FIELD(subquery);
+ READ_BOOL_FIELD(security_barrier);
+ /* we re-use these RELATION fields, too: */
+ READ_OID_FIELD(relid);
+ READ_CHAR_FIELD(relkind);
+ READ_INT_FIELD(rellockmode);
+ READ_UINT_FIELD(perminfoindex);
+ break;
+ case RTE_JOIN:
+ READ_ENUM_FIELD(jointype, JoinType);
+ READ_INT_FIELD(joinmergedcols);
+ READ_NODE_FIELD(joinaliasvars);
+ READ_NODE_FIELD(joinleftcols);
+ READ_NODE_FIELD(joinrightcols);
+ READ_NODE_FIELD(join_using_alias);
+ break;
+ case RTE_FUNCTION:
+ READ_NODE_FIELD(functions);
+ READ_BOOL_FIELD(funcordinality);
+ break;
+ case RTE_TABLEFUNC:
+ READ_NODE_FIELD(tablefunc);
+ /* The RTE must have a copy of the column type info, if any */
+ if (local_node->tablefunc)
+ {
+ TableFunc *tf = local_node->tablefunc;
+
+ local_node->coltypes = tf->coltypes;
+ local_node->coltypmods = tf->coltypmods;
+ local_node->colcollations = tf->colcollations;
+ }
+ break;
+ case RTE_VALUES:
+ READ_NODE_FIELD(values_lists);
+ READ_NODE_FIELD(coltypes);
+ READ_NODE_FIELD(coltypmods);
+ READ_NODE_FIELD(colcollations);
+ break;
+ case RTE_CTE:
+ READ_STRING_FIELD(ctename);
+ READ_UINT_FIELD(ctelevelsup);
+ READ_BOOL_FIELD(self_reference);
+ READ_NODE_FIELD(coltypes);
+ READ_NODE_FIELD(coltypmods);
+ READ_NODE_FIELD(colcollations);
+ break;
+ case RTE_NAMEDTUPLESTORE:
+ READ_STRING_FIELD(enrname);
+ READ_FLOAT_FIELD(enrtuples);
+ READ_NODE_FIELD(coltypes);
+ READ_NODE_FIELD(coltypmods);
+ READ_NODE_FIELD(colcollations);
+ /* we re-use these RELATION fields, too: */
+ READ_OID_FIELD(relid);
+ break;
+ case RTE_RESULT:
+ /* no extra fields */
+ break;
+ default:
+ elog(ERROR, "unrecognized RTE kind: %d",
+ (int) local_node->rtekind);
+ break;
+ }
+
+ READ_BOOL_FIELD(lateral);
+ READ_BOOL_FIELD(inh);
+ READ_BOOL_FIELD(inFromCl);
+ READ_NODE_FIELD(securityQuals);
+
+ READ_DONE();
+}
+
+static A_Expr *
+_readA_Expr(void)
+{
+ READ_LOCALS(A_Expr);
+
+ token = pg_strtok(&length);
+
+ if (length == 3 && strncmp(token, "ANY", 3) == 0)
+ {
+ local_node->kind = AEXPR_OP_ANY;
+ READ_NODE_FIELD(name);
+ }
+ else if (length == 3 && strncmp(token, "ALL", 3) == 0)
+ {
+ local_node->kind = AEXPR_OP_ALL;
+ READ_NODE_FIELD(name);
+ }
+ else if (length == 8 && strncmp(token, "DISTINCT", 8) == 0)
+ {
+ local_node->kind = AEXPR_DISTINCT;
+ READ_NODE_FIELD(name);
+ }
+ else if (length == 12 && strncmp(token, "NOT_DISTINCT", 12) == 0)
+ {
+ local_node->kind = AEXPR_NOT_DISTINCT;
+ READ_NODE_FIELD(name);
+ }
+ else if (length == 6 && strncmp(token, "NULLIF", 6) == 0)
+ {
+ local_node->kind = AEXPR_NULLIF;
+ READ_NODE_FIELD(name);
+ }
+ else if (length == 2 && strncmp(token, "IN", 2) == 0)
+ {
+ local_node->kind = AEXPR_IN;
+ READ_NODE_FIELD(name);
+ }
+ else if (length == 4 && strncmp(token, "LIKE", 4) == 0)
+ {
+ local_node->kind = AEXPR_LIKE;
+ READ_NODE_FIELD(name);
+ }
+ else if (length == 5 && strncmp(token, "ILIKE", 5) == 0)
+ {
+ local_node->kind = AEXPR_ILIKE;
+ READ_NODE_FIELD(name);
+ }
+ else if (length == 7 && strncmp(token, "SIMILAR", 7) == 0)
+ {
+ local_node->kind = AEXPR_SIMILAR;
+ READ_NODE_FIELD(name);
+ }
+ else if (length == 7 && strncmp(token, "BETWEEN", 7) == 0)
+ {
+ local_node->kind = AEXPR_BETWEEN;
+ READ_NODE_FIELD(name);
+ }
+ else if (length == 11 && strncmp(token, "NOT_BETWEEN", 11) == 0)
+ {
+ local_node->kind = AEXPR_NOT_BETWEEN;
+ READ_NODE_FIELD(name);
+ }
+ else if (length == 11 && strncmp(token, "BETWEEN_SYM", 11) == 0)
+ {
+ local_node->kind = AEXPR_BETWEEN_SYM;
+ READ_NODE_FIELD(name);
+ }
+ else if (length == 15 && strncmp(token, "NOT_BETWEEN_SYM", 15) == 0)
+ {
+ local_node->kind = AEXPR_NOT_BETWEEN_SYM;
+ READ_NODE_FIELD(name);
+ }
+ else if (length == 5 && strncmp(token, ":name", 5) == 0)
+ {
+ local_node->kind = AEXPR_OP;
+ local_node->name = nodeRead(NULL, 0);
+ }
+ else
+ elog(ERROR, "unrecognized A_Expr kind: \"%.*s\"", length, token);
+
+ READ_NODE_FIELD(lexpr);
+ READ_NODE_FIELD(rexpr);
+ READ_LOCATION_FIELD(location);
+
+ READ_DONE();
+}
+
+static ExtensibleNode *
+_readExtensibleNode(void)
+{
+ const ExtensibleNodeMethods *methods;
+ ExtensibleNode *local_node;
+ const char *extnodename;
+
+ READ_TEMP_LOCALS();
+
+ token = pg_strtok(&length); /* skip :extnodename */
+ token = pg_strtok(&length); /* get extnodename */
+
+ extnodename = nullable_string(token, length);
+ if (!extnodename)
+ elog(ERROR, "extnodename has to be supplied");
+ methods = GetExtensibleNodeMethods(extnodename, false);
+
+ local_node = (ExtensibleNode *) newNode(methods->node_size,
+ T_ExtensibleNode);
+ local_node->extnodename = extnodename;
+
+ /* deserialize the private fields */
+ methods->nodeRead(local_node);
+
+ READ_DONE();
+}
+
+
+/*
+ * parseNodeString
+ *
+ * Given a character string representing a node tree, parseNodeString creates
+ * the internal node structure.
+ *
+ * The string to be read must already have been loaded into pg_strtok().
+ */
+Node *
+parseNodeString(void)
+{
+ READ_TEMP_LOCALS();
+
+ /* Guard against stack overflow due to overly complex expressions */
+ check_stack_depth();
+
+ token = pg_strtok(&length);
+
+#define MATCH(tokname, namelen) \
+ (length == namelen && memcmp(token, tokname, namelen) == 0)
+
+#include "readfuncs.switch.c"
+
+ elog(ERROR, "badly formatted node string \"%.32s\"...", token);
+ return NULL; /* keep compiler quiet */
+}
+
+
+/*
+ * readDatum
+ *
+ * Given a string representation of a constant, recreate the appropriate
+ * Datum. The string representation embeds length info, but not byValue,
+ * so we must be told that.
+ */
+Datum
+readDatum(bool typbyval)
+{
+ Size length,
+ i;
+ int tokenLength;
+ const char *token;
+ Datum res;
+ char *s;
+
+ /*
+ * read the actual length of the value
+ */
+ token = pg_strtok(&tokenLength);
+ length = atoui(token);
+
+ token = pg_strtok(&tokenLength); /* read the '[' */
+ if (token == NULL || token[0] != '[')
+ elog(ERROR, "expected \"[\" to start datum, but got \"%s\"; length = %zu",
+ token ? token : "[NULL]", length);
+
+ if (typbyval)
+ {
+ if (length > (Size) sizeof(Datum))
+ elog(ERROR, "byval datum but length = %zu", length);
+ res = (Datum) 0;
+ s = (char *) (&res);
+ for (i = 0; i < (Size) sizeof(Datum); i++)
+ {
+ token = pg_strtok(&tokenLength);
+ s[i] = (char) atoi(token);
+ }
+ }
+ else if (length <= 0)
+ res = (Datum) NULL;
+ else
+ {
+ s = (char *) palloc(length);
+ for (i = 0; i < length; i++)
+ {
+ token = pg_strtok(&tokenLength);
+ s[i] = (char) atoi(token);
+ }
+ res = PointerGetDatum(s);
+ }
+
+ token = pg_strtok(&tokenLength); /* read the ']' */
+ if (token == NULL || token[0] != ']')
+ elog(ERROR, "expected \"]\" to end datum, but got \"%s\"; length = %zu",
+ token ? token : "[NULL]", length);
+
+ return res;
+}
+
+/*
+ * common implementation for scalar-array-reading functions
+ *
+ * The data format is either "<>" for a NULL pointer (in which case numCols
+ * is ignored) or "(item item item)" where the number of items must equal
+ * numCols. The convfunc must be okay with stopping at whitespace or a
+ * right parenthesis, since pg_strtok won't null-terminate the token.
+ */
+#define READ_SCALAR_ARRAY(fnname, datatype, convfunc) \
+datatype * \
+fnname(int numCols) \
+{ \
+ datatype *vals; \
+ READ_TEMP_LOCALS(); \
+ token = pg_strtok(&length); \
+ if (token == NULL) \
+ elog(ERROR, "incomplete scalar array"); \
+ if (length == 0) \
+ return NULL; /* it was "<>", so return NULL pointer */ \
+ if (length != 1 || token[0] != '(') \
+ elog(ERROR, "unrecognized token: \"%.*s\"", length, token); \
+ vals = (datatype *) palloc(numCols * sizeof(datatype)); \
+ for (int i = 0; i < numCols; i++) \
+ { \
+ token = pg_strtok(&length); \
+ if (token == NULL || token[0] == ')') \
+ elog(ERROR, "incomplete scalar array"); \
+ vals[i] = convfunc(token); \
+ } \
+ token = pg_strtok(&length); \
+ if (token == NULL || length != 1 || token[0] != ')') \
+ elog(ERROR, "incomplete scalar array"); \
+ return vals; \
+}
+
+/*
+ * Note: these functions are exported in nodes.h for possible use by
+ * extensions, so don't mess too much with their names or API.
+ */
+READ_SCALAR_ARRAY(readAttrNumberCols, int16, atoi)
+READ_SCALAR_ARRAY(readOidCols, Oid, atooid)
+/* outfuncs.c has writeIndexCols, but we don't yet need that here */
+/* READ_SCALAR_ARRAY(readIndexCols, Index, atoui) */
+READ_SCALAR_ARRAY(readIntCols, int, atoi)
+READ_SCALAR_ARRAY(readBoolCols, bool, strtobool)