summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc-xc/src/sgml/ref/create_tablespace.sgmlin7
-rw-r--r--doc-xc/src/sgml/ref/drop_tablespace.sgmlin9
-rw-r--r--doc-xc/src/sgml/ref/execute_direct.sgmlin41
-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
11 files changed, 140 insertions, 97 deletions
diff --git a/doc-xc/src/sgml/ref/create_tablespace.sgmlin b/doc-xc/src/sgml/ref/create_tablespace.sgmlin
index eb79ca53b9..39be9b32d2 100644
--- a/doc-xc/src/sgml/ref/create_tablespace.sgmlin
+++ b/doc-xc/src/sgml/ref/create_tablespace.sgmlin
@@ -116,6 +116,13 @@ CREATE TABLESPACE <replaceable class="parameter">tablespace_name</replaceable> [
user needs to have permission to the same location path on all the servers
involved in the cluster.
</para>
+
+ <para>
+ <command>CREATE TABLESPACE</> can be run with EXECUTE DIRECT to control
+ tablespace existence on remote nodes. This works for both remote Coordinators
+ and Datanodes but not on this operation is not authorized on node where
+ application client is connected.
+ </para>
<!## end>
</refsect1>
diff --git a/doc-xc/src/sgml/ref/drop_tablespace.sgmlin b/doc-xc/src/sgml/ref/drop_tablespace.sgmlin
index 1e320d0584..6d3fb1e3f3 100644
--- a/doc-xc/src/sgml/ref/drop_tablespace.sgmlin
+++ b/doc-xc/src/sgml/ref/drop_tablespace.sgmlin
@@ -78,6 +78,15 @@ DROP TABLESPACE [ IF EXISTS ] <replaceable class="PARAMETER">tablespace_name</re
<para>
<command>DROP TABLESPACE</> cannot be executed inside a transaction block.
</para>
+
+<!## XC>
+ <para>
+ <command>DROP TABLESPACE</> can be run with EXECUTE DIRECT to control
+ tablespace existence on remote nodes. This works for both remote Coordinators
+ and Datanodes but not on this operation is not authorized on node where
+ application client is connected.
+ </para>
+<!## end>
</refsect1>
diff --git a/doc-xc/src/sgml/ref/execute_direct.sgmlin b/doc-xc/src/sgml/ref/execute_direct.sgmlin
index 6696f5b9fc..84b3659b68 100644
--- a/doc-xc/src/sgml/ref/execute_direct.sgmlin
+++ b/doc-xc/src/sgml/ref/execute_direct.sgmlin
@@ -21,8 +21,7 @@ PostgreSQL documentation
<refsynopsisdiv>
<synopsis>
-EXECUTE DIRECT ON
-( COORDINATOR <replaceable class="parameter">nodename</replaceable> [, ... ] | NODE <replaceable class="parameter">nodename</replaceable> [, ... ] )
+EXECUTE DIRECT ON <replaceable class="parameter">nodename</replaceable> [, ... ]
<replaceable class="parameter">query</replaceable>
</synopsis>
</refsynopsisdiv>
@@ -50,10 +49,12 @@ EXECUTE DIRECT ON
</para>
<para>
- The user may use <literal>COORDINATOR</literal> to launch the wanted
- <replaceable class="parameter">query</replaceable> on a Postgres-XC
- Coordinator and <literal>NODE</literal> to do the same on a Postgres-XC
- Datanode.
+ Either Coordinator or Datanode can be selected by its node name.
+ </para>
+
+ <para>
+ <command>EXECUTE DIRECT</> allows the usage of the following utility commands
+ on remote nodes: <command>CREATE TABLESPACE</>, <command>DROP TABLESPACE</>.
</para>
</refsect1>
@@ -63,26 +64,6 @@ EXECUTE DIRECT ON
<variablelist>
<varlistentry>
- <term><literal>COORDINATOR</literal></term>
- <listitem>
- <para>
- This option is mandatory when designing a Coordinator node. <literal>
- NODE</literal> can be used instead, it is not necessary to specify it.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term><literal>NODE</literal></term>
- <listitem>
- <para>
- This option is mandatory when designing a Datanode node. <literal>
- COORDINATOR</literal> can be used instead, it is not necessary to specify it.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
<term><replaceable class="parameter">nodename</replaceable></term>
<listitem>
<para>
@@ -116,16 +97,16 @@ EXECUTE DIRECT ON NODE dn1 'SELECT * FROM tenk1 WHERE col_char = ''foo''';
</para>
<para>
- Select local timestamp of a remote Coordinator named coord2:
+ Select local timestamp of a remote node named coord2:
<programlisting>
-EXECUTE DIRECT ON COORDINATOR coord2 'select clock_timestamp()';
+EXECUTE DIRECT ON coord2 'select clock_timestamp()';
</programlisting>
</para>
<para>
- Select list of tables of a remote Datanode named dn50:
+ Select list of tables of a remote node named dn50:
<programlisting>
-EXECUTE DIRECT ON NODE dn50 'select tablename from pg_tables';
+EXECUTE DIRECT ON dn50 'select tablename from pg_tables';
</programlisting>
</para>
</refsect1>
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;