diff options
| -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 */ |
