You can subscribe to this list here.
2010 |
Jan
|
Feb
|
Mar
|
Apr
(4) |
May
(28) |
Jun
(12) |
Jul
(11) |
Aug
(12) |
Sep
(5) |
Oct
(19) |
Nov
(14) |
Dec
(12) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2011 |
Jan
(18) |
Feb
(30) |
Mar
(115) |
Apr
(89) |
May
(50) |
Jun
(44) |
Jul
(22) |
Aug
(13) |
Sep
(11) |
Oct
(30) |
Nov
(28) |
Dec
(39) |
2012 |
Jan
(38) |
Feb
(18) |
Mar
(43) |
Apr
(91) |
May
(108) |
Jun
(46) |
Jul
(37) |
Aug
(44) |
Sep
(33) |
Oct
(29) |
Nov
(36) |
Dec
(15) |
2013 |
Jan
(35) |
Feb
(611) |
Mar
(5) |
Apr
(55) |
May
(30) |
Jun
(28) |
Jul
(458) |
Aug
(34) |
Sep
(9) |
Oct
(39) |
Nov
(22) |
Dec
(32) |
2014 |
Jan
(16) |
Feb
(16) |
Mar
(42) |
Apr
(179) |
May
(7) |
Jun
(6) |
Jul
(9) |
Aug
|
Sep
(4) |
Oct
|
Nov
(3) |
Dec
|
2015 |
Jan
|
Feb
|
Mar
|
Apr
(2) |
May
(4) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
|
|
1
|
2
(6) |
3
|
4
|
5
|
6
|
7
|
8
|
9
|
10
|
11
|
12
|
13
|
14
|
15
|
16
(2) |
17
(3) |
18
(1) |
19
|
20
|
21
(8) |
22
(6) |
23
(3) |
24
|
25
|
26
|
27
|
28
(1) |
|
|
|
|
|
From: Michael P. <mic...@us...> - 2011-02-02 08:14:13
|
Project "Postgres-XC". The branch, master has been updated via 07465f400258a1ad59d313c008ebc3f8a42491fb (commit) from a1b041e2656b64689cd9719cc5662984a4f5f5a4 (commit) - Log ----------------------------------------------------------------- commit 07465f400258a1ad59d313c008ebc3f8a42491fb Author: Michael P <mic...@us...> Date: Wed Feb 2 17:12:58 2011 +0900 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 diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 75637fc..aa12288 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 6b897c8..08462c2 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 62cb748..2d0fb13 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 1b87bcb..4df4da3 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 b0d8c61..e1266ed 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 580ed18..ea8cc45 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 199293f..d1aef8b 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 c8e67a6..0c19756 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 94fe89c..b48df0f 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 c29e316..2c84923 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 1bc8949..5948fae 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 */ ----------------------------------------------------------------------- Summary of changes: src/backend/catalog/heap.c | 36 ++++++++- src/backend/catalog/pgxc_class.c | 2 +- src/backend/commands/copy.c | 34 ++++---- src/backend/commands/indexcmds.c | 2 +- src/backend/parser/gram.y | 20 ++++- src/backend/parser/parse_utilcmd.c | 13 ++-- src/backend/pgxc/locator/locator.c | 148 +++++++++++++++++++++++++++++++++++- src/backend/pgxc/plan/planner.c | 39 ++++++---- src/include/nodes/primnodes.h | 3 +- src/include/parser/kwlist.h | 3 + src/include/pgxc/locator.h | 8 ++ 11 files changed, 255 insertions(+), 53 deletions(-) hooks/post-receive -- Postgres-XC |
From: Michael P. <mic...@us...> - 2011-02-02 07:45:17
|
Project "Postgres-XC". The branch, ha_support has been updated via 63810afccc1ae9ea8ee0831994106adb3087b795 (commit) from 0049fd0c80b376fb653dcffab154aa7daf0fa9a0 (commit) - Log ----------------------------------------------------------------- commit 63810afccc1ae9ea8ee0831994106adb3087b795 Author: Michael P <mic...@us...> Date: Wed Feb 2 16:45:58 2011 +0900 Addition of a stored function pgxc_is_committed This function can be used to look the status of a transaction depending on its XID number. This feature will be used for 2PC cleanup when a Coordinator crashes. For given ID, this function returns the following values: - true if transaction is committed - false if transaction is aborted - nothing if transaction is not known Examples: select pgxc_is_committed('1000'); execute direct on node 1 'pgxc_is_committed(''1000'')'; diff --git a/src/backend/access/transam/transam.c b/src/backend/access/transam/transam.c index 2a1eab4..b196ddf 100644 --- a/src/backend/access/transam/transam.c +++ b/src/backend/access/transam/transam.c @@ -24,6 +24,9 @@ #include "access/transam.h" #include "utils/snapmgr.h" +#ifdef PGXC +#include "utils/builtins.h" +#endif /* * Single-item cache for results of TransactionLogFetch. It's worth having @@ -41,6 +44,10 @@ static const XLogRecPtr InvalidXLogRecPtr = {0, 0}; /* Local functions */ static XidStatus TransactionLogFetch(TransactionId transactionId); +#ifdef PGXC +/* It is not really necessary to make it appear in header file */ +Datum pgxc_is_committed(PG_FUNCTION_ARGS); +#endif /* ---------------------------------------------------------------- * Postgres log access method interface @@ -97,6 +104,27 @@ TransactionLogFetch(TransactionId transactionId) return xidstatus; } +#ifdef PGXC +/* + * For given Transaction ID, check if transaction is committed or aborted + */ +Datum +pgxc_is_committed(PG_FUNCTION_ARGS) +{ + TransactionId tid = (TransactionId) PG_GETARG_UINT32(0); + XidStatus xidstatus; + + xidstatus = TransactionLogFetch(tid); + + if (xidstatus == TRANSACTION_STATUS_COMMITTED) + PG_RETURN_BOOL(true); + else if (xidstatus == TRANSACTION_STATUS_ABORTED) + PG_RETURN_BOOL(false); + else + PG_RETURN_NULL(); +} +#endif + /* ---------------------------------------------------------------- * Interface functions * diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index bfccbe5..d0dbc3f 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -4715,7 +4715,8 @@ DATA(insert OID = 3113 ( last_value PGNSP PGUID 12 1 0 0 f t f t f i 1 0 2283 " DESCR("fetch the last row value"); DATA(insert OID = 3114 ( nth_value PGNSP PGUID 12 1 0 0 f t f t f i 2 0 2283 "2283 23" _null_ _null_ _null_ _null_ window_nth_value _null_ _null_ _null_ )); DESCR("fetch the Nth row value"); - +DATA(insert OID = 3115 ( pgxc_is_committed PGNSP PGUID 12 1 0 0 f f f t t s 1 0 16 "28" _null_ _null_ _null_ _null_ pgxc_is_committed _null_ _null_ _null_ )); +DESCR("is given GXID committed or aborted?"); /* * Symbolic values for provolatile column: these indicate whether the result diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index 30cd971..26e1b2b 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -1057,4 +1057,9 @@ extern Datum pg_prepared_statement(PG_FUNCTION_ARGS); /* utils/mmgr/portalmem.c */ extern Datum pg_cursor(PG_FUNCTION_ARGS); +/* backend/access/transam/transam.c */ +#ifdef PGXC +extern Datum pgxc_is_committed(PG_FUNCTION_ARGS); +#endif + #endif /* BUILTINS_H */ ----------------------------------------------------------------------- Summary of changes: src/backend/access/transam/transam.c | 28 ++++++++++++++++++++++++++++ src/include/catalog/pg_proc.h | 3 ++- src/include/utils/builtins.h | 5 +++++ 3 files changed, 35 insertions(+), 1 deletions(-) hooks/post-receive -- Postgres-XC |
From: Michael P. <mic...@us...> - 2011-02-02 05:21:16
|
Project "Postgres-XC". The branch, ha_support has been created at 0049fd0c80b376fb653dcffab154aa7daf0fa9a0 (commit) - Log ----------------------------------------------------------------- commit 0049fd0c80b376fb653dcffab154aa7daf0fa9a0 Author: Michael P <mic...@us...> Date: Wed Feb 2 14:16:29 2011 +0900 Extension of 2PC catalog tables Basics for 2PC cleanup in Postgres-XC cluster in case of node crash. Following parameters are added in the view pg_prepared_xacts: - isimplicit, Type of 2PC made: implicit or explicit - isddl, flag indicating if transaction prepared used DDL or not - coordnum, number of Coordinator from where 2PC has been issued - nodelist, list of Datanodes where PREPARE has been issued "nodelist" contains only the list of Datanodes prepared. For prepared transaction involving only Coordinators, nodelist is set to 'n'. Note: 2PC can be involved in a transaction COMMIT if multiple Datanodes have been involved in a write operation. This is a implicit 2PC. Explicit 2PC is the case of an application issuing PREPARE and COMMIT/ABORT PREPARED. diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c index af15e79..04c9f00 100644 --- a/src/backend/access/transam/twophase.c +++ b/src/backend/access/transam/twophase.c @@ -61,7 +61,9 @@ #include "storage/smgr.h" #include "utils/builtins.h" #include "utils/memutils.h" - +#ifdef PGXC +#include "pgxc/execRemote.h" +#endif /* * Directory where Two-phase commit files reside within PGDATA @@ -120,6 +122,12 @@ typedef struct GlobalTransactionData Oid owner; /* ID of user that executed the xact */ TransactionId locking_xid; /* top-level XID of backend working on xact */ bool valid; /* TRUE if fully prepared */ +#ifdef PGXC + bool isimplicit; /* Type of 2PC made: implicit or explicit */ + bool isddl; /* Flag if DDL have been used (Check if Co also are prepared) */ + int32 coordnum; /* Number of Coordinator from where 2PC has been issued */ + char nodelist[NODELISTSIZE]; /* List of Datanodes where PREPARE has been issued */ +#endif char gid[GIDSIZE]; /* The GID assigned to the prepared xact */ } GlobalTransactionData; @@ -144,7 +152,6 @@ typedef struct TwoPhaseStateData static TwoPhaseStateData *TwoPhaseState; - static void RecordTransactionCommitPrepared(TransactionId xid, int nchildren, TransactionId *children, @@ -234,10 +241,27 @@ TwoPhaseShmemInit(void) * Internally, this creates a gxact struct and puts it into the active array. * NOTE: this is also used when reloading a gxact after a crash; so avoid * assuming that we can use very much backend context. + * + * This contains additional information necessary for a PGXC PREPARE: + * - the commit GXID (to be committed at GTM) + * - flag if transaction is a DDL (commit on Coordinators or not) + * - flag if transaction is implicit or explicit (information is on GTM for explicit) + * - list of Datanodes involved + * - Coordinator number from where PREPARE has been issued. */ +#ifdef PGXC +GlobalTransaction +MarkAsPreparing(TransactionId xid, + const char *gid, + TimestampTz prepared_at, + Oid owner, + Oid databaseid, + Remote2PCData *PGXC2PCData) +#else GlobalTransaction MarkAsPreparing(TransactionId xid, const char *gid, TimestampTz prepared_at, Oid owner, Oid databaseid) +#endif { GlobalTransaction gxact; int i; @@ -334,6 +358,13 @@ MarkAsPreparing(TransactionId xid, const char *gid, gxact->locking_xid = xid; gxact->valid = false; strcpy(gxact->gid, gid); +#ifdef PGXC + /* Add also the records associated to a PGXC 2PC */ + memcpy(gxact->nodelist, PGXC2PCData->nodelist, strlen(PGXC2PCData->nodelist)); + gxact->isimplicit = PGXC2PCData->isimplicit; + gxact->isddl = PGXC2PCData->isddl; + gxact->coordnum = PGXC2PCData->coordnum; +#endif /* And insert it into the active array */ Assert(TwoPhaseState->numPrepXacts < max_prepared_xacts); @@ -606,7 +637,11 @@ pg_prepared_xact(PG_FUNCTION_ARGS) /* build tupdesc for result tuples */ /* this had better match pg_prepared_xacts view in system_views.sql */ +#ifdef PGXC + tupdesc = CreateTemplateTupleDesc(9, false); +#else tupde |
From: Michael P. <mic...@us...> - 2011-02-02 05:15:43
|
Project "Postgres-XC". The branch, ha_support has been deleted was 497b27848af35363b745dbce20d2b8cb806c43dc ----------------------------------------------------------------------- 497b27848af35363b745dbce20d2b8cb806c43dc Support for EXECUTE DIRECT ----------------------------------------------------------------------- hooks/post-receive -- Postgres-XC |
From: Michael P. <mic...@us...> - 2011-02-02 05:08:40
|
Project "Postgres-XC". The branch, master has been updated via a1b041e2656b64689cd9719cc5662984a4f5f5a4 (commit) from 10a271b9287eb59b1846f5334e2cb1b35e69b4d6 (commit) - Log ----------------------------------------------------------------- commit a1b041e2656b64689cd9719cc5662984a4f5f5a4 Author: Michael P <mic...@us...> Date: Wed Feb 2 14:13:02 2011 +0900 Support for EXECUTE DIRECT EXECUTE DIRECT is a utility query allowing to launch queries directly on targetted PGXC nodes. EXECUTE DIRECT ON (COORDINATOR num | NODE num) 'query'; This implementation contains the following use restrictions: - only a superuser is allowed to use it - DML queries (DELETE, INSERT, UPDATE) cannot be launched with it (easy to break data consistency) - utilities cannot be launched launched on local coordinator - utilities cannot be launched inside a transaction block (though SELECT queries in EXECUTE DIRECT keep the same visibility if used in a transaction block). - only one query can be launched at a time - query can be launched on a unique node This feature will be used to have a look at 2PC catalog data when nodes crash and to clean up 2PC transactions on targetted nodes. Ex: EXECUTE DIRECT ON NODE 1 'SELECT * from pg_prepared_xact()'; EXECUTE DIRECT ON COORDINATOR 2 'COMMIT PREPARED ''foo'''; diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index 0e9aa43..cb7a1a8 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -264,8 +264,9 @@ set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) * If we are on the coordinator, we always want to use * the remote query path unless it is a pg_catalog table. */ - if (IS_PGXC_COORDINATOR - && get_rel_namespace(rte->relid) != PG_CATALOG_NAMESPACE) + if (IS_PGXC_COORDINATOR && + !IsConnFromCoord() && + get_rel_namespace(rte->relid) != PG_CATALOG_NAMESPACE) add_path(rel, create_remotequery_path(root, rel)); else { diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index 5b2e03f..40777bf 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -41,8 +41,10 @@ #include "rewrite/rewriteManip.h" #ifdef PGXC #include "pgxc/pgxc.h" +#include "access/gtm.h" #include "pgxc/planner.h" #include "tcop/tcopprot.h" +#include "pgxc/poolmgr.h" #endif #include "utils/rel.h" @@ -2066,9 +2068,160 @@ transformExplainStmt(ParseState *pstate, ExplainStmt *stmt) static Query * transformExecDirectStmt(ParseState *pstate, ExecDirectStmt *stmt) { - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("Support for EXECUTE DIRECT is temporary broken"))); + Query *result = makeNode(Query); + bool is_coordinator = stmt->coordinator; + char *query = stmt->query; + List *nodelist = stmt->nodes; + ListCell *nodeitem; + RemoteQuery *step = makeNode(RemoteQuery); + bool is_local = false; + List *raw_parsetree_list; + ListCell *raw_parsetree_item; + + if (list_length(nodelist) > 1) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Support for EXECUTE DIRECT on multiple nodes is not available yet"))); + + if (!superuser()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("must be superuser to use EXECUTE DIRECT"))); + + /* Check if execute direct is local and if node number is correct*/ + foreach(nodeitem, nodelist) + { + int nodenum = intVal(lfirst(nodeitem)); + + if (nodenum < 1 || + (!is_coordinator && nodenum > NumDataNodes) || + (is_coordinator && nodenum > NumCoords)) + ereport(ERROR, + (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("Node Number %d is incorrect", nodenum))); + + if (nodenum == PGXCNodeId && is_coordinator) + is_local = true; + } + + /* Transform the query into a raw parse list */ + raw_parsetree_list = pg_parse_query(query); + + /* EXECUTE DIRECT can just be executed with a single query */ + if (list_length(raw_parsetree_list) > 1) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("EXECUTE DIRECT cannot execute multiple queries"))); + + /* + * Analyze the Raw parse tree + * EXECUTE DIRECT is restricted to one-step usage + */ + foreach(raw_parsetree_item, raw_parsetree_list) + { + Node *parsetree = (Node *) lfirst(raw_parsetree_item); + result = parse_analyze(parsetree, query, NULL, 0); + } + + /* Needed by planner */ + result->sql_statement = pstrdup(query); + + /* Default list of parameters to set */ + step->is_single_step = true; + step->sql_statement = NULL; + step->exec_nodes = NULL; + step->combine_type = COMBINE_TYPE_NONE; + step->simple_aggregates = NIL; + step->sort = NULL; + step->distinct = NULL; + step->read_only = true; + step->force_autocommit = false; + step->cursor = NULL; + step->exec_type = EXEC_ON_DATANODES; + step->paramval_data = NULL; + step->paramval_len = 0; + + step->relname = NULL; + step->remotejoin = false; + step->partitioned_replicated = false; + step->reduce_level = 0; + step->base_tlist = NIL; + step->outer_alias = NULL; + step->inner_alias = NULL; + step->outer_reduce_level = 0; + step->inner_reduce_level = 0; + step->outer_relids = NULL; + step->inner_relids = NULL; + step->inner_statement = NULL; + step->outer_statement = NULL; + step->join_condition = NULL; + + /* Change the list of nodes that will be executed for the query and others */ + step->exec_nodes = (ExecNodes *) palloc(sizeof(ExecNodes)); + step->exec_nodes->primarynodelist = NIL; + step->exec_nodes->nodelist = NIL; + step->exec_nodes->expr = NIL; + step->force_autocommit = false; + step->combine_type = COMBINE_TYPE_SAME; + step->read_only = true; + step->exec_direct_type = EXEC_DIRECT_NONE; + + /* Set up EXECUTE DIRECT flag */ + if (is_local) + { + if (result->commandType == CMD_UTILITY) + step->exec_direct_type = EXEC_DIRECT_LOCAL_UTILITY; + else + step->exec_direct_type = EXEC_DIRECT_LOCAL; + } + else + { + if (result->commandType == CMD_UTILITY) + step->exec_direct_type = EXEC_DIRECT_UTILITY; + else if (result->commandType == CMD_SELECT) + step->exec_direct_type = EXEC_DIRECT_SELECT; + else if (result->commandType == CMD_INSERT) + step->exec_direct_type = EXEC_DIRECT_INSERT; + else if (result->commandType == CMD_UPDATE) + step->exec_direct_type = EXEC_DIRECT_UPDATE; + else if (result->commandType == CMD_DELETE) + step->exec_direct_type = EXEC_DIRECT_DELETE; + } + + /* + * Features not yet supported + * DML can be launched without errors but this could compromise data + * consistency, so block it. + */ + if (step->exec_direct_type == EXEC_DIRECT_DELETE + || step->exec_direct_type == EXEC_DIRECT_UPDATE + || step->exec_direct_type == EXEC_DIRECT_INSERT) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("EXECUTE DIRECT cannot execute DML queries"))); + if (step->exec_direct_type == EXEC_DIRECT_LOCAL_UTILITY) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("EXECUTE DIRECT cannot execute locally utility queries"))); + + /* Build Execute Node list */ + foreach(nodeitem, nodelist) + { + int nodenum = intVal(lfirst(nodeitem)); + step->exec_nodes->nodelist = lappend_int(step->exec_nodes->nodelist, nodenum); + } + + step->sql_statement = pstrdup(query); + + if (is_coordinator) + step->exec_type = EXEC_ON_COORDS; + else + step->exec_type = EXEC_ON_DATANODES; + + /* Associate newly-created RemoteQuery node to the returned Query result */ + result->utilityStmt = (Node *) step; + + return result; } #endif diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 37b012b..b0d8c61 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -6534,16 +6534,17 @@ opt_analyze: /***************************************************************************** * * QUERY: - * EXECUTE DIRECT ON (COORDINATOR | NODE num, ...) query + * EXECUTE DIRECT ON (COORDINATOR num, ... | NODE num, ...) query * *****************************************************************************/ -ExecDirectStmt: EXECUTE DIRECT ON COORDINATOR DirectStmt +ExecDirectStmt: EXECUTE DIRECT ON COORDINATOR coord_list DirectStmt { ExecDirectStmt *n = makeNode(ExecDirectStmt); n->coordinator = TRUE; n->nodes = NIL; - n->query = $5; + n->nodes = $5; + n->query = $6; $$ = (Node *)n; } | EXECUTE DIRECT ON NODE data_node_list DirectStmt diff --git a/src/backend/pgxc/plan/planner.c b/src/backend/pgxc/plan/planner.c index fbfe733..c8e67a6 100644 --- a/src/backend/pgxc/plan/planner.c +++ b/src/backend/pgxc/plan/planner.c @@ -943,10 +943,22 @@ examine_conditions_walker(Node *expr_node, XCWalkerContext *context) } return false; } - // ??? current plan node is not a remote query - context->query_step->exec_nodes = makeNode(ExecNodes); - context->query_step->exec_nodes->tableusagetype = TABLE_USAGE_TYPE_PGCATALOG; - context->exec_on_coord = true; + + /* Even with a catalog table EXECUTE direct in launched on dedicated nodes */ + if (context->query_step->exec_direct_type == EXEC_DIRECT_LOCAL + || context->query_step->exec_direct_type == EXEC_DIRECT_NONE + || context->query_step->exec_direct_type == EXEC_DIRECT_LOCAL_UTILITY) + { + context->query_step->exec_nodes = makeNode(ExecNodes); + context->query_step->exec_nodes->tableusagetype = TABLE_USAGE_TYPE_PGCATALOG; + context->exec_on_coord = true; + } + else + { + context->query_step->exec_nodes->tableusagetype = TABLE_USAGE_TYPE_USER; + context->exec_on_coord = false; + } + return false; } @@ -1404,6 +1416,10 @@ get_plan_nodes_walker(Node *query_node, XCWalkerContext *context) if (!query_node && !IsA(query_node,Query)) return true; + /* if EXECUTE DIRECT, just return */ + if (context->query_step->exec_direct_type != EXEC_DIRECT_NONE) + return false; + query = (Query *) query_node; /* If no tables, just return */ @@ -1574,7 +1590,7 @@ get_plan_nodes_walker(Node *query_node, XCWalkerContext *context) } } - /* If we are just dealing with pg_catalog, just return */ + /* If we are just dealing with pg_catalog, just return. */ if (table_usage_type == TABLE_USAGE_TYPE_PGCATALOG) { context->query_step->exec_nodes = makeNode(ExecNodes); @@ -1816,6 +1832,7 @@ makeRemoteQuery(void) result->exec_type = EXEC_ON_DATANODES; result->paramval_data = NULL; result->paramval_len = 0; + result->exec_direct_type = EXEC_DIRECT_NONE; result->relname = NULL; result->remotejoin = false; @@ -1852,7 +1869,7 @@ get_plan_nodes(PlannerInfo *root, RemoteQuery *step, RelationAccessType accessTy context.rtables = lappend(context.rtables, query->rtable); if ((get_plan_nodes_walker((Node *) query, &context) - || context.exec_on_coord) && context.query_step->exec_nodes) + || context.exec_on_coord) && context.query_step->exec_nodes) { pfree(context.query_step->exec_nodes); context.query_step->exec_nodes = NULL; @@ -2748,13 +2765,33 @@ pgxc_planner(Query *query, int cursorOptions, ParamListInfo boundParams) result->intoClause = query->intoClause; result->rtable = query->rtable; - query_step = makeRemoteQuery(); + /* EXECUTE DIRECT statements have their RemoteQuery node already built when analyzing */ + if (query->utilityStmt + && IsA(query->utilityStmt, RemoteQuery)) + { + RemoteQuery *stmt = (RemoteQuery *) query->utilityStmt; + if (stmt->exec_direct_type != EXEC_DIRECT_NONE) + { + query_step = stmt; + query->utilityStmt = NULL; + result->utilityStmt = NULL; + } + else + { + query_step = makeRemoteQuery(); + query_step->exec_nodes = query->execNodes; + } + } + else + { + query_step = makeRemoteQuery(); + query_step->exec_nodes = query->execNodes; + } - query_step->exec_nodes = query->execNodes; /* Optimize multi-node handling */ query_step->read_only = query->commandType == CMD_SELECT; - if (query->utilityStmt && + if (query->utilityStmt && IsA(query->utilityStmt, DeclareCursorStmt)) cursorOptions |= ((DeclareCursorStmt *) query->utilityStmt)->options; diff --git a/src/backend/pgxc/pool/execRemote.c b/src/backend/pgxc/pool/execRemote.c index c5610dc..1d41a5c 100644 --- a/src/backend/pgxc/pool/execRemote.c +++ b/src/backend/pgxc/pool/execRemote.c @@ -3024,12 +3024,19 @@ get_exec_connections(RemoteQueryState *planstate, FreeRelationLocInfo(rel_loc_info); } } - } else { - nodelist = exec_nodes->nodelist; + } + else + { + if (exec_type == EXEC_ON_DATANODES || exec_type == EXEC_ON_ALL_NODES) + nodelist = exec_nodes->nodelist; + else if (exec_type == EXEC_ON_COORDS) + coordlist = exec_nodes->nodelist; + primarynode = exec_nodes->primarynodelist; } } + /* Set node list and DN number */ if (list_length(nodelist) == 0 && (exec_type == EXEC_ON_ALL_NODES || exec_type == EXEC_ON_DATANODES)) @@ -3039,20 +3046,31 @@ get_exec_connections(RemoteQueryState *planstate, } else { - if (primarynode) - dn_conn_count = list_length(nodelist) + 1; + if (exec_type == EXEC_ON_DATANODES || exec_type == EXEC_ON_ALL_NODES) + { + if (primarynode) + dn_conn_count = list_length(nodelist) + 1; + else + dn_conn_count = list_length(nodelist); + } else - dn_conn_count = list_length(nodelist); + dn_conn_count = 0; } - if (exec_type == EXEC_ON_ALL_NODES || - exec_type == EXEC_ON_COORDS) + /* Set Coordinator list and coordinator number */ + if ((list_length(nodelist) == 0 && exec_type == EXEC_ON_ALL_NODES) || + (list_length(coordlist) == 0 && exec_type == EXEC_ON_COORDS)) { co_conn_count = NumCoords; coordlist = GetAllCoordNodes(); } else - co_conn_count = 0; + { + if (exec_type == EXEC_ON_COORDS) + co_conn_count = list_length(coordlist); + else + co_conn_count = 0; + } /* Get other connections (non-primary) */ pgxc_handles = get_handles(nodelist, coordlist, is_query_coord_only); @@ -3138,11 +3156,20 @@ do_query(RemoteQueryState *node) * are launched in ExecRemoteUtility */ pgxc_connections = get_exec_connections(node, step->exec_nodes, - EXEC_ON_DATANODES); + step->exec_type); + + if (step->exec_type == EXEC_ON_DATANODES) + { + connections = pgxc_connections->datanode_handles; + total_conn_count = regular_conn_count = pgxc_connections->dn_conn_count; + } + else if (step->exec_type == EXEC_ON_COORDS) + { + connections = pgxc_connections->coord_handles; + total_conn_count = regular_conn_count = pgxc_connections->co_conn_count; + } - connections = pgxc_connections->datanode_handles; primaryconnection = pgxc_connections->primary_handle; - total_conn_count = regular_conn_count = pgxc_connections->dn_conn_count; /* * Primary connection is counted separately but is included in total_conn_count if used. @@ -4011,6 +4038,7 @@ ExecRemoteUtility(RemoteQuery *node) int co_conn_count; int dn_conn_count; bool need_tran; + ExecDirectType exec_direct_type = node->exec_direct_type; int i; implicit_force_autocommit = force_autocommit; @@ -4020,7 +4048,15 @@ ExecRemoteUtility(RemoteQuery *node) pgxc_connections = get_exec_connections(NULL, node->exec_nodes, exec_type); dn_conn_count = pgxc_connections->dn_conn_count; - co_conn_count = pgxc_connections->co_conn_count; + + /* + * EXECUTE DIRECT can only be launched on a single node + * but we have to count local node also here. + */ + if (exec_direct_type != EXEC_DIRECT_NONE && exec_type == EXEC_ON_COORDS) + co_conn_count = 2; + else + co_conn_count = pgxc_connections->co_conn_count; /* Registering new connections needs the sum of Connections to Datanodes AND to Coordinators */ total_conn_count = dn_conn_count + co_conn_count; @@ -4033,6 +4069,17 @@ ExecRemoteUtility(RemoteQuery *node) else need_tran = !autocommit || total_conn_count > 1; + /* Commands launched through EXECUTE DIRECT do not need start a transaction */ + if (exec_direct_type == EXEC_DIRECT_UTILITY) + { + need_tran = false; + + /* This check is not done when analyzing to limit dependencies */ + if (IsTransactionBlock()) + ereport(ERROR, + (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION), + errmsg("cannot run EXECUTE DIRECT with utility inside a transaction block"))); + } if (!is_read_only) { diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c index 93bf626..a070db1 100644 --- a/src/backend/tcop/pquery.c +++ b/src/backend/tcop/pquery.c @@ -23,6 +23,7 @@ #include "pg_trace.h" #ifdef PGXC #include "pgxc/pgxc.h" +#include "pgxc/planner.h" #include "pgxc/execRemote.h" #endif #include "tcop/pquery.h" @@ -293,12 +294,26 @@ ChoosePortalStrategy(List *stmts) #ifdef PGXC else if (IsA(stmt, RemoteQuery)) { + RemoteQuery *step = (RemoteQuery *) stmt; /* * Let's choose PORTAL_ONE_SELECT for now * After adding more PGXC functionality we may have more * sophisticated algorithm of determining portal strategy + * + * EXECUTE DIRECT is a utility but depending on its inner query + * it can return tuples or not depending on the query used. */ - return PORTAL_ONE_SELECT; + if (step->exec_direct_type == EXEC_DIRECT_SELECT + || step->exec_direct_type == EXEC_DIRECT_UPDATE + || step->exec_direct_type == EXEC_DIRECT_DELETE + || step->exec_direct_type == EXEC_DIRECT_INSERT + || step->exec_direct_type == EXEC_DIRECT_LOCAL) + return PORTAL_ONE_SELECT; + else if (step->exec_direct_type == EXEC_DIRECT_UTILITY + || step->exec_direct_type == EXEC_DIRECT_LOCAL_UTILITY) + return PORTAL_MULTI_QUERY; + else + return PORTAL_ONE_SELECT; } #endif else if (IsA(stmt, PlannedStmt)) diff --git a/src/include/pgxc/planner.h b/src/include/pgxc/planner.h index ad0f05d..872a2fc 100644 --- a/src/include/pgxc/planner.h +++ b/src/include/pgxc/planner.h @@ -68,6 +68,18 @@ typedef enum EXEC_ON_ALL_NODES } RemoteQueryExecType; +typedef enum +{ + EXEC_DIRECT_NONE, + EXEC_DIRECT_LOCAL, + EXEC_DIRECT_LOCAL_UTILITY, + EXEC_DIRECT_UTILITY, + EXEC_DIRECT_SELECT, + EXEC_DIRECT_INSERT, + EXEC_DIRECT_UPDATE, + EXEC_DIRECT_DELETE +} ExecDirectType; + /* * Contains instructions on processing a step of a query. * In the prototype this will be simple, but it will eventually @@ -77,6 +89,7 @@ typedef struct { Scan scan; bool is_single_step; /* special case, skip extra work */ + ExecDirectType exec_direct_type; /* track if remote query is execute direct and what type it is */ char *sql_statement; ExecNodes *exec_nodes; /* List of Datanodes where to launch query */ CombineType combine_type; ----------------------------------------------------------------------- Summary of changes: src/backend/optimizer/path/allpaths.c | 5 +- src/backend/parser/analyze.c | 159 ++++++++++++++++++++++++++++++++- src/backend/parser/gram.y | 7 +- src/backend/pgxc/plan/planner.c | 55 ++++++++++-- src/backend/pgxc/pool/execRemote.c | 71 ++++++++++++--- src/backend/tcop/pquery.c | 17 ++++- src/include/pgxc/planner.h | 13 +++ 7 files changed, 297 insertions(+), 30 deletions(-) hooks/post-receive -- Postgres-XC |