1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-28 23:42:10 +03:00

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
This commit is contained in:
Tom Lane
2021-01-26 16:37:12 -05:00
parent 7292fd8f1c
commit d5a83d79c9
4 changed files with 314 additions and 244 deletions

View File

@ -632,6 +632,172 @@ int SPI_exec(const char * <parameter>command</parameter>, long <parameter>count<
<!-- *********************************************** -->
<refentry id="spi-spi-execute-extended">
<indexterm><primary>SPI_execute_extended</primary></indexterm>
<refmeta>
<refentrytitle>SPI_execute_extended</refentrytitle>
<manvolnum>3</manvolnum>
</refmeta>
<refnamediv>
<refname>SPI_execute_extended</refname>
<refpurpose>execute a command with out-of-line parameters</refpurpose>
</refnamediv>
<refsynopsisdiv>
<synopsis>
int SPI_execute_extended(const char *<parameter>command</parameter>,
const SPIExecuteOptions * <parameter>options</parameter>)
</synopsis>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para>
<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 <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 <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>
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>
<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 SPIExecuteOptions * <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>ParamListInfo <parameter>params</parameter></literal></term>
<listitem>
<para>
data structure containing query parameter types and values; NULL if none
</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>bool <parameter>no_snapshots</parameter></literal></term>
<listitem>
<para>
<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>
maximum number of rows to return,
or <literal>0</literal> for no limit
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>DestReceiver * <parameter>dest</parameter></literal></term>
<listitem>
<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>ResourceOwner <parameter>owner</parameter></literal></term>
<listitem>
<para>
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>
</variablelist>
</refsect1>
<refsect1>
<title>Return Value</title>
<para>
The return value is the same as for <function>SPI_execute</function>.
</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>.
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-args">
<indexterm><primary>SPI_execute_with_args</primary></indexterm>
@ -785,133 +951,6 @@ int SPI_execute_with_args(const char *<parameter>command</parameter>,
<!-- *********************************************** -->
<refentry id="spi-spi-execute-with-receiver">
<indexterm><primary>SPI_execute_with_receiver</primary></indexterm>
<refmeta>
<refentrytitle>SPI_execute_with_receiver</refentrytitle>
<manvolnum>3</manvolnum>
</refmeta>
<refnamediv>
<refname>SPI_execute_with_receiver</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>)
</synopsis>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para>
<function>SPI_execute_with_receiver</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.
<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.
</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.
</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>ParamListInfo <parameter>params</parameter></literal></term>
<listitem>
<para>
data structure containing parameter types and values; NULL if none
</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>
<varlistentry>
<term><literal>DestReceiver * <parameter>dest</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>
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Return Value</title>
<para>
The return value is the same as for <function>SPI_execute</function>.
</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.
</para>
</refsect1>
</refentry>
<!-- *********************************************** -->
<refentry id="spi-spi-prepare">
<indexterm><primary>SPI_prepare</primary></indexterm>
@ -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>
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.
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>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>