diff options
| author | Michael P | 2012-01-26 00:44:45 +0000 |
|---|---|---|
| committer | Michael P | 2012-01-26 00:44:45 +0000 |
| commit | 99cf748f6a09e6536f43e87e705ba2b4ccd96c8f (patch) | |
| tree | a5657c5d5315e0ad9f0122024824ef3b35abccfe /src | |
| parent | ba5f1a0be3b0688bf2a1d04eaddf714ce0e0ae50 (diff) | |
EXECUTE DIRECT: grammar simplification and filter for utility commands
For the time being only CREATE/DROP TABLESPACE are allowed through
EXECUTE DIRECT on remote nodes only. Trying to launch EXECUTE DIRECT
on local node with a utility command is still blocked.
Grammar does not have anymore COORDINATOR/NODE as keyword, now only
the node name is necessary.
Diffstat (limited to 'src')
| -rw-r--r-- | src/backend/nodes/copyfuncs.c | 1 | ||||
| -rw-r--r-- | src/backend/optimizer/path/allpaths.c | 3 | ||||
| -rw-r--r-- | src/backend/parser/analyze.c | 140 | ||||
| -rw-r--r-- | src/backend/parser/gram.y | 17 | ||||
| -rw-r--r-- | src/backend/pgxc/plan/planner.c | 7 | ||||
| -rw-r--r-- | src/backend/utils/adt/dbsize.c | 2 | ||||
| -rw-r--r-- | src/include/nodes/parsenodes.h | 8 | ||||
| -rw-r--r-- | src/pl/plpgsql/src/plpgsql--1.0.sql | 2 |
8 files changed, 113 insertions, 67 deletions
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 9da51c101b..c2fc8b2612 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -987,7 +987,6 @@ _copyExecDirect(ExecDirectStmt *from) { ExecDirectStmt *newnode = makeNode(ExecDirectStmt); - COPY_SCALAR_FIELD(coordinator); COPY_NODE_FIELD(node_names); COPY_STRING_FIELD(query); diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index aa3403a1ea..f3e28ffc40 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -285,7 +285,8 @@ set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) if (IS_PGXC_COORDINATOR && !IsConnFromCoord() && get_rel_namespace(rte->relid) != PG_CATALOG_NAMESPACE && - get_rel_relkind(rte->relid) != RELKIND_SEQUENCE) + get_rel_relkind(rte->relid) != RELKIND_SEQUENCE && + !root->parse->is_local) add_path(rel, create_remotequery_path(root, rel)); else { diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index b5c7fe03f1..21044a644d 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -44,6 +44,7 @@ #ifdef PGXC #include "miscadmin.h" #include "pgxc/pgxc.h" +#include "pgxc/pgxcnode.h" #include "access/gtm.h" #include "utils/lsyscache.h" #include "pgxc/planner.h" @@ -76,6 +77,7 @@ static Query *transformExplainStmt(ParseState *pstate, ExplainStmt *stmt); #ifdef PGXC static Query *transformExecDirectStmt(ParseState *pstate, ExecDirectStmt *stmt); +static bool IsExecDirectUtilityStmt(Node *node); #endif static void transformLockingClause(ParseState *pstate, Query *qry, @@ -2296,14 +2298,16 @@ static Query * transformExecDirectStmt(ParseState *pstate, ExecDirectStmt *stmt) { Query *result = makeNode(Query); - bool is_coordinator = stmt->coordinator; char *query = stmt->query; List *nodelist = stmt->node_names; - ListCell *nodeitem; RemoteQuery *step = makeNode(RemoteQuery); bool is_local = false; List *raw_parsetree_list; ListCell *raw_parsetree_item; + char *nodename; + Oid nodeoid; + int nodeIndex; + char nodetype; if (list_length(nodelist) > 1) ereport(ERROR, @@ -2315,24 +2319,26 @@ transformExecDirectStmt(ParseState *pstate, ExecDirectStmt *stmt) (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 nodeIndex; - char *node_name = strVal(lfirst(nodeitem)); - Oid nodeoid = get_pgxc_nodeoid(node_name); + Assert(list_length(nodelist) == 1); + Assert(IS_PGXC_COORDINATOR); - if (!OidIsValid(nodeoid)) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("PGXC Node %s: object not defined", - node_name))); + /* There is a single element here */ + nodename = strVal(linitial(nodelist)); + nodeoid = get_pgxc_nodeoid(nodename); + + if (!OidIsValid(nodeoid)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("PGXC Node %s: object not defined", + nodename))); - nodeIndex = PGXCNodeGetNodeId(nodeoid, get_pgxc_nodetype(nodeoid)); + /* Get node type and index */ + nodetype = get_pgxc_nodetype(nodeoid); + nodeIndex = PGXCNodeGetNodeId(nodeoid, get_pgxc_nodetype(nodeoid)); - if (nodeIndex == PGXCNodeId && is_coordinator) - is_local = true; - } + /* Check if node is requested is the self-node or not */ + if (nodetype == PGXC_NODE_COORDINATOR && nodeIndex == PGXCNodeId - 1) + is_local = true; /* Transform the query into a raw parse list */ raw_parsetree_list = pg_parse_query(query); @@ -2365,7 +2371,13 @@ transformExecDirectStmt(ParseState *pstate, ExecDirectStmt *stmt) step->read_only = true; step->force_autocommit = false; step->cursor = NULL; - step->exec_type = EXEC_ON_DATANODES; + + /* This is needed by executor */ + step->sql_statement = pstrdup(query); + if (nodetype == PGXC_NODE_COORDINATOR) + step->exec_type = EXEC_ON_COORDS; + else + step->exec_type = EXEC_ON_DATANODES; step->relname = NULL; step->remotejoin = false; @@ -2398,16 +2410,26 @@ transformExecDirectStmt(ParseState *pstate, ExecDirectStmt *stmt) } 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; + switch(result->commandType) + { + case CMD_UTILITY: + step->exec_direct_type = EXEC_DIRECT_UTILITY; + break; + case CMD_SELECT: + step->exec_direct_type = EXEC_DIRECT_SELECT; + break; + case CMD_INSERT: + step->exec_direct_type = EXEC_DIRECT_INSERT; + break; + case CMD_UPDATE: + step->exec_direct_type = EXEC_DIRECT_UPDATE; + break; + case CMD_DELETE: + step->exec_direct_type = EXEC_DIRECT_DELETE; + break; + default: + Assert(0); + } } /* @@ -2421,34 +2443,60 @@ transformExecDirectStmt(ParseState *pstate, ExecDirectStmt *stmt) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("EXECUTE DIRECT cannot execute DML queries"))); - if (step->exec_direct_type == EXEC_DIRECT_LOCAL_UTILITY) + else if (step->exec_direct_type == EXEC_DIRECT_UTILITY && + !IsExecDirectUtilityStmt(result->utilityStmt)) + { + /* In case this statement is an utility, check if it is authorized */ ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("EXECUTE DIRECT cannot execute locally utility queries"))); - - /* Build Execute Node list */ - foreach(nodeitem, nodelist) + errmsg("EXECUTE DIRECT cannot execute this utility query"))); + } + else if (step->exec_direct_type == EXEC_DIRECT_LOCAL_UTILITY) { - int nodeIndex; - Oid nodeoid = get_pgxc_nodeoid(strVal(lfirst(nodeitem))); - - nodeIndex = PGXCNodeGetNodeId(nodeoid, get_pgxc_nodetype(nodeoid)); - if (nodeIndex >= 0) - step->exec_nodes->nodeList = lappend_int(step->exec_nodes->nodeList, nodeIndex); + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("EXECUTE DIRECT cannot execute locally this utility query"))); } - step->sql_statement = pstrdup(query); - - if (is_coordinator) - step->exec_type = EXEC_ON_COORDS; - else - step->exec_type = EXEC_ON_DATANODES; + /* Build Execute Node list, there is a unique node for the time being */ + step->exec_nodes->nodeList = lappend_int(step->exec_nodes->nodeList, nodeIndex); /* Associate newly-created RemoteQuery node to the returned Query result */ - result->utilityStmt = (Node *) step; + result->is_local = is_local; + if (!is_local) + result->utilityStmt = (Node *) step; return result; } + +/* + * Check if given node is authorized to go through EXECUTE DURECT + */ +static bool +IsExecDirectUtilityStmt(Node *node) +{ + bool res = true; + + if (!node) + return res; + + switch(nodeTag(node)) + { + /* + * CREATE/DROP TABLESPACE are authorized to control + * tablespace at single node level. + */ + case T_CreateTableSpaceStmt: + case T_DropTableSpaceStmt: + res = true; + break; + default: + res = false; + break; + } + + return res; +} #endif /* diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 61248d17b4..f56624e369 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -8217,24 +8217,15 @@ explain_option_arg: /***************************************************************************** * * QUERY: - * EXECUTE DIRECT ON (COORDINATOR nodename, ... | NODE nodename, ...) query + * EXECUTE DIRECT ON (nodename, ...) query * *****************************************************************************/ -ExecDirectStmt: EXECUTE DIRECT ON COORDINATOR pgxcnode_list DirectStmt +ExecDirectStmt: EXECUTE DIRECT ON pgxcnode_list DirectStmt { ExecDirectStmt *n = makeNode(ExecDirectStmt); - n->coordinator = TRUE; - n->node_names = $5; - n->query = $6; - $$ = (Node *)n; - } - | EXECUTE DIRECT ON NODE pgxcnode_list DirectStmt - { - ExecDirectStmt *n = makeNode(ExecDirectStmt); - n->coordinator = FALSE; - n->node_names = $5; - n->query = $6; + n->node_names = $4; + n->query = $5; $$ = (Node *)n; } ; diff --git a/src/backend/pgxc/plan/planner.c b/src/backend/pgxc/plan/planner.c index ad43cffe97..975d92d3bb 100644 --- a/src/backend/pgxc/plan/planner.c +++ b/src/backend/pgxc/plan/planner.c @@ -3418,6 +3418,13 @@ static bool pgxc_query_needs_coord(Query *query) { /* + * In case query is local, just return here, it will be launched on + * local Coordinator by the way. + */ + if (query->is_local) + return true; + + /* * if the query has its utility set, it could be an EXEC_DIRECT statement, * check if it needs to be executed on coordinator */ diff --git a/src/backend/utils/adt/dbsize.c b/src/backend/utils/adt/dbsize.c index f17f3f040d..c326c4ac7a 100644 --- a/src/backend/utils/adt/dbsize.c +++ b/src/backend/utils/adt/dbsize.c @@ -774,7 +774,7 @@ pgxc_execute_on_nodes(int numnodes, Oid *nodelist, char *query) { nodename = get_pgxc_nodename(nodelist[i]); resetStringInfo(&buf); - appendStringInfo(&buf, "EXECUTE DIRECT ON NODE %s %s", + appendStringInfo(&buf, "EXECUTE DIRECT ON %s %s", nodename, quote_literal_cstr(query)); ret = SPI_execute(buf.data, false, 0); diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 30d414f553..09d13fbdfa 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -158,10 +158,11 @@ typedef struct Query #ifdef PGXC /* need this info for PGXC Planner, may be temporary */ char *sql_statement; /* original query */ - ExecNodes *execNodes; /* execute nodes */ + ExecNodes *execNodes; /* execute nodes */ bool qry_finalise_aggs; /* used for queries intended for datanodes, - * should datanode finalise the aggregagtes? - */ + * should datanode finalise the aggregates? */ + bool is_local; /* enforce query execution on local node + * this is used by EXECUTE DIRECT especially. */ #endif } Query; @@ -2732,7 +2733,6 @@ typedef struct AlterTSConfigurationStmt typedef struct ExecDirectStmt { NodeTag type; - bool coordinator; List *node_names; char *query; } ExecDirectStmt; diff --git a/src/pl/plpgsql/src/plpgsql--1.0.sql b/src/pl/plpgsql/src/plpgsql--1.0.sql index 6c4efd35c6..e8d68deca5 100644 --- a/src/pl/plpgsql/src/plpgsql--1.0.sql +++ b/src/pl/plpgsql/src/plpgsql--1.0.sql @@ -24,7 +24,7 @@ DECLARE --Get all the node names query_str_nodes := 'SELECT node_name FROM pgxc_node WHERE node_type = ''D'''; FOR row_name IN EXECUTE(query_str_nodes) LOOP - query_str := 'EXECUTE DIRECT ON NODE ' || row_name.node_name || ' ''SELECT gid FROM pg_prepared_xact()'''; + query_str := 'EXECUTE DIRECT ON ' || row_name.node_name || ' ''SELECT gid FROM pg_prepared_xact()'''; FOR row_data IN EXECUTE(query_str) LOOP return next row_data.gid; END LOOP; |
