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) |
2
|
3
|
4
|
5
|
6
|
7
|
8
|
9
|
10
|
11
|
12
|
13
|
14
|
15
(1) |
16
(3) |
17
|
18
|
19
|
20
|
21
|
22
|
23
|
24
(2) |
25
|
26
|
27
(1) |
28
(1) |
29
(1) |
30
(1) |
|
|
|
From: mason_s <ma...@us...> - 2010-06-15 18:59:22
|
Project "Postgres-XC". The branch, master has been updated via 4a16b67e0239abda5f2ca8ec45489b7fc906ec4b (commit) from ffe244ab59c464283ac1833e13377782bee1c122 (commit) - Log ----------------------------------------------------------------- commit 4a16b67e0239abda5f2ca8ec45489b7fc906ec4b Author: Mason S <masonsharp@mason-sharps-macbook.local> Date: Tue Jun 15 14:54:23 2010 -0400 Add support for views. A view is in effect rewritten into a FROM clause subquery, so we also add support of detecting safe FROM clause subqueries. We check after the query tree is rewritten if the query is safe to execute in a single step, include FROM clause subqueries. If not, we do not allow it. diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index cc4413c..a8f9d30 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -878,6 +878,12 @@ AddRelationDistribution (Oid relid, case DISTTYPE_HASH: /* User specified hash column, validate */ attnum = get_attnum(relid, distributeby->colname); + if (!attnum) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_TABLE_DEFINITION), + errmsg("Invalid distribution column specified"))); + } if (!IsHashDistributable(descriptor->attrs[attnum-1]->atttypid)) { diff --git a/src/backend/pgxc/plan/planner.c b/src/backend/pgxc/plan/planner.c index 13a0f8b..5e318dc 100644 --- a/src/backend/pgxc/plan/planner.c +++ b/src/backend/pgxc/plan/planner.c @@ -86,6 +86,15 @@ typedef struct PGXCJoinType join_type; } PGXC_Join; +/* used for base column in an expression */ +typedef struct ColumnBase +{ + int relid; + char *relname; + char *relalias; + char *colname; +} ColumnBase; + /* A list of List*'s, one for each relation. */ List *join_list = NULL; @@ -96,6 +105,17 @@ bool StrictStatementChecking = true; bool StrictSelectChecking = false; /* + * True if both lists contain only one node and are the same + */ +static bool +same_single_node (List *nodelist1, List *nodelist2) +{ + return nodelist1 && list_length(nodelist1) == 1 + && nodelist2 && list_length(nodelist2) == 1 + && linitial_int(nodelist1) != linitial_int(nodelist2); +} + +/* * Create a new join struct for tracking how relations are joined */ static PGXC_Join * @@ -224,7 +244,6 @@ free_join_list(void) if (join_list == NULL) return; - /* free all items in list including PGXC_Join struct */ list_free_deep(join_list); } @@ -269,7 +288,7 @@ get_numeric_constant(Expr *expr) * type, like a join, and we need to then look at the joinaliasvars * to determine what the base table and column really is. */ -static Var * +static ColumnBase* get_base_var(Var *var, List *rtables) { RangeTblEntry *rte; @@ -282,18 +301,45 @@ get_base_var(Var *var, List *rtables) rte = list_nth(rtables, var->varno - 1); if (rte->rtekind == RTE_RELATION) - return var; + { + ColumnBase *column_base = (ColumnBase *) palloc0(sizeof(ColumnBase)); + + column_base->relid = rte->relid; + column_base->relname = get_rel_name(rte->relid); + column_base->colname = strVal(list_nth(rte->eref->colnames, + var->varattno - 1)); + column_base->relalias = rte->eref->aliasname; + return column_base; + } else if (rte->rtekind == RTE_JOIN) { Var *colvar = list_nth(rte->joinaliasvars, var->varattno - 1); /* continue resolving recursively */ return get_base_var(colvar, rtables); + //may need to set this, toocolumn_base->relalias = rte->eref->aliasname; } - else + else if (rte->rtekind == RTE_SUBQUERY) { - return NULL; + /* + * Handle views like select * from v1 where col1 = 1 + * where col1 is partition column of base relation + */ + /* the varattno corresponds with the subquery's target list (projections) */ + TargetEntry *tle = list_nth(rte->subquery->targetList, var->varattno - 1); /* or varno? */ + + if (!IsA(tle->expr, Var)) + return NULL; /* not column based expressoin, return */ + else + { + Var *colvar = (Var *) tle->expr; + + /* continue resolving recursively */ + return get_base_var(colvar, rte->subquery->rtable); + } } + + return NULL; } @@ -316,10 +362,11 @@ get_plan_nodes_insert(Query *query) return NULL; /* Make sure there is just one table */ - if (query->rtable == NULL || query->rtable->length != 1) + if (query->rtable == NULL) return NULL; - rte = (RangeTblEntry *) lfirst(list_head(query->rtable)); + rte = (RangeTblEntry *) list_nth(query->rtable, query->resultRelation - 1); + if (rte != NULL && rte->rtekind != RTE_RELATION) /* Bad relation type */ @@ -402,10 +449,6 @@ get_plan_nodes_insert(Query *query) static bool examine_conditions(Special_Conditions *conditions, List *rtables, Node *expr_node) { - char *rel_name, - *rel_name2; - char *col_name, - *col_name2; RelationLocInfo *rel_loc_info1, *rel_loc_info2; Const *constant; @@ -472,23 +515,14 @@ examine_conditions(Special_Conditions *conditions, List *rtables, Node *expr_nod /* Look for a table */ if (IsA(arg1, Var)) { - RangeTblEntry *rte1, - *rte2; - /* get the RangeTableEntry */ Var *colvar = (Var *) arg1; - colvar = get_base_var(colvar, rtables); + ColumnBase *column_base = get_base_var(colvar, rtables); - if (!colvar) + if (!column_base) return false; - rte1 = list_nth(rtables, colvar->varno - 1); - - rel_name = get_rel_name(rte1->relid); - col_name = strVal(list_nth(rte1->eref->colnames, - colvar->varattno - 1)); - /* Look at other argument */ /* We may have a cast, try and handle it */ @@ -502,21 +536,21 @@ examine_conditions(Special_Conditions *conditions, List *rtables, Node *expr_nod /* We have column = literal. Check if partitioned case */ constant = (Const *) arg2; - rel_loc_info1 = GetRelationLocInfo(rte1->relid); + rel_loc_info1 = GetRelationLocInfo(column_base->relid); if (!rel_loc_info1) return false; /* If hash partitioned, check if the part column was used */ - if (IsHashColumn(rel_loc_info1, col_name)) + if (IsHashColumn(rel_loc_info1, column_base->colname)) { /* add to partitioned literal join conditions */ Literal_Comparison *lit_comp = palloc(sizeof(Literal_Comparison)); - lit_comp->relid = rte1->relid; + lit_comp->relid = column_base->relid; lit_comp->rel_loc_info = rel_loc_info1; - lit_comp->col_name = col_name; + lit_comp->col_name = column_base->colname; lit_comp->constant = constant->constvalue; conditions->partitioned_literal_comps = lappend( @@ -537,23 +571,22 @@ examine_conditions(Special_Conditions *conditions, List *rtables, Node *expr_nod else if (IsA(arg2, Var)) { PGXC_Join *pgxc_join; + ColumnBase *column_base2; Var *colvar2 = (Var *) arg2; - rel_loc_info1 = GetRelationLocInfo(rte1->relid); + rel_loc_info1 = GetRelationLocInfo(column_base->relid); if (!rel_loc_info1) return false; - colvar2 = get_base_var(colvar2, rtables); - if (!colvar2) + column_base2 = get_base_var(colvar2, rtables); + if (!column_base2) return false; - rte2 = list_nth(rtables, colvar2->varno - 1); - rel_name2 = get_rel_name(rte2->relid); - rel_loc_info2 = GetRelationLocInfo(rte2->relid); + rel_loc_info2 = GetRelationLocInfo(column_base2->relid); /* get data struct about these two relations joining */ - pgxc_join = find_or_create_pgxc_join(rte1->relid, rte1->eref->aliasname, - rte2->relid, rte2->eref->aliasname); + pgxc_join = find_or_create_pgxc_join(column_base->relid, column_base->relalias, + column_base2->relid, column_base2->relalias); /* * pgxc_join->condition_list = @@ -569,7 +602,7 @@ examine_conditions(Special_Conditions *conditions, List *rtables, Node *expr_nod if (rel_loc_info2->locatorType != LOCATOR_TYPE_REPLICATED) { /* Note other relation, saves us work later. */ - conditions->base_rel_name = rel_name2; + conditions->base_rel_name = column_base2->relname; conditions->base_rel_loc_info = rel_loc_info2; if (rel_loc_info1) FreeRelationLocInfo(rel_loc_info1); @@ -577,7 +610,7 @@ examine_conditions(Special_Conditions *conditions, List *rtables, Node *expr_nod if (conditions->base_rel_name == NULL) { - conditions->base_rel_name = rel_name; + conditions->base_rel_name = column_base->relname; conditions->base_rel_loc_info = rel_loc_info1; if (rel_loc_info2) FreeRelationLocInfo(rel_loc_info2); @@ -595,7 +628,7 @@ examine_conditions(Special_Conditions *conditions, List *rtables, Node *expr_nod lappend(conditions->replicated_joins, opexpr); /* other relation not replicated, note it for later */ - conditions->base_rel_name = rel_name; + conditions->base_rel_name = column_base->relname; conditions->base_rel_loc_info = rel_loc_info1; /* note nature of join between the two relations */ @@ -613,11 +646,8 @@ examine_conditions(Special_Conditions *conditions, List *rtables, Node *expr_nod * PGXCTODO - for the prototype, we assume all partitioned * tables are on the same nodes. */ - col_name2 = strVal(list_nth(rte2->eref->colnames, - colvar2->varattno - 1)); - - if (IsHashColumn(rel_loc_info1, col_name) - && IsHashColumn(rel_loc_info2, col_name2)) + if (IsHashColumn(rel_loc_info1, column_base->colname) + && IsHashColumn(rel_loc_info2, column_base2->colname)) { /* We found a partitioned join */ conditions->partitioned_parent_child = @@ -740,13 +770,16 @@ get_plan_nodes(Query_Plan *query_plan, Query *query, bool isRead) ListCell *lc, *item; Special_Conditions *special_conditions; - OpExpr *opexpr; + OpExpr *opexpr; Var *colvar; RelationLocInfo *rel_loc_info; - Exec_Nodes *exec_nodes; - Exec_Nodes *test_exec_nodes; + Exec_Nodes *test_exec_nodes = NULL; + Exec_Nodes *exec_nodes = NULL; + Exec_Nodes *current_nodes = NULL; + Exec_Nodes *from_query_nodes = NULL; TableUsageType table_usage_type = TABLE_USAGE_TYPE_NO_TABLE; TableUsageType current_usage_type = TABLE_USAGE_TYPE_NO_TABLE; + int from_subquery_count = 0; exec_nodes = NULL; @@ -778,13 +811,11 @@ get_plan_nodes(Query_Plan *query_plan, Query *query, bool isRead) exec_nodes = (Exec_Nodes *) palloc0(sizeof(Exec_Nodes)); exec_nodes->tableusagetype = TABLE_USAGE_TYPE_PGCATALOG; free_special_relations(special_conditions); - free_join_list(); return exec_nodes; } /* complicated */ free_special_relations(special_conditions); - free_join_list(); return NULL; } } @@ -797,20 +828,49 @@ get_plan_nodes(Query_Plan *query_plan, Query *query, bool isRead) if (rte->rtekind == RTE_SUBQUERY) { + from_subquery_count++; /* * Recursively call for subqueries. * Note this also works for views, which are rewritten as subqueries. */ - Exec_Nodes *sub_nodes = get_plan_nodes(query_plan, rte->subquery, isRead); - if (sub_nodes) - current_usage_type = sub_nodes->tableusagetype; + current_nodes = get_plan_nodes(query_plan, rte->subquery, isRead); + if (current_nodes) + current_usage_type = current_nodes->tableusagetype; else { /* could be complicated */ free_special_relations(special_conditions); - free_join_list(); return NULL; } + + /* We compare to make sure that the subquery is safe to execute with previous- + * we may have multiple ones in the FROM clause. + * We handle the simple case of allowing multiple subqueries in the from clause, + * but only allow one of them to not contain replicated tables + */ + if (!from_query_nodes) + from_query_nodes = current_nodes; + else if (current_nodes->tableusagetype == TABLE_USAGE_TYPE_USER_REPLICATED) + { + /* ok, safe */ + if (!from_query_nodes) + from_query_nodes = current_nodes; + } + else + { + if (from_query_nodes->tableusagetype == TABLE_USAGE_TYPE_USER_REPLICATED) + from_query_nodes = current_nodes; + else + { + /* Allow if they are both using one node, and the same one */ + if (!same_single_node (from_query_nodes->nodelist, current_nodes->nodelist)) + { + /* Complicated */ + free_special_relations(special_conditions); + return NULL; + } + } + } } else if (rte->rtekind == RTE_RELATION) { @@ -818,7 +878,7 @@ get_plan_nodes(Query_Plan *query_plan, Query *query, bool isRead) if (get_rel_namespace(rte->relid) == PG_CATALOG_NAMESPACE) current_usage_type = TABLE_USAGE_TYPE_PGCATALOG; else - current_usage_type = TABLE_USAGE_TYPE_USER_TABLE; + current_usage_type = TABLE_USAGE_TYPE_USER; } else if (rte->rtekind == RTE_FUNCTION) { @@ -827,13 +887,17 @@ get_plan_nodes(Query_Plan *query_plan, Query *query, bool isRead) if (get_func_namespace(funcexpr->funcid) == PG_CATALOG_NAMESPACE) current_usage_type = TABLE_USAGE_TYPE_PGCATALOG; else - current_usage_type = TABLE_USAGE_TYPE_USER_TABLE; + { + //current_usage_type = TABLE_USAGE_TYPE_USER; + /* Complicated */ + free_special_relations(special_conditions); + return NULL; + } } else { /* could be complicated */ free_special_relations(special_conditions); - free_join_list(); return NULL; } @@ -844,7 +908,6 @@ get_plan_nodes(Query_Plan *query_plan, Query *query, bool isRead) { /* mixed- too complicated for us for now */ free_special_relations(special_conditions); - free_join_list(); return NULL; } } @@ -852,7 +915,6 @@ get_plan_nodes(Query_Plan *query_plan, Query *query, bool isRead) { /* could be complicated */ free_special_relations(special_conditions); - free_join_list(); return NULL; } } @@ -871,7 +933,6 @@ get_plan_nodes(Query_Plan *query_plan, Query *query, bool isRead) { /* if cross joins may exist, just return NULL */ free_special_relations(special_conditions); - free_join_list(); return NULL; } @@ -886,7 +947,6 @@ get_plan_nodes(Query_Plan *query_plan, Query *query, bool isRead) if (pgxcjoin->join_type == JOIN_OTHER) { free_special_relations(special_conditions); - free_join_list(); return NULL; } } @@ -897,36 +957,64 @@ get_plan_nodes(Query_Plan *query_plan, Query *query, bool isRead) if (special_conditions->partitioned_parent_child == NULL && special_conditions->partitioned_literal_comps == NULL) { - if (special_conditions->replicated_joins == NULL - && (query->rtable == NULL || query->rtable->length > 1)) + /* + * We have either a single table, just replicated tables, or a + * table that just joins with replicated tables, or something + * complicated. + */ - /* - * This is too complicated for a single step, or there is no FROM - * clause - */ - exec_nodes = NULL; - else + /* See if we noted a table earlier to use */ + rel_loc_info = special_conditions->base_rel_loc_info; + + if (rel_loc_info == NULL) { - /* - * We have either a single table, just replicated tables, or a - * table that just joins with replicated tables. - */ + RangeTblEntry *rtesave = NULL; - /* See if we noted a table earlier to use */ - rel_loc_info = special_conditions->base_rel_loc_info; + foreach(lc, query->rtable) + { + rte = (RangeTblEntry *) lfirst(lc); + + /* + * If the query is rewritten (which can be due to rules or views), + * ignore extra stuff. Also ignore subqueries we have processed + */ + if (!rte->inFromCl || rte->rtekind != RTE_RELATION) + continue; + + /* PGXCTODO - handle RTEs that are functions */ + if (rtesave) + /* + * Too complicated, we have multiple relations that still + * cannot be joined safely + */ + return NULL; + + rtesave = rte; + } - if (rel_loc_info == NULL) + if (rtesave) { /* a single table, just grab it */ - rte = (RangeTblEntry *) linitial(query->rtable); - rel_loc_info = GetRelationLocInfo(rte->relid); + rel_loc_info = GetRelationLocInfo(rtesave->relid); if (!rel_loc_info) return NULL; - } + exec_nodes = GetRelationNodes(rel_loc_info, NULL, isRead); + } + } + else + { exec_nodes = GetRelationNodes(rel_loc_info, NULL, isRead); - exec_nodes->tableusagetype = table_usage_type; + } + + /* Note replicated table usage for determining safe queries */ + if (exec_nodes) + { + if (table_usage_type == TABLE_USAGE_TYPE_USER && IsReplicated(rel_loc_info)) + table_usage_type = TABLE_USAGE_TYPE_USER_REPLICATED; + else + exec_nodes->tableusagetype = table_usage_type; } } /* check for partitioned col comparison against a literal */ @@ -950,15 +1038,10 @@ get_plan_nodes(Query_Plan *query_plan, Query *query, bool isRead) exec_nodes = test_exec_nodes; else { - if ((exec_nodes && list_length(exec_nodes->nodelist) > 1) - || (test_exec_nodes && list_length(test_exec_nodes->nodelist) > 1)) - /* there should only be one */ - exec_nodes = NULL; - else + if (!same_single_node(exec_nodes->nodelist, test_exec_nodes->nodelist)) { - /* Make sure they use the same nodes */ - if (linitial_int(test_exec_nodes->nodelist) != linitial_int(exec_nodes->nodelist)) - exec_nodes = NULL; + free_special_relations(special_conditions); + return NULL; } } } @@ -970,14 +1053,18 @@ get_plan_nodes(Query_Plan *query_plan, Query *query, bool isRead) * no partitioned column comparison condition with a literal. We just * use one of the tables as a basis for node determination. */ + ColumnBase *column_base; + opexpr = (OpExpr *) linitial(special_conditions->partitioned_parent_child); colvar = (Var *) linitial(opexpr->args); /* get the RangeTableEntry */ - rte = list_nth(query->rtable, colvar->varno - 1); - rel_loc_info = GetRelationLocInfo(rte->relid); + column_base = get_base_var(colvar, query->rtable); + if (!column_base) + return false; + rel_loc_info = GetRelationLocInfo(column_base->relid); if (!rel_loc_info) return false; @@ -985,7 +1072,29 @@ get_plan_nodes(Query_Plan *query_plan, Query *query, bool isRead) exec_nodes->tableusagetype = table_usage_type; } free_special_relations(special_conditions); - free_join_list(); + + if (from_query_nodes) + { + if (!exec_nodes) + return from_query_nodes; + /* Just use exec_nodes if the from subqueries are all replicated or using the exact + * same node + */ + else if (from_query_nodes->tableusagetype == TABLE_USAGE_TYPE_USER_REPLICATED + || (same_single_node(from_query_nodes->nodelist, exec_nodes->nodelist))) + return exec_nodes; + else + { + /* We allow views, where the (rewritten) subquery may be on all nodes, but the parent + * query applies a condition on the from subquery. + */ + if (list_length(query->jointree->fromlist) == from_subquery_count + && list_length(exec_nodes->nodelist) == 1) + return exec_nodes; + } + /* Too complicated, give up */ + return NULL; + } return exec_nodes; } @@ -999,26 +1108,30 @@ get_plan_nodes(Query_Plan *query_plan, Query *query, bool isRead) static Exec_Nodes * get_plan_nodes_command(Query_Plan *query_plan, Query *query) { + Exec_Nodes *exec_nodes = NULL; switch (query->commandType) { case CMD_SELECT: - return get_plan_nodes(query_plan, query, true); + exec_nodes = get_plan_nodes(query_plan, query, true); + break; case CMD_INSERT: - return get_plan_nodes_insert(query); + exec_nodes = get_plan_nodes_insert(query); + break; case CMD_UPDATE: - /* treat as a select */ - return get_plan_nodes(query_plan, query, false); - case CMD_DELETE: /* treat as a select */ - return get_plan_nodes(query_plan, query, false); + exec_nodes = get_plan_nodes(query_plan, query, false); + break; default: return NULL; } + + free_join_list(); + return exec_nodes; } @@ -1498,6 +1611,7 @@ GetQueryPlan(Node *parsetree, const char *sql_statement, List *querytree_list) case T_RemoveOpFamilyStmt: case T_TruncateStmt: case T_VariableSetStmt: + case T_ViewStmt: /* * Also support these, should help later with pg_restore, although @@ -1581,7 +1695,6 @@ GetQueryPlan(Node *parsetree, const char *sql_statement, List *querytree_list) case T_PrepareStmt: case T_RuleStmt: case T_UnlistenStmt: - case T_ViewStmt: /* fall through */ default: /* Allow for override */ diff --git a/src/include/pgxc/locator.h b/src/include/pgxc/locator.h index 5fea37a..5ead756 100644 --- a/src/include/pgxc/locator.h +++ b/src/include/pgxc/locator.h @@ -25,6 +25,7 @@ #define HASH_SIZE 4096 #define HASH_MASK 0x00000FFF; +#define IsReplicated(x) (x->locatorType == LOCATOR_TYPE_REPLICATED) #include "utils/relcache.h" @@ -47,7 +48,8 @@ typedef enum { TABLE_USAGE_TYPE_NO_TABLE, TABLE_USAGE_TYPE_PGCATALOG, - TABLE_USAGE_TYPE_USER_TABLE, + TABLE_USAGE_TYPE_USER, + TABLE_USAGE_TYPE_USER_REPLICATED, /* based on a replicated table */ TABLE_USAGE_TYPE_MIXED } TableUsageType; ----------------------------------------------------------------------- Summary of changes: src/backend/catalog/heap.c | 6 + src/backend/pgxc/plan/planner.c | 303 +++++++++++++++++++++++++++------------ src/include/pgxc/locator.h | 4 +- 3 files changed, 217 insertions(+), 96 deletions(-) hooks/post-receive -- Postgres-XC |