summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAmit Khandekar2012-04-30 14:03:17 +0000
committerAmit Khandekar2012-04-30 14:03:17 +0000
commit26e073f38d8a301c8f5de116613c6459903a50df (patch)
tree192bd89c1bc4d377deea614e46e5b760e9115c9b
parent64f749fcd29cacca13ed28996c2275333a348cb3 (diff)
Fix for Bug 3498157 : pg_relation_size bug
For exec-direct, the super-user restriction is applied in parse/analyse phase. So, create SPI function SPI_execute_direct() specially to allow running internal SQLs directly on other nodes, transparent to the user. This function bypasses the parsing stage by creating an ExecDirectStmt node manually and then does the usual analyze, rewrite, plan and execute using the usual SPI interface functions. This allows us to bypass the super-user restriction which is now shifted from analyze phase to parse phase. So for this release 1.0 we leave the exec-direct super-user restriction, but allow to propagate SQLs to other nodes through backend code. This prevents normal users from accidentally doing table writes using exec-direct but at the same time allows transparently to propagate system functions like pg_relation_size, pg_advisory_lock() etc to be propagated to coordinators and/or datanodes transparently.
-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 */