diff options
| author | Amit Khandekar | 2012-04-30 14:03:17 +0000 |
|---|---|---|
| committer | Amit Khandekar | 2012-04-30 14:03:17 +0000 |
| commit | 26e073f38d8a301c8f5de116613c6459903a50df (patch) | |
| tree | 192bd89c1bc4d377deea614e46e5b760e9115c9b | |
| parent | 64f749fcd29cacca13ed28996c2275333a348cb3 (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.c | 74 | ||||
| -rw-r--r-- | src/backend/parser/analyze.c | 5 | ||||
| -rw-r--r-- | src/backend/parser/gram.y | 6 | ||||
| -rw-r--r-- | src/backend/utils/adt/dbsize.c | 5 | ||||
| -rw-r--r-- | src/include/executor/spi.h | 4 |
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 */ |
