summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMichael P2012-01-26 00:44:45 +0000
committerMichael P2012-01-26 00:44:45 +0000
commit99cf748f6a09e6536f43e87e705ba2b4ccd96c8f (patch)
treea5657c5d5315e0ad9f0122024824ef3b35abccfe /src
parentba5f1a0be3b0688bf2a1d04eaddf714ce0e0ae50 (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.c1
-rw-r--r--src/backend/optimizer/path/allpaths.c3
-rw-r--r--src/backend/parser/analyze.c140
-rw-r--r--src/backend/parser/gram.y17
-rw-r--r--src/backend/pgxc/plan/planner.c7
-rw-r--r--src/backend/utils/adt/dbsize.c2
-rw-r--r--src/include/nodes/parsenodes.h8
-rw-r--r--src/pl/plpgsql/src/plpgsql--1.0.sql2
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;