summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2021-01-26 16:37:12 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2021-01-26 16:37:12 -0500
commitd5a83d79c9f9b660a6a5a77afafe146d3c8c6f46 (patch)
treee0c3626c5bd5369cf1433a42a1db1d9df9dd53ba /src
parent7292fd8f1c781278021407276474d9188845113d (diff)
downloadpostgresql-d5a83d79c9f9b660a6a5a77afafe146d3c8c6f46.tar.gz
Rethink recently-added SPI interfaces.
SPI_execute_with_receiver and SPI_cursor_parse_open_with_paramlist are new in v14 (cf. commit 2f48ede08). Before they can get out the door, let's change their APIs to follow the practice recently established by SPI_prepare_extended etc: shove all optional arguments into a struct that callers are supposed to pre-zero. The hope is to allow future addition of more options without either API breakage or a continuing proliferation of new SPI entry points. With that in mind, choose slightly more generic names for them: SPI_execute_extended and SPI_cursor_parse_open respectively. Discussion: https://postgr.es/m/CAFj8pRCLPdDAETvR7Po7gC5y_ibkn_-bOzbeJb39WHms01194Q@mail.gmail.com
Diffstat (limited to 'src')
-rw-r--r--src/backend/executor/spi.c114
-rw-r--r--src/include/executor/spi.h24
-rw-r--r--src/pl/plpgsql/src/pl_exec.c46
3 files changed, 91 insertions, 93 deletions
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index 68a6bcea02..00aa78ea53 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -538,6 +538,43 @@ SPI_exec(const char *src, long tcount)
return SPI_execute(src, false, tcount);
}
+/* Parse, plan, and execute a query string, with extensible options */
+int
+SPI_execute_extended(const char *src,
+ const SPIExecuteOptions *options)
+{
+ int res;
+ _SPI_plan plan;
+
+ if (src == NULL || options == NULL)
+ return SPI_ERROR_ARGUMENT;
+
+ res = _SPI_begin_call(true);
+ if (res < 0)
+ return res;
+
+ memset(&plan, 0, sizeof(_SPI_plan));
+ plan.magic = _SPI_PLAN_MAGIC;
+ plan.parse_mode = RAW_PARSE_DEFAULT;
+ plan.cursor_options = CURSOR_OPT_PARALLEL_OK;
+ if (options->params)
+ {
+ plan.parserSetup = options->params->parserSetup;
+ plan.parserSetupArg = options->params->parserSetupArg;
+ }
+
+ _SPI_prepare_oneshot_plan(src, &plan);
+
+ res = _SPI_execute_plan(&plan, options->params,
+ InvalidSnapshot, InvalidSnapshot,
+ options->read_only, options->no_snapshots,
+ true, options->tcount,
+ options->dest, options->owner);
+
+ _SPI_end_call(true);
+ return res;
+}
+
/* Execute a previously prepared plan */
int
SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls,
@@ -715,52 +752,6 @@ SPI_execute_with_args(const char *src,
return res;
}
-/*
- * SPI_execute_with_receiver -- plan and execute a query with arguments
- *
- * This is the same as SPI_execute_with_args except that parameters are
- * supplied through a ParamListInfo, and (if dest isn't NULL) we send
- * result tuples to the caller-supplied DestReceiver rather than through
- * the usual SPI output arrangements.
- */
-int
-SPI_execute_with_receiver(const char *src,
- ParamListInfo params,
- bool read_only, long tcount,
- DestReceiver *dest)
-{
- int res;
- _SPI_plan plan;
-
- if (src == NULL || tcount < 0)
- return SPI_ERROR_ARGUMENT;
-
- res = _SPI_begin_call(true);
- if (res < 0)
- return res;
-
- memset(&plan, 0, sizeof(_SPI_plan));
- plan.magic = _SPI_PLAN_MAGIC;
- plan.parse_mode = RAW_PARSE_DEFAULT;
- plan.cursor_options = CURSOR_OPT_PARALLEL_OK;
- if (params)
- {
- plan.parserSetup = params->parserSetup;
- plan.parserSetupArg = params->parserSetupArg;
- }
-
- _SPI_prepare_oneshot_plan(src, &plan);
-
- res = _SPI_execute_plan(&plan, params,
- InvalidSnapshot, InvalidSnapshot,
- read_only, false,
- true, tcount,
- dest, NULL);
-
- _SPI_end_call(true);
- return res;
-}
-
SPIPlanPtr
SPI_prepare(const char *src, int nargs, Oid *argtypes)
{
@@ -1433,43 +1424,38 @@ SPI_cursor_open_with_paramlist(const char *name, SPIPlanPtr plan,
return SPI_cursor_open_internal(name, plan, params, read_only);
}
-/*
- * SPI_cursor_parse_open_with_paramlist()
- *
- * Same as SPI_cursor_open_with_args except that parameters (if any) are passed
- * as a ParamListInfo, which supports dynamic parameter set determination
- */
+/* Parse a query and open it as a cursor */
Portal
-SPI_cursor_parse_open_with_paramlist(const char *name,
- const char *src,
- ParamListInfo params,
- bool read_only, int cursorOptions)
+SPI_cursor_parse_open(const char *name,
+ const char *src,
+ const SPIParseOpenOptions *options)
{
Portal result;
_SPI_plan plan;
- if (src == NULL)
- elog(ERROR, "SPI_cursor_parse_open_with_paramlist called with invalid arguments");
+ if (src == NULL || options == NULL)
+ elog(ERROR, "SPI_cursor_parse_open called with invalid arguments");
SPI_result = _SPI_begin_call(true);
if (SPI_result < 0)
- elog(ERROR, "SPI_cursor_parse_open_with_paramlist called while not connected");
+ elog(ERROR, "SPI_cursor_parse_open called while not connected");
memset(&plan, 0, sizeof(_SPI_plan));
plan.magic = _SPI_PLAN_MAGIC;
plan.parse_mode = RAW_PARSE_DEFAULT;
- plan.cursor_options = cursorOptions;
- if (params)
+ plan.cursor_options = options->cursorOptions;
+ if (options->params)
{
- plan.parserSetup = params->parserSetup;
- plan.parserSetupArg = params->parserSetupArg;
+ plan.parserSetup = options->params->parserSetup;
+ plan.parserSetupArg = options->params->parserSetupArg;
}
_SPI_prepare_plan(src, &plan);
/* We needn't copy the plan; SPI_cursor_open_internal will do so */
- result = SPI_cursor_open_internal(name, &plan, params, read_only);
+ result = SPI_cursor_open_internal(name, &plan,
+ options->params, options->read_only);
/* And clean up */
_SPI_end_call(true);
diff --git a/src/include/executor/spi.h b/src/include/executor/spi.h
index 5740f8956e..6455d100f5 100644
--- a/src/include/executor/spi.h
+++ b/src/include/executor/spi.h
@@ -42,7 +42,7 @@ typedef struct SPIPrepareOptions
int cursorOptions;
} SPIPrepareOptions;
-/* Optional arguments for SPI_execute_plan_extended */
+/* Optional arguments for SPI_execute[_plan]_extended */
typedef struct SPIExecuteOptions
{
ParamListInfo params;
@@ -53,6 +53,14 @@ typedef struct SPIExecuteOptions
ResourceOwner owner;
} SPIExecuteOptions;
+/* Optional arguments for SPI_cursor_parse_open */
+typedef struct SPIParseOpenOptions
+{
+ ParamListInfo params;
+ int cursorOptions;
+ bool read_only;
+} SPIParseOpenOptions;
+
/* Plans are opaque structs for standard users of SPI */
typedef struct _SPI_plan *SPIPlanPtr;
@@ -105,6 +113,8 @@ extern int SPI_connect(void);
extern int SPI_connect_ext(int options);
extern int SPI_finish(void);
extern int SPI_execute(const char *src, bool read_only, long tcount);
+extern int SPI_execute_extended(const char *src,
+ const SPIExecuteOptions *options);
extern int SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls,
bool read_only, long tcount);
extern int SPI_execute_plan_extended(SPIPlanPtr plan,
@@ -124,10 +134,6 @@ extern int SPI_execute_with_args(const char *src,
int nargs, Oid *argtypes,
Datum *Values, const char *Nulls,
bool read_only, long tcount);
-extern int SPI_execute_with_receiver(const char *src,
- ParamListInfo params,
- bool read_only, long tcount,
- DestReceiver *dest);
extern SPIPlanPtr SPI_prepare(const char *src, int nargs, Oid *argtypes);
extern SPIPlanPtr SPI_prepare_cursor(const char *src, int nargs, Oid *argtypes,
int cursorOptions);
@@ -178,11 +184,9 @@ extern Portal SPI_cursor_open_with_args(const char *name,
bool read_only, int cursorOptions);
extern Portal SPI_cursor_open_with_paramlist(const char *name, SPIPlanPtr plan,
ParamListInfo params, bool read_only);
-extern Portal SPI_cursor_parse_open_with_paramlist(const char *name,
- const char *src,
- ParamListInfo params,
- bool read_only,
- int cursorOptions);
+extern Portal SPI_cursor_parse_open(const char *name,
+ const char *src,
+ const SPIParseOpenOptions *options);
extern Portal SPI_cursor_find(const char *name);
extern void SPI_cursor_fetch(Portal portal, bool forward, long count);
extern void SPI_cursor_move(Portal portal, bool forward, long count);
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index 383d92fc1d..b4c70aaa7f 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -3603,6 +3603,7 @@ exec_stmt_return_query(PLpgSQL_execstate *estate,
Oid restype;
int32 restypmod;
char *querystr;
+ SPIExecuteOptions options;
/*
* Evaluate the string expression after the EXECUTE keyword. Its
@@ -3625,14 +3626,15 @@ exec_stmt_return_query(PLpgSQL_execstate *estate,
exec_eval_cleanup(estate);
/* Execute query, passing params if necessary */
- rc = SPI_execute_with_receiver(querystr,
- exec_eval_using_params(estate,
- stmt->params),
- estate->readonly_func,
- 0,
- treceiver);
+ memset(&options, 0, sizeof(options));
+ options.params = exec_eval_using_params(estate,
+ stmt->params);
+ options.read_only = estate->readonly_func;
+ options.dest = treceiver;
+
+ rc = SPI_execute_extended(querystr, &options);
if (rc < 0)
- elog(ERROR, "SPI_execute_with_receiver failed executing query \"%s\": %s",
+ elog(ERROR, "SPI_execute_extended failed executing query \"%s\": %s",
querystr, SPI_result_code_string(rc));
}
@@ -4402,6 +4404,7 @@ exec_stmt_dynexecute(PLpgSQL_execstate *estate,
char *querystr;
int exec_res;
ParamListInfo paramLI;
+ SPIExecuteOptions options;
MemoryContext stmt_mcontext = get_stmt_mcontext(estate);
/*
@@ -4426,8 +4429,12 @@ exec_stmt_dynexecute(PLpgSQL_execstate *estate,
* Execute the query without preparing a saved plan.
*/
paramLI = exec_eval_using_params(estate, stmt->params);
- exec_res = SPI_execute_with_receiver(querystr, paramLI,
- estate->readonly_func, 0, NULL);
+
+ memset(&options, 0, sizeof(options));
+ options.params = paramLI;
+ options.read_only = estate->readonly_func;
+
+ exec_res = SPI_execute_extended(querystr, &options);
switch (exec_res)
{
@@ -4479,7 +4486,7 @@ exec_stmt_dynexecute(PLpgSQL_execstate *estate,
break;
default:
- elog(ERROR, "SPI_execute_with_receiver failed executing query \"%s\": %s",
+ elog(ERROR, "SPI_execute_extended failed executing query \"%s\": %s",
querystr, SPI_result_code_string(exec_res));
break;
}
@@ -8582,6 +8589,7 @@ exec_dynquery_with_params(PLpgSQL_execstate *estate,
Oid restype;
int32 restypmod;
char *querystr;
+ SPIParseOpenOptions options;
MemoryContext stmt_mcontext = get_stmt_mcontext(estate);
/*
@@ -8603,16 +8611,16 @@ exec_dynquery_with_params(PLpgSQL_execstate *estate,
exec_eval_cleanup(estate);
/*
- * Open an implicit cursor for the query. We use
- * SPI_cursor_parse_open_with_paramlist even when there are no params,
- * because this avoids making and freeing one copy of the plan.
+ * Open an implicit cursor for the query. We use SPI_cursor_parse_open
+ * even when there are no params, because this avoids making and freeing
+ * one copy of the plan.
*/
- portal = SPI_cursor_parse_open_with_paramlist(portalname,
- querystr,
- exec_eval_using_params(estate,
- params),
- estate->readonly_func,
- cursorOptions);
+ memset(&options, 0, sizeof(options));
+ options.params = exec_eval_using_params(estate, params);
+ options.cursorOptions = cursorOptions;
+ options.read_only = estate->readonly_func;
+
+ portal = SPI_cursor_parse_open(portalname, querystr, &options);
if (portal == NULL)
elog(ERROR, "could not open implicit cursor for query \"%s\": %s",