/*------------------------------------------------------------------------- * * citus_readfuncs.c * Citus specific node functions * * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 2012-2015, Citus Data, Inc. * *------------------------------------------------------------------------- */ #include "postgres.h" #include #include "distributed/citus_nodefuncs.h" #include "nodes/parsenodes.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 */ #if (PG_VERSION_NUM >= 90600) static inline Node * CitusSetTag(Node *node, int tag) { CitusNode *citus_node = (CitusNode *) node; citus_node->citus_tag = tag; return node; } /* *INDENT-OFF* */ #define READ_LOCALS_NO_FIELDS(nodeTypeName) \ nodeTypeName *local_node = (nodeTypeName *) CitusSetTag((Node *) node, T_##nodeTypeName) #else #define READ_LOCALS_NO_FIELDS(nodeTypeName) \ nodeTypeName *local_node = CitusMakeNode(nodeTypeName) #endif /* And a few guys need only the citus_pg_strtok support fields */ #define READ_TEMP_LOCALS() \ 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 = citus_pg_strtok(&length); /* skip :fldname */ \ token = citus_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 = citus_pg_strtok(&length); /* skip :fldname */ \ token = citus_pg_strtok(&length); /* get field value */ \ local_node->fldname = atoui(token) /* XXX: CITUS Read an uint64 field (anything written as ":fldname %u") */ #define READ_UINT64_FIELD(fldname) \ token = citus_pg_strtok(&length); /* skip :fldname */ \ token = citus_pg_strtok(&length); /* get field value */ \ local_node->fldname = atoull(token) /* Read an OID field (don't hard-wire assumption that OID is same as uint) */ #define READ_OID_FIELD(fldname) \ token = citus_pg_strtok(&length); /* skip :fldname */ \ token = citus_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 = citus_pg_strtok(&length); /* skip :fldname */ \ token = citus_pg_strtok(&length); /* get field value */ \ local_node->fldname = token[0] /* Read an enumerated-type field that was written as an integer code */ #define READ_ENUM_FIELD(fldname, enumtype) \ token = citus_pg_strtok(&length); /* skip :fldname */ \ token = citus_pg_strtok(&length); /* get field value */ \ local_node->fldname = (enumtype) atoi(token) /* Read a float field */ #define READ_FLOAT_FIELD(fldname) \ token = citus_pg_strtok(&length); /* skip :fldname */ \ token = citus_pg_strtok(&length); /* get field value */ \ local_node->fldname = atof(token) /* Read a boolean field */ #define READ_BOOL_FIELD(fldname) \ token = citus_pg_strtok(&length); /* skip :fldname */ \ token = citus_pg_strtok(&length); /* get field value */ \ local_node->fldname = strtobool(token) /* Read a character-string field */ #define READ_STRING_FIELD(fldname) \ token = citus_pg_strtok(&length); /* skip :fldname */ \ token = citus_pg_strtok(&length); /* get field value */ \ local_node->fldname = nullable_string(token, length) /* Read a parse location field (and throw away the value, per notes above) */ #define READ_LOCATION_FIELD(fldname) \ token = citus_pg_strtok(&length); /* skip :fldname */ \ token = citus_pg_strtok(&length); /* get field value */ \ (void) token; /* in case not used elsewhere */ \ local_node->fldname = -1 /* set field to "unknown" */ /* Read a Node field XXX: Citus: replaced call to nodeRead with CitusNodeRead */ #define READ_NODE_FIELD(fldname) \ token = citus_pg_strtok(&length); /* skip :fldname */ \ (void) token; /* in case not used elsewhere */ \ local_node->fldname = CitusNodeRead(NULL, 0) /* Routine exit */ #if (PG_VERSION_NUM >= 90600) #define READ_DONE() \ return; #else #define READ_DONE() \ return (Node *) local_node #endif /* * 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 atooid(x) ((Oid) strtoul((x), NULL, 10)) /* XXX: Citus */ #define atoull(x) ((uint64) strtoull((x), NULL, 10)) #define strtobool(x) ((*(x) == 't') ? true : false) #define nullable_string(token,length) \ ((length) == 0 ? NULL : debackslash(token, length)) static void readJobInfo(Job *local_node) { READ_TEMP_LOCALS(); READ_UINT64_FIELD(jobId); READ_NODE_FIELD(jobQuery); READ_NODE_FIELD(taskList); READ_NODE_FIELD(dependedJobList); READ_BOOL_FIELD(subqueryPushdown); READ_BOOL_FIELD(requiresMasterEvaluation); } READFUNC_RET ReadJob(READFUNC_ARGS) { READ_LOCALS_NO_FIELDS(Job); readJobInfo(local_node); READ_DONE(); } READFUNC_RET ReadMultiPlan(READFUNC_ARGS) { READ_LOCALS(MultiPlan); READ_NODE_FIELD(workerJob); READ_NODE_FIELD(masterQuery); READ_STRING_FIELD(masterTableName); READ_DONE(); } READFUNC_RET ReadShardInterval(READFUNC_ARGS) { READ_LOCALS(ShardInterval); READ_OID_FIELD(relationId); READ_CHAR_FIELD(storageType); READ_OID_FIELD(valueTypeId); READ_INT_FIELD(valueTypeLen); READ_BOOL_FIELD(valueByVal); READ_BOOL_FIELD(minValueExists); READ_BOOL_FIELD(maxValueExists); token = citus_pg_strtok(&length); /* skip :minValue */ if (!local_node->minValueExists) token = citus_pg_strtok(&length); /* skip "<>" */ else local_node->minValue = readDatum(local_node->valueByVal); token = citus_pg_strtok(&length); /* skip :maxValue */ if (!local_node->minValueExists) token = citus_pg_strtok(&length); /* skip "<>" */ else local_node->maxValue = readDatum(local_node->valueByVal); READ_UINT64_FIELD(shardId); READ_DONE(); } READFUNC_RET ReadMapMergeJob(READFUNC_ARGS) { int arrayLength; int i; READ_LOCALS(MapMergeJob); readJobInfo(&local_node->job); READ_NODE_FIELD(reduceQuery); READ_ENUM_FIELD(partitionType, PartitionType); READ_NODE_FIELD(partitionColumn); READ_UINT_FIELD(partitionCount); READ_INT_FIELD(sortedShardIntervalArrayLength); arrayLength = local_node->sortedShardIntervalArrayLength; /* now build & read sortedShardIntervalArray */ local_node->sortedShardIntervalArray = (ShardInterval**) palloc(arrayLength * sizeof(ShardInterval *)); for (i = 0; i < arrayLength; ++i) { /* can't use READ_NODE_FIELD, no field names */ local_node->sortedShardIntervalArray[i] = CitusNodeRead(NULL, 0); } READ_NODE_FIELD(mapTaskList); READ_NODE_FIELD(mergeTaskList); READ_DONE(); } READFUNC_RET ReadShardPlacement(READFUNC_ARGS) { READ_LOCALS(ShardPlacement); READ_OID_FIELD(placementId); READ_UINT64_FIELD(shardId); READ_UINT64_FIELD(shardLength); READ_ENUM_FIELD(shardState, RelayFileState); READ_STRING_FIELD(nodeName); READ_UINT_FIELD(nodePort); READ_DONE(); } READFUNC_RET ReadTask(READFUNC_ARGS) { READ_LOCALS(Task); READ_ENUM_FIELD(taskType, TaskType); READ_UINT64_FIELD(jobId); READ_UINT_FIELD(taskId); READ_STRING_FIELD(queryString); READ_UINT64_FIELD(anchorShardId); READ_NODE_FIELD(taskPlacementList); READ_NODE_FIELD(dependedTaskList); READ_UINT_FIELD(partitionId); READ_UINT_FIELD(upstreamTaskId); READ_NODE_FIELD(shardInterval); READ_BOOL_FIELD(assignmentConstrained); READ_NODE_FIELD(taskExecution); READ_BOOL_FIELD(upsertQuery); READ_DONE(); } READFUNC_RET ReadUnsupportedCitusNode(READFUNC_ARGS) { ereport(ERROR, (errmsg("not implemented"))); } #if (PG_VERSION_NUM < 90600) /* * 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; char *token; Datum res; char *s; /* * read the actual length of the value */ token = citus_pg_strtok(&tokenLength); length = atoui(token); token = citus_pg_strtok(&tokenLength); /* read the '[' */ if (token == NULL || token[0] != '[') elog(ERROR, "expected \"[\" to start datum, but got \"%s\"; length = %zu", token ? (const char *) 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 = citus_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 = citus_pg_strtok(&tokenLength); s[i] = (char) atoi(token); } res = PointerGetDatum(s); } token = citus_pg_strtok(&tokenLength); /* read the ']' */ if (token == NULL || token[0] != ']') elog(ERROR, "expected \"]\" to end datum, but got \"%s\"; length = %zu", token ? (const char *) token : "[NULL]", length); return res; } #endif #if (PG_VERSION_NUM >= 90600) /* *INDENT-ON* */ /* * For 9.6+ we can just use the, now extensible, parseNodeString(). Before * that citus_readfuncs_$ver.c has a version specific implementation. */ Node * CitusParseNodeString(void) { return parseNodeString(); } #endif