diff options
author | vvvv <vvvv@yandex-team.com> | 2024-11-07 12:29:36 +0300 |
---|---|---|
committer | vvvv <vvvv@yandex-team.com> | 2024-11-07 13:49:47 +0300 |
commit | d4c258e9431675bab6745c8638df6e3dfd4dca6b (patch) | |
tree | b5efcfa11351152a4c872fccaea35749141c0b11 /yql/essentials/parser/pg_wrapper/postgresql/src/backend/nodes/readfuncs.c | |
parent | 13a4f274caef5cfdaf0263b24e4d6bdd5521472b (diff) | |
download | ydb-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.c | 822 |
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) |