summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/executor/spi.c74
-rw-r--r--src/backend/parser/analyze.c5
-rw-r--r--src/backend/parser/gram.y6
-rw-r--r--src/backend/utils/adt/dbsize.c5
-rw-r--r--src/include/executor/spi.h4
5 files changed, 83 insertions, 11 deletions
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index 4bfc6bc3c3..0f49a4d7cb 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -49,6 +49,10 @@ static Portal SPI_cursor_open_internal(const char *name, SPIPlanPtr plan,
static void _SPI_prepare_plan(const char *src, SPIPlanPtr plan,
ParamListInfo boundParams);
+#ifdef PGXC
+static void _SPI_pgxc_prepare_plan(const char *src, List *src_parsetree,
+ SPIPlanPtr plan, ParamListInfo boundParams);
+#endif
static int _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
Snapshot snapshot, Snapshot crosscheck_snapshot,
@@ -336,6 +340,53 @@ SPI_restore_connection(void)
_SPI_curid = _SPI_connected - 1;
}
+#ifdef PGXC
+/* SPI_execute_direct:
+ * Runs the 'remote_sql' query string on the node 'nodename'
+ * Create the ExecDirectStmt parse tree node using remote_sql, and then prepare
+ * and execute it using SPI interface.
+ * This function is essentially used for making internal exec-direct operations;
+ * and this should not require super-user privileges. We cannot run EXEC-DIRECT
+ * query because it is meant only for superusers. So this function needs to
+ * bypass the parse stage. This is achieved here by calling
+ * _SPI_pgxc_prepare_plan which accepts a parse tree.
+ */
+int
+SPI_execute_direct(const char *remote_sql, char *nodename)
+{
+ _SPI_plan plan;
+ int res;
+ ExecDirectStmt *stmt = makeNode(ExecDirectStmt);
+ StringInfoData execdirect;
+
+ initStringInfo(&execdirect);
+
+ /* This string is never used. It is just passed to fill up spierrcontext.arg */
+ appendStringInfo(&execdirect, "EXECUTE DIRECT ON %s '%s'",
+ nodename, remote_sql);
+
+ stmt->node_names = list_make1(makeString(nodename));
+ stmt->query = strdup(remote_sql);
+
+ res = _SPI_begin_call(true);
+ if (res < 0)
+ return res;
+
+ memset(&plan, 0, sizeof(_SPI_plan));
+ plan.magic = _SPI_PLAN_MAGIC;
+ plan.cursor_options = 0;
+
+ /* Now pass the ExecDirectStmt parsetree node */
+ _SPI_pgxc_prepare_plan(execdirect.data, list_make1(stmt), &plan, NULL);
+
+ res = _SPI_execute_plan(&plan, NULL,
+ InvalidSnapshot, InvalidSnapshot, false, true, 0);
+
+ _SPI_end_call(true);
+ return res;
+}
+#endif
+
/* Parse, plan, and execute a query string */
int
SPI_execute(const char *src, bool read_only, long tcount)
@@ -1665,6 +1716,20 @@ spi_printtup(TupleTableSlot *slot, DestReceiver *self)
static void
_SPI_prepare_plan(const char *src, SPIPlanPtr plan, ParamListInfo boundParams)
{
+#ifdef PGXC
+ _SPI_pgxc_prepare_plan(src, NULL, plan, boundParams);
+}
+
+/*
+ * _SPI_pgxc_prepare_plan: Optionally accepts a parsetree which allows it to
+ * bypass the parse phase, and directly analyse, rewrite and plan. Meant to be
+ * called for internally executed execute-direct statements that are
+ * transparent to the user.
+ */
+static void
+_SPI_pgxc_prepare_plan(const char *src, List *src_parsetree, SPIPlanPtr plan, ParamListInfo boundParams)
+{
+#endif
List *raw_parsetree_list;
List *plancache_list;
ListCell *list_item;
@@ -1682,8 +1747,13 @@ _SPI_prepare_plan(const char *src, SPIPlanPtr plan, ParamListInfo boundParams)
/*
* Parse the request string into a list of raw parse trees.
*/
- raw_parsetree_list = pg_parse_query(src);
-
+#ifdef PGXC
+ /* Parse it only if there isn't an already parsed tree passed */
+ if (src_parsetree)
+ raw_parsetree_list = src_parsetree;
+ else
+#endif
+ raw_parsetree_list = pg_parse_query(src);
/*
* Do parse analysis, rule rewrite, and planning for each raw parsetree,
* then cons up a phony plancache entry for each one.
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 4aa0bdaf45..2cca884b34 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -2315,11 +2315,6 @@ transformExecDirectStmt(ParseState *pstate, ExecDirectStmt *stmt)
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("Support for EXECUTE DIRECT on multiple nodes is not available yet")));
- if (!superuser())
- ereport(ERROR,
- (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must be superuser to use EXECUTE DIRECT")));
-
Assert(list_length(nodelist) == 1);
Assert(IS_PGXC_COORDINATOR);
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 9eb9f69b77..fdce3d3145 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -56,6 +56,7 @@
#include "catalog/namespace.h"
#include "catalog/pg_trigger.h"
#include "commands/defrem.h"
+#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "parser/gramparse.h"
@@ -8228,6 +8229,11 @@ ExecDirectStmt: EXECUTE DIRECT ON pgxcnode_list DirectStmt
n->node_names = $4;
n->query = $5;
$$ = (Node *)n;
+
+ if (!superuser())
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("must be superuser to use EXECUTE DIRECT")));
}
;
diff --git a/src/backend/utils/adt/dbsize.c b/src/backend/utils/adt/dbsize.c
index 4b0a9d643d..7a7d6e4c32 100644
--- a/src/backend/utils/adt/dbsize.c
+++ b/src/backend/utils/adt/dbsize.c
@@ -811,11 +811,8 @@ pgxc_execute_on_nodes(int numnodes, Oid *nodelist, char *query)
for (i = 0; i < numnodes; i++)
{
nodename = get_pgxc_nodename(nodelist[i]);
- resetStringInfo(&buf);
- appendStringInfo(&buf, "EXECUTE DIRECT ON %s %s",
- nodename, quote_literal_cstr(query));
- ret = SPI_execute(buf.data, false, 0);
+ ret = SPI_execute_direct(query, nodename);
spi_tupdesc = SPI_tuptable->tupdesc;
if (ret != SPI_OK_SELECT)
diff --git a/src/include/executor/spi.h b/src/include/executor/spi.h
index 98d194a37d..31a1e92c65 100644
--- a/src/include/executor/spi.h
+++ b/src/include/executor/spi.h
@@ -141,4 +141,8 @@ extern void SPI_cursor_close(Portal portal);
extern void AtEOXact_SPI(bool isCommit);
extern void AtEOSubXact_SPI(bool isCommit, SubTransactionId mySubid);
+#ifdef PGXC
+extern int SPI_execute_direct(const char *src, char *nodename);
+#endif
+
#endif /* SPI_H */