Rethink recently-added SPI interfaces.
authorTom Lane <[email protected]>
Tue, 26 Jan 2021 21:37:12 +0000 (16:37 -0500)
committerTom Lane <[email protected]>
Tue, 26 Jan 2021 21:37:12 +0000 (16:37 -0500)
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

doc/src/sgml/spi.sgml
src/backend/executor/spi.c
src/include/executor/spi.h
src/pl/plpgsql/src/pl_exec.c

index d8c121f5f355f9738bdd408db49cc6a3d03d86e1..6543eaa03435b736038300cf5b0931198df9788c 100644 (file)
@@ -632,25 +632,23 @@ int SPI_exec(const char * <parameter>command</parameter>, long <parameter>count<
 
 <!-- *********************************************** -->
 
-<refentry id="spi-spi-execute-with-args">
- <indexterm><primary>SPI_execute_with_args</primary></indexterm>
+<refentry id="spi-spi-execute-extended">
+ <indexterm><primary>SPI_execute_extended</primary></indexterm>
 
  <refmeta>
-  <refentrytitle>SPI_execute_with_args</refentrytitle>
+  <refentrytitle>SPI_execute_extended</refentrytitle>
   <manvolnum>3</manvolnum>
  </refmeta>
 
  <refnamediv>
-  <refname>SPI_execute_with_args</refname>
+  <refname>SPI_execute_extended</refname>
   <refpurpose>execute a command with out-of-line parameters</refpurpose>
  </refnamediv>
 
  <refsynopsisdiv>
 <synopsis>
-int SPI_execute_with_args(const char *<parameter>command</parameter>,
-                          int <parameter>nargs</parameter>, Oid *<parameter>argtypes</parameter>,
-                          Datum *<parameter>values</parameter>, const char *<parameter>nulls</parameter>,
-                          bool <parameter>read_only</parameter>, long <parameter>count</parameter>)
+int SPI_execute_extended(const char *<parameter>command</parameter>,
+                         const SPIExecuteOptions * <parameter>options</parameter>)
 </synopsis>
  </refsynopsisdiv>
 
@@ -658,30 +656,28 @@ int SPI_execute_with_args(const char *<parameter>command</parameter>,
   <title>Description</title>
 
   <para>
-   <function>SPI_execute_with_args</function> executes a command that might
+   <function>SPI_execute_extended</function> executes a command that might
    include references to externally supplied parameters.  The command text
-   refers to a parameter as <literal>$<replaceable>n</replaceable></literal>, and
-   the call specifies data types and values for each such symbol.
-   <parameter>read_only</parameter> and <parameter>count</parameter> have
-   the same interpretation as in <function>SPI_execute</function>.
+   refers to a parameter as <literal>$<replaceable>n</replaceable></literal>,
+   and the <parameter>options-&gt;params</parameter> object (if supplied)
+   provides values and type information for each such symbol.
+   Various execution options can be specified
+   in the <parameter>options</parameter> struct, too.
   </para>
 
   <para>
-   The main advantage of this routine compared to
-   <function>SPI_execute</function> is that data values can be inserted
-   into the command without tedious quoting/escaping, and thus with much
-   less risk of SQL-injection attacks.
+   The <parameter>options-&gt;params</parameter> object should normally
+   mark each parameter with the <literal>PARAM_FLAG_CONST</literal> flag,
+   since a one-shot plan is always used for the query.
   </para>
 
   <para>
-   Similar results can be achieved with <function>SPI_prepare</function> followed by
-   <function>SPI_execute_plan</function>; however, when using this function
-   the query plan is always customized to the specific parameter values
-   provided.
-   For one-time query execution, this function should be preferred.
-   If the same command is to be executed with many different parameters,
-   either method might be faster, depending on the cost of re-planning
-   versus the benefit of custom plans.
+   If <parameter>options-&gt;dest</parameter> is not NULL, then result
+   tuples are passed to that object as they are generated by the executor,
+   instead of being accumulated in <varname>SPI_tuptable</varname>.  Using
+   a caller-supplied <literal>DestReceiver</literal> object is particularly
+   helpful for queries that might generate many tuples, since the data can
+   be processed on-the-fly instead of being accumulated in memory.
   </para>
  </refsect1>
 
@@ -699,69 +695,80 @@ int SPI_execute_with_args(const char *<parameter>command</parameter>,
    </varlistentry>
 
    <varlistentry>
-    <term><literal>int <parameter>nargs</parameter></literal></term>
+    <term><literal>const SPIExecuteOptions * <parameter>options</parameter></literal></term>
     <listitem>
      <para>
-      number of input parameters (<literal>$1</literal>, <literal>$2</literal>, etc.)
+      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>Oid * <parameter>argtypes</parameter></literal></term>
+    <term><literal>ParamListInfo <parameter>params</parameter></literal></term>
     <listitem>
      <para>
-      an array of length <parameter>nargs</parameter>, containing the
-      <acronym>OID</acronym>s of the data types of the parameters
+      data structure containing query parameter types and values; NULL if none
      </para>
     </listitem>
    </varlistentry>
 
    <varlistentry>
-    <term><literal>Datum * <parameter>values</parameter></literal></term>
+    <term><literal>bool <parameter>read_only</parameter></literal></term>
     <listitem>
-     <para>
-      an array of length <parameter>nargs</parameter>, containing the actual
-      parameter values
-     </para>
+     <para><literal>true</literal> for read-only execution</para>
     </listitem>
    </varlistentry>
 
    <varlistentry>
-    <term><literal>const char * <parameter>nulls</parameter></literal></term>
+    <term><literal>bool <parameter>no_snapshots</parameter></literal></term>
     <listitem>
      <para>
-      an array of length <parameter>nargs</parameter>, describing which
-      parameters are null
+      <literal>true</literal> prevents SPI from managing snapshots for
+      execution of the query; use with extreme caution
      </para>
+    </listitem>
+   </varlistentry>
 
+   <varlistentry>
+    <term><literal>uint64 <parameter>tcount</parameter></literal></term>
+    <listitem>
      <para>
-      If <parameter>nulls</parameter> is <symbol>NULL</symbol> then
-      <function>SPI_execute_with_args</function> assumes that no parameters
-      are null.  Otherwise, each entry of the <parameter>nulls</parameter>
-      array should be <literal>'&nbsp;'</literal> if the corresponding parameter
-      value is non-null, or <literal>'n'</literal> if the corresponding parameter
-      value is null.  (In the latter case, the actual value in the
-      corresponding <parameter>values</parameter> entry doesn't matter.)  Note
-      that <parameter>nulls</parameter> is not a text string, just an array:
-      it does not need a <literal>'\0'</literal> terminator.
+      maximum number of rows to return,
+      or <literal>0</literal> for no limit
      </para>
     </listitem>
    </varlistentry>
 
    <varlistentry>
-    <term><literal>bool <parameter>read_only</parameter></literal></term>
+    <term><literal>DestReceiver * <parameter>dest</parameter></literal></term>
     <listitem>
-     <para><literal>true</literal> for read-only execution</para>
+     <para>
+      <literal>DestReceiver</literal> object that will receive any tuples
+      emitted by the query; if NULL, result tuples are accumulated into
+      a <varname>SPI_tuptable</varname> structure, as
+      in <function>SPI_execute</function>
+     </para>
     </listitem>
    </varlistentry>
 
    <varlistentry>
-    <term><literal>long <parameter>count</parameter></literal></term>
+    <term><literal>ResourceOwner <parameter>owner</parameter></literal></term>
     <listitem>
      <para>
-      maximum number of rows to return,
-      or <literal>0</literal> for no limit
+      This field is present for consistency
+      with <function>SPI_execute_plan_extended</function>, but it is
+      ignored, since the plan used
+      by <function>SPI_execute_extended</function> is never saved.
      </para>
     </listitem>
    </varlistentry>
@@ -776,35 +783,40 @@ int SPI_execute_with_args(const char *<parameter>command</parameter>,
   </para>
 
   <para>
+   When <parameter>options-&gt;dest</parameter> is NULL,
    <varname>SPI_processed</varname> and
    <varname>SPI_tuptable</varname> are set as in
-   <function>SPI_execute</function> if successful.
+   <function>SPI_execute</function>.
+   When <parameter>options-&gt;dest</parameter> is not NULL,
+   <varname>SPI_processed</varname> is set to zero and
+   <varname>SPI_tuptable</varname> is set to NULL.  If a tuple count
+   is required, the caller's <literal>DestReceiver</literal> object must
+   calculate it.
   </para>
  </refsect1>
 </refentry>
 
 <!-- *********************************************** -->
 
-<refentry id="spi-spi-execute-with-receiver">
- <indexterm><primary>SPI_execute_with_receiver</primary></indexterm>
+<refentry id="spi-spi-execute-with-args">
+ <indexterm><primary>SPI_execute_with_args</primary></indexterm>
 
  <refmeta>
-  <refentrytitle>SPI_execute_with_receiver</refentrytitle>
+  <refentrytitle>SPI_execute_with_args</refentrytitle>
   <manvolnum>3</manvolnum>
  </refmeta>
 
  <refnamediv>
-  <refname>SPI_execute_with_receiver</refname>
+  <refname>SPI_execute_with_args</refname>
   <refpurpose>execute a command with out-of-line parameters</refpurpose>
  </refnamediv>
 
  <refsynopsisdiv>
 <synopsis>
-  int SPI_execute_with_receiver(const char *<parameter>command</parameter>,
-                                ParamListInfo <parameter>params</parameter>,
-                                bool <parameter>read_only</parameter>,
-                                long <parameter>count</parameter>,
-                                DestReceiver *<parameter>dest</parameter>)
+int SPI_execute_with_args(const char *<parameter>command</parameter>,
+                          int <parameter>nargs</parameter>, Oid *<parameter>argtypes</parameter>,
+                          Datum *<parameter>values</parameter>, const char *<parameter>nulls</parameter>,
+                          bool <parameter>read_only</parameter>, long <parameter>count</parameter>)
 </synopsis>
  </refsynopsisdiv>
 
@@ -812,28 +824,30 @@ int SPI_execute_with_args(const char *<parameter>command</parameter>,
   <title>Description</title>
 
   <para>
-   <function>SPI_execute_with_receiver</function> executes a command that might
+   <function>SPI_execute_with_args</function> executes a command that might
    include references to externally supplied parameters.  The command text
-   refers to a parameter as <literal>$<replaceable>n</replaceable></literal>,
-   and the <parameter>params</parameter> object provides values and type
-   information for each such symbol.
+   refers to a parameter as <literal>$<replaceable>n</replaceable></literal>, and
+   the call specifies data types and values for each such symbol.
    <parameter>read_only</parameter> and <parameter>count</parameter> have
    the same interpretation as in <function>SPI_execute</function>.
   </para>
 
   <para>
-   If <parameter>dest</parameter> is not NULL, then result tuples are passed
-   to that object as they are generated by the executor, instead of being
-   accumulated in <varname>SPI_tuptable</varname>.  Using a
-   caller-supplied <literal>DestReceiver</literal> object is particularly
-   helpful for queries that might generate many tuples, since the data can
-   be processed on-the-fly instead of being accumulated in memory.
+   The main advantage of this routine compared to
+   <function>SPI_execute</function> is that data values can be inserted
+   into the command without tedious quoting/escaping, and thus with much
+   less risk of SQL-injection attacks.
   </para>
 
   <para>
-   The <parameter>params</parameter> object should normally mark each
-   parameter with the <literal>PARAM_FLAG_CONST</literal> flag, since
-   a one-shot plan is always used for the query.
+   Similar results can be achieved with <function>SPI_prepare</function> followed by
+   <function>SPI_execute_plan</function>; however, when using this function
+   the query plan is always customized to the specific parameter values
+   provided.
+   For one-time query execution, this function should be preferred.
+   If the same command is to be executed with many different parameters,
+   either method might be faster, depending on the cost of re-planning
+   versus the benefit of custom plans.
   </para>
  </refsect1>
 
@@ -851,38 +865,69 @@ int SPI_execute_with_args(const char *<parameter>command</parameter>,
    </varlistentry>
 
    <varlistentry>
-    <term><literal>ParamListInfo <parameter>params</parameter></literal></term>
+    <term><literal>int <parameter>nargs</parameter></literal></term>
     <listitem>
      <para>
-      data structure containing parameter types and values; NULL if none
+      number of input parameters (<literal>$1</literal>, <literal>$2</literal>, etc.)
      </para>
     </listitem>
    </varlistentry>
 
    <varlistentry>
-    <term><literal>bool <parameter>read_only</parameter></literal></term>
+    <term><literal>Oid * <parameter>argtypes</parameter></literal></term>
     <listitem>
-     <para><literal>true</literal> for read-only execution</para>
+     <para>
+      an array of length <parameter>nargs</parameter>, containing the
+      <acronym>OID</acronym>s of the data types of the parameters
+     </para>
     </listitem>
    </varlistentry>
 
    <varlistentry>
-    <term><literal>long <parameter>count</parameter></literal></term>
+    <term><literal>Datum * <parameter>values</parameter></literal></term>
     <listitem>
      <para>
-      maximum number of rows to return,
-      or <literal>0</literal> for no limit
+      an array of length <parameter>nargs</parameter>, containing the actual
+      parameter values
      </para>
     </listitem>
    </varlistentry>
 
    <varlistentry>
-    <term><literal>DestReceiver * <parameter>dest</parameter></literal></term>
+    <term><literal>const char * <parameter>nulls</parameter></literal></term>
     <listitem>
      <para>
-      <literal>DestReceiver</literal> object that will receive any tuples
-      emitted by the query; if NULL, tuples are returned
-      in <varname>SPI_tuptable</varname>
+      an array of length <parameter>nargs</parameter>, describing which
+      parameters are null
+     </para>
+
+     <para>
+      If <parameter>nulls</parameter> is <symbol>NULL</symbol> then
+      <function>SPI_execute_with_args</function> assumes that no parameters
+      are null.  Otherwise, each entry of the <parameter>nulls</parameter>
+      array should be <literal>'&nbsp;'</literal> if the corresponding parameter
+      value is non-null, or <literal>'n'</literal> if the corresponding parameter
+      value is null.  (In the latter case, the actual value in the
+      corresponding <parameter>values</parameter> entry doesn't matter.)  Note
+      that <parameter>nulls</parameter> is not a text string, just an array:
+      it does not need a <literal>'\0'</literal> terminator.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><literal>bool <parameter>read_only</parameter></literal></term>
+    <listitem>
+     <para><literal>true</literal> for read-only execution</para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><literal>long <parameter>count</parameter></literal></term>
+    <listitem>
+     <para>
+      maximum number of rows to return,
+      or <literal>0</literal> for no limit
      </para>
     </listitem>
    </varlistentry>
@@ -897,15 +942,9 @@ int SPI_execute_with_args(const char *<parameter>command</parameter>,
   </para>
 
   <para>
-   When <parameter>dest</parameter> is NULL,
    <varname>SPI_processed</varname> and
    <varname>SPI_tuptable</varname> are set as in
-   <function>SPI_execute</function>.
-   When <parameter>dest</parameter> is not NULL,
-   <varname>SPI_processed</varname> is set to zero and
-   <varname>SPI_tuptable</varname> is set to NULL.  If a tuple count
-   is required, the caller's <literal>DestReceiver</literal> object must
-   calculate it.
+   <function>SPI_execute</function> if successful.
   </para>
  </refsect1>
 </refentry>
@@ -1873,11 +1912,11 @@ int SPI_execute_plan_extended(SPIPlanPtr <parameter>plan</parameter>,
   </para>
 
   <para>
-   When <parameter>dest</parameter> is NULL,
+   When <parameter>options-&gt;dest</parameter> is NULL,
    <varname>SPI_processed</varname> and
    <varname>SPI_tuptable</varname> are set as in
    <function>SPI_execute_plan</function>.
-   When <parameter>dest</parameter> is not NULL,
+   When <parameter>options-&gt;dest</parameter> is not NULL,
    <varname>SPI_processed</varname> is set to zero and
    <varname>SPI_tuptable</varname> is set to NULL.  If a tuple count
    is required, the caller's <literal>DestReceiver</literal> object must
@@ -2263,6 +2302,12 @@ Portal SPI_cursor_open_with_args(const char *<parameter>name</parameter>,
    The passed-in parameter data will be copied into the cursor's portal, so it
    can be freed while the cursor still exists.
   </para>
+
+  <para>
+   This function is now deprecated in favor
+   of <function>SPI_cursor_parse_open</function>, which provides equivalent
+   functionality using a more modern API for handling query parameters.
+  </para>
  </refsect1>
 
  <refsect1>
@@ -2465,26 +2510,24 @@ Portal SPI_cursor_open_with_paramlist(const char *<parameter>name</parameter>,
 
 <!-- *********************************************** -->
 
-<refentry id="spi-spi-cursor-parse-open-with-paramlist">
- <indexterm><primary>SPI_cursor_parse_open_with_paramlist</primary></indexterm>
+<refentry id="spi-spi-cursor-parse-open">
+ <indexterm><primary>SPI_cursor_parse_open</primary></indexterm>
 
  <refmeta>
-  <refentrytitle>SPI_cursor_parse_open_with_paramlist</refentrytitle>
+  <refentrytitle>SPI_cursor_parse_open</refentrytitle>
   <manvolnum>3</manvolnum>
  </refmeta>
 
  <refnamediv>
-  <refname>SPI_cursor_parse_open_with_paramlist</refname>
-  <refpurpose>set up a cursor using a query and parameters</refpurpose>
+  <refname>SPI_cursor_parse_open</refname>
+  <refpurpose>set up a cursor using a query string and parameters</refpurpose>
  </refnamediv>
 
  <refsynopsisdiv>
 <synopsis>
-Portal SPI_cursor_parse_open_with_paramlist(const char *<parameter>name</parameter>,
-                                            const char *<parameter>command</parameter>,
-                                            ParamListInfo <parameter>params</parameter>,
-                                            bool <parameter>read_only</parameter>,
-                                            int <parameter>cursorOptions</parameter>)
+Portal SPI_cursor_parse_open(const char *<parameter>name</parameter>,
+                             const char *<parameter>command</parameter>,
+                             const SPIParseOpenOptions * <parameter>options</parameter>)
 </synopsis>
  </refsynopsisdiv>
 
@@ -2492,17 +2535,27 @@ Portal SPI_cursor_parse_open_with_paramlist(const char *<parameter>name</paramet
   <title>Description</title>
 
   <para>
-   <function>SPI_cursor_parse_open_with_paramlist</function> sets up a cursor
-   (internally, a portal) that will execute the specified query.  This
-   function is equivalent to <function>SPI_cursor_open_with_args</function>
-   except that any parameters referenced by the query are provided by
-   a <literal>ParamListInfo</literal> object, rather than in ad-hoc arrays.
+   <function>SPI_cursor_parse_open</function> sets up a cursor
+   (internally, a portal) that will execute the specified query string.
+   This is comparable to <function>SPI_prepare_cursor</function> followed
+   by <function>SPI_cursor_open_with_paramlist</function>, except that
+   parameter references within the query string are handled entirely by
+   supplying a <literal>ParamListInfo</literal> object.
+  </para>
+
+  <para>
+   For one-time query execution, this function should be preferred
+   over <function>SPI_prepare_cursor</function> followed by
+   <function>SPI_cursor_open_with_paramlist</function>.
+   If the same command is to be executed with many different parameters,
+   either method might be faster, depending on the cost of re-planning
+   versus the benefit of custom plans.
   </para>
 
   <para>
-   The <parameter>params</parameter> object should normally mark each
-   parameter with the <literal>PARAM_FLAG_CONST</literal> flag, since
-   a one-shot plan is always used for the query.
+   The <parameter>options-&gt;params</parameter> object should normally
+   mark each parameter with the <literal>PARAM_FLAG_CONST</literal> flag,
+   since a one-shot plan is always used for the query.
   </para>
 
   <para>
@@ -2535,18 +2588,30 @@ Portal SPI_cursor_parse_open_with_paramlist(const char *<parameter>name</paramet
    </varlistentry>
 
    <varlistentry>
-    <term><literal>ParamListInfo <parameter>params</parameter></literal></term>
+    <term><literal>const SPIParseOpenOptions * <parameter>options</parameter></literal></term>
     <listitem>
      <para>
-      data structure containing parameter types and values; NULL if none
+      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>bool <parameter>read_only</parameter></literal></term>
+    <term><literal>ParamListInfo <parameter>params</parameter></literal></term>
     <listitem>
-     <para><literal>true</literal> for read-only execution</para>
+     <para>
+      data structure containing query parameter types and values; NULL if none
+     </para>
     </listitem>
    </varlistentry>
 
@@ -2558,6 +2623,13 @@ Portal SPI_cursor_parse_open_with_paramlist(const char *<parameter>name</paramet
      </para>
     </listitem>
    </varlistentry>
+
+   <varlistentry>
+    <term><literal>bool <parameter>read_only</parameter></literal></term>
+    <listitem>
+     <para><literal>true</literal> for read-only execution</para>
+    </listitem>
+   </varlistentry>
   </variablelist>
  </refsect1>
 
index 68a6bcea02d5975248efb5d9e5e204bd38ee5acc..00aa78ea5399334e99e7f63f2f78005ac28233a6 100644 (file)
@@ -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);
index 5740f8956e53aa8d94a3437543491376f7661743..6455d100f5034e2d7664ff2bdbd8903ebcaf9d1b 100644 (file)
@@ -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);
index 383d92fc1d054c8017a60cc180f80c3c07e8712f..b4c70aaa7fa5dfbf1710b9351d21ae3d29429cc9 100644 (file)
@@ -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",