mirror of https://github.com/citusdata/citus.git
384 lines
9.8 KiB
C
384 lines
9.8 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* 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 <math.h>
|
|
|
|
#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
|