v1-0002-add-spi-prepare-extended.patch
text/x-diff
Filename: v1-0002-add-spi-prepare-extended.patch
Type: text/x-diff
Part: 1
Patch
Format: unified
Series: patch v1-0002
| File | + | − |
|---|---|---|
| doc/src/sgml/spi.sgml | 126 | 0 |
| src/backend/executor/spi.c | 49 | 3 |
| src/include/executor/spi.h | 12 | 1 |
| src/include/executor/spi_priv.h | 1 | 0 |
| src/pl/plpgsql/src/pl_exec.c | 8 | 5 |
diff --git a/doc/src/sgml/spi.sgml b/doc/src/sgml/spi.sgml
index 7752de0a4d..f0dcba946e 100644
--- a/doc/src/sgml/spi.sgml
+++ b/doc/src/sgml/spi.sgml
@@ -1105,6 +1105,11 @@ SPIPlanPtr SPI_prepare_cursor(const char * <parameter>command</parameter>, int <
for the <structfield>options</structfield> field of <structname>DeclareCursorStmt</structname>.
<function>SPI_prepare</function> always takes the cursor options as zero.
</para>
+
+ <para>
+ This function is now deprecated in favor
+ of <function>SPI_prepare_extended</function>.
+ </para>
</refsect1>
<refsect1>
@@ -1176,6 +1181,122 @@ SPIPlanPtr SPI_prepare_cursor(const char * <parameter>command</parameter>, int <
<!-- *********************************************** -->
+<refentry id="spi-spi-prepare-extended">
+ <indexterm><primary>SPI_prepare_extended</primary></indexterm>
+
+ <refmeta>
+ <refentrytitle>SPI_prepare_extended</refentrytitle>
+ <manvolnum>3</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname>SPI_prepare_extended</refname>
+ <refpurpose>prepare a statement, without executing it yet</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+<synopsis>
+SPIPlanPtr SPI_prepare_extended(const char * <parameter>command</parameter>,
+ const SPIPrepareOptions * <parameter>options</parameter>)
+</synopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>
+ <function>SPI_prepare_extended</function> creates and returns a prepared
+ statement for the specified command, but doesn't execute the command.
+ This function is equivalent to <function>SPI_prepare</function>,
+ with the addition that the caller can specify options to control
+ the parsing of external parameter references, as well as other facets
+ of query parsing and planning.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Arguments</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><literal>const char * <parameter>command</parameter></literal></term>
+ <listitem>
+ <para>
+ command string
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>const SPIPrepareOptions * <parameter>options</parameter></literal></term>
+ <listitem>
+ <para>
+ struct containing optional arguments
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ <para>
+ Callers should always zero out the entire <parameter>options</parameter>
+ struct, then fill whichever fields they want to set. This ensures forward
+ compatibility of code, since any fields that are added to the struct in
+ future will be defined to behave backwards-compatibly if they are zero.
+ The currently available <parameter>options</parameter> fields are:
+ </para>
+
+ <variablelist>
+ <varlistentry>
+ <term><literal>ParserSetupHook <parameter>parserSetup</parameter></literal></term>
+ <listitem>
+ <para>
+ Parser hook setup function
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>void * <parameter>parserSetupArg</parameter></literal></term>
+ <listitem>
+ <para>
+ pass-through argument for <parameter>parserSetup</parameter>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>RawParseMode <parameter>parseMode</parameter></literal></term>
+ <listitem>
+ <para>
+ mode for raw parsing; <literal>RAW_PARSE_DEFAULT</literal> (zero)
+ produces default behavior
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>int <parameter>cursorOptions</parameter></literal></term>
+ <listitem>
+ <para>
+ integer bit mask of cursor options; zero produces default behavior
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Return Value</title>
+
+ <para>
+ <function>SPI_prepare_extended</function> has the same return conventions as
+ <function>SPI_prepare</function>.
+ </para>
+ </refsect1>
+</refentry>
+
+<!-- *********************************************** -->
+
<refentry id="spi-spi-prepare-params">
<indexterm><primary>SPI_prepare_params</primary></indexterm>
@@ -1208,6 +1329,11 @@ SPIPlanPtr SPI_prepare_params(const char * <parameter>command</parameter>,
with the addition that the caller can specify parser hook functions
to control the parsing of external parameter references.
</para>
+
+ <para>
+ This function is now deprecated in favor
+ of <function>SPI_prepare_extended</function>.
+ </para>
</refsect1>
<refsect1>
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index 055ebb77ae..3acf88e67c 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -508,6 +508,7 @@ SPI_execute(const char *src, bool read_only, long tcount)
memset(&plan, 0, sizeof(_SPI_plan));
plan.magic = _SPI_PLAN_MAGIC;
+ plan.parse_mode = RAW_PARSE_DEFAULT;
plan.cursor_options = CURSOR_OPT_PARALLEL_OK;
_SPI_prepare_oneshot_plan(src, &plan);
@@ -681,6 +682,7 @@ SPI_execute_with_args(const char *src,
memset(&plan, 0, sizeof(_SPI_plan));
plan.magic = _SPI_PLAN_MAGIC;
+ plan.parse_mode = RAW_PARSE_DEFAULT;
plan.cursor_options = CURSOR_OPT_PARALLEL_OK;
plan.nargs = nargs;
plan.argtypes = argtypes;
@@ -726,6 +728,7 @@ SPI_execute_with_receiver(const char *src,
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)
{
@@ -768,6 +771,7 @@ SPI_prepare_cursor(const char *src, int nargs, Oid *argtypes,
memset(&plan, 0, sizeof(_SPI_plan));
plan.magic = _SPI_PLAN_MAGIC;
+ plan.parse_mode = RAW_PARSE_DEFAULT;
plan.cursor_options = cursorOptions;
plan.nargs = nargs;
plan.argtypes = argtypes;
@@ -784,6 +788,42 @@ SPI_prepare_cursor(const char *src, int nargs, Oid *argtypes,
return result;
}
+SPIPlanPtr
+SPI_prepare_extended(const char *src,
+ const SPIPrepareOptions *options)
+{
+ _SPI_plan plan;
+ SPIPlanPtr result;
+
+ if (src == NULL || options == NULL)
+ {
+ SPI_result = SPI_ERROR_ARGUMENT;
+ return NULL;
+ }
+
+ SPI_result = _SPI_begin_call(true);
+ if (SPI_result < 0)
+ return NULL;
+
+ memset(&plan, 0, sizeof(_SPI_plan));
+ plan.magic = _SPI_PLAN_MAGIC;
+ plan.parse_mode = options->parseMode;
+ plan.cursor_options = options->cursorOptions;
+ plan.nargs = 0;
+ plan.argtypes = NULL;
+ plan.parserSetup = options->parserSetup;
+ plan.parserSetupArg = options->parserSetupArg;
+
+ _SPI_prepare_plan(src, &plan);
+
+ /* copy plan to procedure context */
+ result = _SPI_make_plan_non_temp(&plan);
+
+ _SPI_end_call(true);
+
+ return result;
+}
+
SPIPlanPtr
SPI_prepare_params(const char *src,
ParserSetupHook parserSetup,
@@ -805,6 +845,7 @@ SPI_prepare_params(const char *src,
memset(&plan, 0, sizeof(_SPI_plan));
plan.magic = _SPI_PLAN_MAGIC;
+ plan.parse_mode = RAW_PARSE_DEFAULT;
plan.cursor_options = cursorOptions;
plan.nargs = 0;
plan.argtypes = NULL;
@@ -1340,6 +1381,7 @@ SPI_cursor_open_with_args(const char *name,
memset(&plan, 0, sizeof(_SPI_plan));
plan.magic = _SPI_PLAN_MAGIC;
+ plan.parse_mode = RAW_PARSE_DEFAULT;
plan.cursor_options = cursorOptions;
plan.nargs = nargs;
plan.argtypes = argtypes;
@@ -1400,6 +1442,7 @@ SPI_cursor_parse_open_with_paramlist(const char *name,
memset(&plan, 0, sizeof(_SPI_plan));
plan.magic = _SPI_PLAN_MAGIC;
+ plan.parse_mode = RAW_PARSE_DEFAULT;
plan.cursor_options = cursorOptions;
if (params)
{
@@ -2036,7 +2079,8 @@ spi_printtup(TupleTableSlot *slot, DestReceiver *self)
* Parse and analyze a querystring.
*
* At entry, plan->argtypes and plan->nargs (or alternatively plan->parserSetup
- * and plan->parserSetupArg) must be valid, as must plan->cursor_options.
+ * and plan->parserSetupArg) must be valid, as must plan->parse_mode and
+ * plan->cursor_options.
*
* Results are stored into *plan (specifically, plan->plancache_list).
* Note that the result data is all in CurrentMemoryContext or child contexts
@@ -2063,7 +2107,7 @@ _SPI_prepare_plan(const char *src, SPIPlanPtr plan)
/*
* Parse the request string into a list of raw parse trees.
*/
- raw_parsetree_list = pg_parse_query(src);
+ raw_parsetree_list = raw_parser(src, plan->parse_mode);
/*
* Do parse analysis and rule rewrite for each raw parsetree, storing the
@@ -2168,7 +2212,7 @@ _SPI_prepare_oneshot_plan(const char *src, SPIPlanPtr plan)
/*
* Parse the request string into a list of raw parse trees.
*/
- raw_parsetree_list = pg_parse_query(src);
+ raw_parsetree_list = raw_parser(src, plan->parse_mode);
/*
* Construct plancache entries, but don't do parse analysis yet.
@@ -2866,6 +2910,7 @@ _SPI_make_plan_non_temp(SPIPlanPtr plan)
newplan = (SPIPlanPtr) palloc0(sizeof(_SPI_plan));
newplan->magic = _SPI_PLAN_MAGIC;
newplan->plancxt = plancxt;
+ newplan->parse_mode = plan->parse_mode;
newplan->cursor_options = plan->cursor_options;
newplan->nargs = plan->nargs;
if (plan->nargs > 0)
@@ -2930,6 +2975,7 @@ _SPI_save_plan(SPIPlanPtr plan)
newplan = (SPIPlanPtr) palloc0(sizeof(_SPI_plan));
newplan->magic = _SPI_PLAN_MAGIC;
newplan->plancxt = plancxt;
+ newplan->parse_mode = plan->parse_mode;
newplan->cursor_options = plan->cursor_options;
newplan->nargs = plan->nargs;
if (plan->nargs > 0)
diff --git a/src/include/executor/spi.h b/src/include/executor/spi.h
index 896ec0a2ad..8ff4236c8f 100644
--- a/src/include/executor/spi.h
+++ b/src/include/executor/spi.h
@@ -15,7 +15,7 @@
#include "commands/trigger.h"
#include "lib/ilist.h"
-#include "nodes/parsenodes.h"
+#include "parser/parser.h"
#include "utils/portal.h"
@@ -33,6 +33,15 @@ typedef struct SPITupleTable
SubTransactionId subid; /* subxact in which tuptable was created */
} SPITupleTable;
+/* Optional arguments for SPI_prepare_extended */
+typedef struct SPIPrepareOptions
+{
+ ParserSetupHook parserSetup;
+ void *parserSetupArg;
+ RawParseMode parseMode;
+ int cursorOptions;
+} SPIPrepareOptions;
+
/* Plans are opaque structs for standard users of SPI */
typedef struct _SPI_plan *SPIPlanPtr;
@@ -113,6 +122,8 @@ extern int SPI_execute_with_receiver(const char *src,
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);
+extern SPIPlanPtr SPI_prepare_extended(const char *src,
+ const SPIPrepareOptions *options);
extern SPIPlanPtr SPI_prepare_params(const char *src,
ParserSetupHook parserSetup,
void *parserSetupArg,
diff --git a/src/include/executor/spi_priv.h b/src/include/executor/spi_priv.h
index 6220928bd3..9c99aeb84e 100644
--- a/src/include/executor/spi_priv.h
+++ b/src/include/executor/spi_priv.h
@@ -95,6 +95,7 @@ typedef struct _SPI_plan
bool no_snapshots; /* let the caller handle the snapshots */
List *plancache_list; /* one CachedPlanSource per parsetree */
MemoryContext plancxt; /* Context containing _SPI_plan and data */
+ RawParseMode parse_mode; /* raw_parser() mode */
int cursor_options; /* Cursor options used for planning */
int nargs; /* number of plan arguments */
Oid *argtypes; /* Argument types (NULL if nargs is 0) */
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index ccbc50fc45..86f5e9fd24 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -4170,6 +4170,7 @@ exec_prepare_plan(PLpgSQL_execstate *estate,
bool keepplan)
{
SPIPlanPtr plan;
+ SPIPrepareOptions options;
/*
* The grammar can't conveniently set expr->func while building the parse
@@ -4180,12 +4181,14 @@ exec_prepare_plan(PLpgSQL_execstate *estate,
/*
* Generate and save the plan
*/
- plan = SPI_prepare_params(expr->query,
- (ParserSetupHook) plpgsql_parser_setup,
- (void *) expr,
- cursorOptions);
+ memset(&options, 0, sizeof(options));
+ options.parserSetup = (ParserSetupHook) plpgsql_parser_setup;
+ options.parserSetupArg = (void *) expr;
+ options.parseMode = RAW_PARSE_DEFAULT;
+ options.cursorOptions = cursorOptions;
+ plan = SPI_prepare_extended(expr->query, &options);
if (plan == NULL)
- elog(ERROR, "SPI_prepare_params failed for \"%s\": %s",
+ elog(ERROR, "SPI_prepare_extended failed for \"%s\": %s",
expr->query, SPI_result_code_string(SPI_result));
if (keepplan)
SPI_keepplan(plan);