diff options
| -rw-r--r-- | doc-xc/src/sgml/ref/create_tablespace.sgmlin | 7 | ||||
| -rw-r--r-- | doc-xc/src/sgml/ref/drop_tablespace.sgmlin | 9 | ||||
| -rw-r--r-- | doc-xc/src/sgml/ref/execute_direct.sgmlin | 41 | ||||
| -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 |
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; |
