summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael P2011-02-02 08:12:58 +0000
committerPavan Deolasee2011-05-19 17:49:37 +0000
commite08eb37ced7b0d4416a9812432ed365f54aa5a08 (patch)
treed4a8cf5552724243b91d4c0b543a3f79ed0eddb2
parent2e81ffec5df4a2a6c1a21973d81d84d7f5b5d6fc (diff)
CREATE TABLE: new distribution function MODULO
new catalogue is named pgxc_class. It has the following columns pcrelid - The OID of the added relation in pg_class pclocatortype - XC defines distribution types as a single character in locator.h The provided distribution type is stored here. Distribution types can be 'R' - Replicated 'H' - Based on a column's hash value 'N' - Based on round robin for all data nodes 'M' - Based on modulo of a column's value This new distribution type is added by this patch. Similarly G, S and C are also defined. pcattnum - The number of the column used for replication valid only for H and M - Zero for the rest This patch supports also copy and INSERT(SELECT). It does NOT SUPPPORT multiple INSERT. The following issues are remaining though: 1) Non-definition of distribution column in table makes a crash 2) Creation of an index on a column that is not the distribution column 3) Creation of a foreign key on distribution column 4) Distribution on another column other than unique makes a crash
-rw-r--r--src/backend/catalog/heap.c36
-rw-r--r--src/backend/catalog/pgxc_class.c2
-rw-r--r--src/backend/commands/copy.c34
-rw-r--r--src/backend/commands/indexcmds.c2
-rw-r--r--src/backend/parser/gram.y20
-rw-r--r--src/backend/parser/parse_utilcmd.c13
-rw-r--r--src/backend/pgxc/locator/locator.c148
-rw-r--r--src/backend/pgxc/plan/planner.c39
-rw-r--r--src/include/nodes/primnodes.h3
-rw-r--r--src/include/parser/kwlist.h3
-rw-r--r--src/include/pgxc/locator.h8
11 files changed, 255 insertions, 53 deletions
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index a92e73a2b3..ec8d2517c9 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -828,6 +828,7 @@ AddRelationDistribution (Oid relid,
switch (locatortype)
{
case LOCATOR_TYPE_HASH:
+ case LOCATOR_TYPE_MODULO:
attnum = rel_loc_info->partAttrNum;
break;
@@ -895,6 +896,26 @@ AddRelationDistribution (Oid relid,
locatortype = LOCATOR_TYPE_HASH;
break;
+ case DISTTYPE_MODULO:
+ /* User specified modulo column, validate */
+ attnum = get_attnum(relid, distributeby->colname);
+ if (!attnum)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
+ errmsg("Invalid distribution column specified")));
+ }
+
+ if (!IsModuloDistributable(descriptor->attrs[attnum-1]->atttypid))
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("Column %s is not modulo distributable data type",
+ distributeby->colname)));
+ }
+ locatortype = LOCATOR_TYPE_MODULO;
+ break;
+
case DISTTYPE_REPLICATION:
locatortype = LOCATOR_TYPE_REPLICATED;
break;
@@ -910,12 +931,17 @@ AddRelationDistribution (Oid relid,
}
}
- if (locatortype == LOCATOR_TYPE_HASH)
+ switch (locatortype)
{
- /* PGXCTODO */
- /* Use these for now until we make allowing different algorithms more flexible */
- hashalgorithm = 1;
- hashbuckets = HASH_SIZE;
+ case LOCATOR_TYPE_HASH:
+ /* PGXCTODO */
+ /* Use these for now until we make allowing different algorithms more flexible */
+ hashalgorithm = 1;
+ hashbuckets = HASH_SIZE;
+ break;
+
+ case LOCATOR_TYPE_MODULO:
+ break;
}
PgxcClassCreate (relid, locatortype, attnum, hashalgorithm, hashbuckets);
diff --git a/src/backend/catalog/pgxc_class.c b/src/backend/catalog/pgxc_class.c
index 6b897c8311..08462c2619 100644
--- a/src/backend/catalog/pgxc_class.c
+++ b/src/backend/catalog/pgxc_class.c
@@ -51,7 +51,7 @@ PgxcClassCreate(Oid pcrelid,
values[Anum_pgxc_class_pcrelid - 1] = ObjectIdGetDatum(pcrelid);
values[Anum_pgxc_class_pclocatortype - 1] = ObjectIdGetDatum(pclocatortype);
- if (pclocatortype == LOCATOR_TYPE_HASH)
+ if (pclocatortype == LOCATOR_TYPE_HASH || pclocatortype == LOCATOR_TYPE_MODULO)
{
values[Anum_pgxc_class_pcattnum - 1] = ObjectIdGetDatum(pcattnum);
values[Anum_pgxc_class_pchashalgorithm - 1] = ObjectIdGetDatum(pchashalgorithm);
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index b4f19bda29..061d05ed55 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -181,7 +181,7 @@ typedef struct CopyStateData
/* Locator information */
RelationLocInfo *rel_loc; /* the locator key */
- int hash_idx; /* index of the hash column */
+ int idx_dist_by_col; /* index of the distributed by column */
PGXCNodeHandle **connections; /* Involved data node connections */
TupleDesc tupDesc; /* for INSERT SELECT */
@@ -2312,14 +2312,14 @@ CopyFrom(CopyState cstate)
#ifdef PGXC
if (IS_PGXC_COORDINATOR && cstate->rel_loc)
{
- Datum *hash_value = NULL;
+ Datum *dist_col_value = NULL;
- if (cstate->hash_idx >= 0 && !nulls[cstate->hash_idx])
- hash_value = &values[cstate->hash_idx];
+ if (cstate->idx_dist_by_col >= 0 && !nulls[cstate->idx_dist_by_col])
+ dist_col_value = &values[cstate->idx_dist_by_col];
if (DataNodeCopyIn(cstate->line_buf.data,
cstate->line_buf.len,
- GetRelationNodes(cstate->rel_loc, (long *)hash_value,
+ GetRelationNodes(cstate->rel_loc, (long *)dist_col_value,
RELATION_ACCESS_INSERT),
cstate->connections))
ereport(ERROR,
@@ -3737,7 +3737,7 @@ static ExecNodes*
build_copy_statement(CopyState cstate, List *attnamelist,
TupleDesc tupDesc, bool is_from, List *force_quote, List *force_notnull)
{
- char *hash_att;
+ char *pPartByCol;
ExecNodes *exec_nodes = makeNode(ExecNodes);
@@ -3749,10 +3749,10 @@ build_copy_statement(CopyState cstate, List *attnamelist,
*/
cstate->rel_loc = GetRelationLocInfo(RelationGetRelid(cstate->rel));
- hash_att = GetRelationHashColumn(cstate->rel_loc);
+ pPartByCol = GetRelationDistColumn(cstate->rel_loc);
if (cstate->rel_loc)
{
- if (is_from || hash_att)
+ if (is_from || pPartByCol)
exec_nodes->nodelist = list_copy(cstate->rel_loc->nodeList);
else
{
@@ -3764,8 +3764,8 @@ build_copy_statement(CopyState cstate, List *attnamelist,
}
}
- cstate->hash_idx = -1;
- if (hash_att)
+ cstate->idx_dist_by_col = -1;
+ if (pPartByCol)
{
List *attnums;
ListCell *cur;
@@ -3774,9 +3774,9 @@ build_copy_statement(CopyState cstate, List *attnamelist,
foreach(cur, attnums)
{
int attnum = lfirst_int(cur);
- if (namestrcmp(&(tupDesc->attrs[attnum - 1]->attname), hash_att) == 0)
+ if (namestrcmp(&(tupDesc->attrs[attnum - 1]->attname), pPartByCol) == 0)
{
- cstate->hash_idx = attnum - 1;
+ cstate->idx_dist_by_col = attnum - 1;
break;
}
}
@@ -3903,7 +3903,7 @@ DoInsertSelectCopy(EState *estate, TupleTableSlot *slot)
HeapTuple tuple;
Datum *values;
bool *nulls;
- Datum *hash_value = NULL;
+ Datum *dist_col_value = NULL;
MemoryContext oldcontext;
CopyState cstate;
@@ -4016,14 +4016,14 @@ DoInsertSelectCopy(EState *estate, TupleTableSlot *slot)
/* Format the input tuple for sending */
CopyOneRowTo(cstate, 0, values, nulls);
- /* Get hash partition column, if any */
- if (cstate->hash_idx >= 0 && !nulls[cstate->hash_idx])
- hash_value = &values[cstate->hash_idx];
+ /* Get dist column, if any */
+ if (cstate->idx_dist_by_col >= 0 && !nulls[cstate->idx_dist_by_col])
+ dist_col_value = &values[cstate->idx_dist_by_col];
/* Send item to the appropriate data node(s) (buffer) */
if (DataNodeCopyIn(cstate->fe_msgbuf->data,
cstate->fe_msgbuf->len,
- GetRelationNodes(cstate->rel_loc, (long *)hash_value, RELATION_ACCESS_INSERT),
+ GetRelationNodes(cstate->rel_loc, (long *)dist_col_value, RELATION_ACCESS_INSERT),
cstate->connections))
ereport(ERROR,
(errcode(ERRCODE_CONNECTION_EXCEPTION),
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 0f1a2e5b63..c25a944f79 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -430,7 +430,7 @@ DefineIndex(RangeVar *heapRelation,
if (!isSafe)
ereport(ERROR,
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
- errmsg("Unique index of partitioned table must contain the hash distribution column.")));
+ errmsg("Unique index of partitioned table must contain the hash/modulo distribution column.")));
}
#endif
/*
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 11bc8e2643..a4ccc03d3a 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -436,7 +436,7 @@ static TypeName *TableFuncTypeName(List *columns);
*/
/* ordinary key words in alphabetical order */
-/* PGXC - added REPLICATION, DISTRIBUTE, and HASH */
+/* PGXC - added REPLICATION, DISTRIBUTE, MODULO and HASH */
%token <keyword> ABORT_P ABSOLUTE_P ACCESS ACTION ADD_P ADMIN AFTER
AGGREGATE ALL ALSO ALTER ALWAYS ANALYSE ANALYZE AND ANY ARRAY AS ASC
ASSERTION ASSIGNMENT ASYMMETRIC AT AUTHORIZATION
@@ -484,9 +484,9 @@ static TypeName *TableFuncTypeName(List *columns);
LANCOMPILER LANGUAGE LARGE_P LAST_P LC_COLLATE_P LC_CTYPE_P LEADING
LEAST LEFT LEVEL LIKE LIMIT LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP
LOCATION LOCK_P LOGIN_P
-
- MAPPING MATCH MAXVALUE MINUTE_P MINVALUE MODE MONTH_P MOVE
-
+/* PGXC_BEGIN */
+ MAPPING MATCH MAXVALUE MINUTE_P MINVALUE MODE MODULO MONTH_P MOVE
+/* PGXC_END */
NAME_P NAMES NATIONAL NATURAL NCHAR NEW NEXT NO NOCREATEDB
NOCREATEROLE NOCREATEUSER NODE NOINHERIT NOLOGIN_P NONE NOSUPERUSER
NOT NOTHING NOTIFY NOTNULL NOWAIT NULL_P NULLIF NULLS_P NUMERIC
@@ -2550,6 +2550,13 @@ OptDistributeBy: DistributeByHash '(' name ')'
n->colname = $3;
$$ = n;
}
+ | DISTRIBUTE BY MODULO '(' name ')'
+ {
+ DistributeBy *n = makeNode(DistributeBy);
+ n->disttype = DISTTYPE_MODULO;
+ n->colname = $5;
+ $$ = n;
+ }
| DISTRIBUTE BY REPLICATION
{
DistributeBy *n = makeNode(DistributeBy);
@@ -10282,7 +10289,7 @@ ColLabel: IDENT { $$ = $1; }
/* "Unreserved" keywords --- available for use as any kind of name.
*/
-/* PGXC - added DISTRIBUTE, HASH, REPLICATION */
+/* PGXC - added DISTRIBUTE, HASH, REPLICATION, MODULO */
unreserved_keyword:
ABORT_P
| ABSOLUTE_P
@@ -10419,6 +10426,9 @@ unreserved_keyword:
| MINUTE_P
| MINVALUE
| MODE
+/* PGXC_BEGIN */
+ | MODULO
+/* PGXC_END */
| MONTH_P
| MOVE
| NAME_P
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 10e0584852..23e057b0a8 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -2266,7 +2266,7 @@ CheckLocalIndexColumn (char loctype, char *partcolname, char *indexcolname)
ereport(ERROR,
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
errmsg("Cannot locally enforce a unique index on round robin distributed table.")));
- else if (loctype == LOCATOR_TYPE_HASH)
+ else if (loctype == LOCATOR_TYPE_HASH || loctype == LOCATOR_TYPE_MODULO)
{
if (partcolname && indexcolname && strcmp(partcolname, indexcolname) == 0)
return true;
@@ -2307,12 +2307,13 @@ static checkLocalFKConstraints(CreateStmtContext *cxt)
}
/*
- * See if we are hash partitioned and the column appears in the
+ * See if we are hash or modulo partitioned and the column appears in the
* constraint, and it corresponds to the position in the referenced table.
*/
if (cxt->isalter)
{
- if (cxt->rel->rd_locator_info->locatorType == LOCATOR_TYPE_HASH)
+ if (cxt->rel->rd_locator_info->locatorType == LOCATOR_TYPE_HASH ||
+ cxt->rel->rd_locator_info->locatorType == LOCATOR_TYPE_MODULO)
{
checkcolname = cxt->rel->rd_locator_info->partAttrName;
}
@@ -2352,13 +2353,13 @@ static checkLocalFKConstraints(CreateStmtContext *cxt)
if (pos >= list_length(fkconstraint->fk_attrs))
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("Hash distributed table must include distribution column in index")));
+ errmsg("Hash/Modulo distributed table must include distribution column in index")));
/* Verify that the referenced table is partitioned at the same position in the index */
- if (!IsHashColumnForRelId(pk_rel_id, strVal(list_nth(fkconstraint->pk_attrs,pos))))
+ if (!IsDistColumnForRelId(pk_rel_id, strVal(list_nth(fkconstraint->pk_attrs,pos))))
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("Hash distribution column does not refer to hash distribution column in referenced table.")));
+ errmsg("Hash/Modulo distribution column does not refer to hash/modulo distribution column in referenced table.")));
}
}
}
diff --git a/src/backend/pgxc/locator/locator.c b/src/backend/pgxc/locator/locator.c
index 199293fe41..d1aef8b348 100644
--- a/src/backend/pgxc/locator/locator.c
+++ b/src/backend/pgxc/locator/locator.c
@@ -158,6 +158,46 @@ get_node_from_hash(int hash)
return mappingTable[hash];
}
+/*
+ * compute_modulo
+ */
+static int
+compute_modulo(int valueOfPartCol)
+{
+ return ((abs(valueOfPartCol)) % NumDataNodes)+1;
+}
+
+/*
+ * get_node_from_modulo - determine node based on modulo
+ *
+ */
+static int
+get_node_from_modulo(int modulo)
+{
+ if (modulo > NumDataNodes || modulo <= 0)
+ ereport(ERROR, (errmsg("Modulo value out of range\n")));
+
+ return modulo;
+}
+
+/*
+ * GetRelationDistColumn - Returns the name of the hash or modulo distribution column
+ * First hash distribution is checked
+ * Retuens NULL if the table is neither hash nor modulo distributed
+ */
+char *
+GetRelationDistColumn(RelationLocInfo * rel_loc_info)
+{
+char *pColName;
+
+ pColName = NULL;
+
+ pColName = GetRelationHashColumn(rel_loc_info);
+ if (pColName == NULL)
+ pColName = GetRelationModuloColumn(rel_loc_info);
+
+ return pColName;
+}
/*
* Returns whether or not the data type is hash distributable with PG-XC
@@ -172,9 +212,8 @@ IsHashDistributable(Oid col_type)
return false;
}
-
/*
- * get_hash_column - return hash column for relation.
+ * GetRelationHashColumn - return hash column for relation.
*
* Returns NULL if the relation is not hash partitioned.
*/
@@ -230,6 +269,95 @@ IsHashColumnForRelId(Oid relid, char *part_col_name)
return IsHashColumn(rel_loc_info, part_col_name);
}
+/*
+ * IsDistColumnForRelId - return whether or not column for relation is used for hash or modulo distribution
+ *
+ */
+bool
+IsDistColumnForRelId(Oid relid, char *part_col_name)
+{
+bool bRet;
+RelationLocInfo *rel_loc_info;
+
+ rel_loc_info = GetRelationLocInfo(relid);
+ bRet = false;
+
+ bRet = IsHashColumn(rel_loc_info, part_col_name);
+ if (bRet == false)
+ IsModuloColumn(rel_loc_info, part_col_name);
+ return bRet;
+}
+
+
+/*
+ * Returns whether or not the data type is modulo distributable with PG-XC
+ * PGXCTODO - expand support for other data types!
+ */
+bool
+IsModuloDistributable(Oid col_type)
+{
+ if (col_type == INT4OID || col_type == INT2OID)
+ return true;
+
+ return false;
+}
+
+/*
+ * GetRelationModuloColumn - return modulo column for relation.
+ *
+ * Returns NULL if the relation is not modulo partitioned.
+ */
+char *
+GetRelationModuloColumn(RelationLocInfo * rel_loc_info)
+{
+ char *column_str = NULL;
+
+ if (rel_loc_info == NULL)
+ column_str = NULL;
+ else if (rel_loc_info->locatorType != LOCATOR_TYPE_MODULO)
+ column_str = NULL;
+ else
+ {
+ int len = strlen(rel_loc_info->partAttrName);
+
+ column_str = (char *) palloc(len + 1);
+ strncpy(column_str, rel_loc_info->partAttrName, len + 1);
+ }
+
+ return column_str;
+}
+
+/*
+ * IsModuloColumn - return whether or not column for relation is used for modulo distribution.
+ *
+ */
+bool
+IsModuloColumn(RelationLocInfo *rel_loc_info, char *part_col_name)
+{
+ bool ret_value = false;
+
+ if (!rel_loc_info || !part_col_name)
+ ret_value = false;
+ else if (rel_loc_info->locatorType != LOCATOR_TYPE_MODULO)
+ ret_value = false;
+ else
+ ret_value = !strcmp(part_col_name, rel_loc_info->partAttrName);
+
+ return ret_value;
+}
+
+
+/*
+ * IsModuloColumnForRelId - return whether or not column for relation is used for modulo distribution.
+ *
+ */
+bool
+IsModuloColumnForRelId(Oid relid, char *part_col_name)
+{
+ RelationLocInfo *rel_loc_info = GetRelationLocInfo(relid);
+
+ return IsModuloColumn(rel_loc_info, part_col_name);
+}
/*
* Update the round robin node for the relation
@@ -365,6 +493,19 @@ GetRelationNodes(RelationLocInfo *rel_loc_info, long *partValue,
exec_nodes->nodelist = list_copy(rel_loc_info->nodeList);
break;
+ case LOCATOR_TYPE_MODULO:
+ if (partValue != NULL)
+ /* in prototype, all partitioned tables use same map */
+ exec_nodes->nodelist = lappend_int(NULL, get_node_from_modulo(compute_modulo(*partValue)));
+ else
+ if (accessType == RELATION_ACCESS_INSERT)
+ /* Insert NULL to node 1 */
+ exec_nodes->nodelist = lappend_int(NULL, 1);
+ else
+ /* Use all nodes for other types of access */
+ exec_nodes->nodelist = list_copy(rel_loc_info->nodeList);
+ break;
+
case LOCATOR_TYPE_SINGLE:
/* just return first (there should only be one) */
@@ -420,6 +561,9 @@ ConvertToLocatorType(int disttype)
case DISTTYPE_REPLICATION:
loctype = LOCATOR_TYPE_REPLICATED;
break;
+ case DISTTYPE_MODULO:
+ loctype = LOCATOR_TYPE_MODULO;
+ break;
default:
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
diff --git a/src/backend/pgxc/plan/planner.c b/src/backend/pgxc/plan/planner.c
index c8e67a632a..0c197565d6 100644
--- a/src/backend/pgxc/plan/planner.c
+++ b/src/backend/pgxc/plan/planner.c
@@ -499,7 +499,8 @@ get_plan_nodes_insert(PlannerInfo *root, RemoteQuery *step)
/* Optimization is only done for distributed tables */
if (query->jointree != NULL
&& query->jointree->fromlist != NULL
- && rel_loc_info->locatorType == LOCATOR_TYPE_HASH)
+ && (rel_loc_info->locatorType == LOCATOR_TYPE_HASH ||
+ rel_loc_info->locatorType == LOCATOR_TYPE_MODULO))
{
/*
* See if it is "single-step"
@@ -526,7 +527,8 @@ get_plan_nodes_insert(PlannerInfo *root, RemoteQuery *step)
/* If the source is not hash-based (eg, replicated) also send
* through general planner
*/
- if (step->exec_nodes->baselocatortype != LOCATOR_TYPE_HASH)
+ if (step->exec_nodes->baselocatortype != LOCATOR_TYPE_HASH &&
+ step->exec_nodes->baselocatortype != LOCATOR_TYPE_MODULO)
{
step->exec_nodes = NULL;
return;
@@ -539,8 +541,9 @@ get_plan_nodes_insert(PlannerInfo *root, RemoteQuery *step)
}
- if (rel_loc_info->locatorType == LOCATOR_TYPE_HASH &&
- rel_loc_info->partAttrName != NULL)
+ if ( (rel_loc_info->partAttrName != NULL) &&
+ ( (rel_loc_info->locatorType == LOCATOR_TYPE_HASH) ||
+ (rel_loc_info->locatorType == LOCATOR_TYPE_MODULO) ))
{
Expr *checkexpr;
TargetEntry *tle = NULL;
@@ -600,8 +603,9 @@ get_plan_nodes_insert(PlannerInfo *root, RemoteQuery *step)
(errcode(ERRCODE_STATEMENT_TOO_COMPLEX),
(errmsg("Could not find relation for oid = %d", rte->relid))));
- if (source_rel_loc_info->locatorType == LOCATOR_TYPE_HASH &&
- strcmp(col_base->colname, source_rel_loc_info->partAttrName) == 0)
+ if ((strcmp(col_base->colname, source_rel_loc_info->partAttrName) == 0) &&
+ ( (source_rel_loc_info->locatorType == LOCATOR_TYPE_HASH) ||
+ (source_rel_loc_info->locatorType == LOCATOR_TYPE_MODULO) ))
{
/*
* Partition columns match, we have a "single-step INSERT SELECT".
@@ -1072,8 +1076,9 @@ examine_conditions_walker(Node *expr_node, XCWalkerContext *context)
if (!rel_loc_info1)
return true;
- /* If hash partitioned, check if the part column was used */
- if (IsHashColumn(rel_loc_info1, column_base->colname))
+ /* If hash or modulo partitioned, check if the part column was used */
+ if (IsHashColumn(rel_loc_info1, column_base->colname) ||
+ IsModuloColumn(rel_loc_info1, column_base->colname))
{
/* add to partitioned literal join conditions */
Literal_Comparison *lit_comp =
@@ -1174,8 +1179,10 @@ examine_conditions_walker(Node *expr_node, XCWalkerContext *context)
* PGXCTODO - for the prototype, we assume all partitioned
* tables are on the same nodes.
*/
- if (IsHashColumn(rel_loc_info1, column_base->colname)
- && IsHashColumn(rel_loc_info2, column_base2->colname))
+ if ( ( (IsHashColumn(rel_loc_info1, column_base->colname)) &&
+ (IsHashColumn(rel_loc_info2, column_base2->colname))) ||
+ ( (IsModuloColumn(rel_loc_info1, column_base->colname)) &&
+ (IsModuloColumn(rel_loc_info2, column_base2->colname))))
{
/* We found a partitioned join */
Parent_Child_Join *parent_child = (Parent_Child_Join *)
@@ -1219,7 +1226,8 @@ examine_conditions_walker(Node *expr_node, XCWalkerContext *context)
if (!rel_loc_info1)
return true;
- if (IsHashColumn(rel_loc_info1, column_base->colname))
+ if (IsHashColumn(rel_loc_info1, column_base->colname) ||
+ IsModuloColumn(rel_loc_info1, column_base->colname))
{
Expr_Comparison *expr_comp =
palloc(sizeof(Expr_Comparison));
@@ -1668,7 +1676,8 @@ get_plan_nodes_walker(Node *query_node, XCWalkerContext *context)
if (!rel_loc_info)
return true;
- if (rel_loc_info->locatorType != LOCATOR_TYPE_HASH)
+ if (rel_loc_info->locatorType != LOCATOR_TYPE_HASH &&
+ rel_loc_info->locatorType != LOCATOR_TYPE_MODULO)
/* do not need to determine partitioning expression */
context->query_step->exec_nodes = GetRelationNodes(rel_loc_info,
NULL,
@@ -3197,9 +3206,9 @@ validate_part_col_updatable(const Query *query)
(errmsg("Could not find relation for oid = %d", rte->relid))));
- /* Only LOCATOR_TYPE_HASH should be checked */
- if (rel_loc_info->locatorType == LOCATOR_TYPE_HASH &&
- rel_loc_info->partAttrName != NULL)
+ /* Only LOCATOR_TYPE_HASH & LOCATOR_TYPE_MODULO should be checked */
+ if ( (rel_loc_info->partAttrName != NULL) &&
+ ( (rel_loc_info->locatorType == LOCATOR_TYPE_HASH) || (rel_loc_info->locatorType == LOCATOR_TYPE_MODULO) ) )
{
/* It is a partitioned table, check partition column in targetList */
foreach(lc, query->targetList)
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index 9a96ea6886..c5ca1e5d3c 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -1185,7 +1185,8 @@ typedef enum DistributionType
{
DISTTYPE_REPLICATION, /* Replicated */
DISTTYPE_HASH, /* Hash partitioned */
- DISTTYPE_ROUNDROBIN /* Round Robin */
+ DISTTYPE_ROUNDROBIN, /* Round Robin */
+ DISTTYPE_MODULO /* Modulo partitioned */
} DistributionType;
/*----------
diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h
index dc6b96e3b5..d6e0aae515 100644
--- a/src/include/parser/kwlist.h
+++ b/src/include/parser/kwlist.h
@@ -242,6 +242,9 @@ PG_KEYWORD("maxvalue", MAXVALUE, UNRESERVED_KEYWORD)
PG_KEYWORD("minute", MINUTE_P, UNRESERVED_KEYWORD)
PG_KEYWORD("minvalue", MINVALUE, UNRESERVED_KEYWORD)
PG_KEYWORD("mode", MODE, UNRESERVED_KEYWORD)
+#ifdef PGXC
+PG_KEYWORD("modulo", MODULO, UNRESERVED_KEYWORD)
+#endif
PG_KEYWORD("month", MONTH_P, UNRESERVED_KEYWORD)
PG_KEYWORD("move", MOVE, UNRESERVED_KEYWORD)
PG_KEYWORD("name", NAME_P, UNRESERVED_KEYWORD)
diff --git a/src/include/pgxc/locator.h b/src/include/pgxc/locator.h
index 1bc894953f..5948faece6 100644
--- a/src/include/pgxc/locator.h
+++ b/src/include/pgxc/locator.h
@@ -21,6 +21,7 @@
#define LOCATOR_TYPE_SINGLE 'S'
#define LOCATOR_TYPE_RROBIN 'N'
#define LOCATOR_TYPE_CUSTOM 'C'
+#define LOCATOR_TYPE_MODULO 'M'
#define HASH_SIZE 4096
#define HASH_MASK 0x00000FFF;
@@ -107,4 +108,11 @@ extern List *GetAnyDataNode(void);
extern void RelationBuildLocator(Relation rel);
extern void FreeRelationLocInfo(RelationLocInfo *relationLocInfo);
+extern bool IsModuloDistributable(Oid col_type);
+extern char *GetRelationModuloColumn(RelationLocInfo * rel_loc_info);
+extern bool IsModuloColumn(RelationLocInfo *rel_loc_info, char *part_col_name);
+extern bool IsModuloColumnForRelId(Oid relid, char *part_col_name);
+extern char *GetRelationDistColumn(RelationLocInfo * rel_loc_info);
+extern bool IsDistColumnForRelId(Oid relid, char *part_col_name);
+
#endif /* LOCATOR_H */