Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit d5466e3

Browse files
committed
Add SPI-level support for executing SQL commands with one-time-use plans,
that is commands that have out-of-line parameters but the plan is prepared assuming that the parameter values are constants. This is needed for the plpgsql EXECUTE USING patch, but will probably have use elsewhere. This commit includes the SPI functions and documentation, but no callers nor regression tests. The upcoming EXECUTE USING patch will provide regression-test coverage. I thought committing this separately made sense since it's logically a distinct feature.
1 parent 6b73d7e commit d5466e3

File tree

3 files changed

+480
-51
lines changed

3 files changed

+480
-51
lines changed

doc/src/sgml/spi.sgml

Lines changed: 301 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- $PostgreSQL: pgsql/doc/src/sgml/spi.sgml,v 1.61 2008/03/25 22:42:42 tgl Exp $ -->
1+
<!-- $PostgreSQL: pgsql/doc/src/sgml/spi.sgml,v 1.62 2008/04/01 03:09:30 tgl Exp $ -->
22

33
<chapter id="spi">
44
<title>Server Programming Interface</title>
@@ -267,7 +267,7 @@ void SPI_pop(void)
267267
<title>Description</title>
268268

269269
<para>
270-
<function>SPI_pop</function> pops the previous environment from the
270+
<function>SPI_pop</function> pops the previous environment from the
271271
SPI call stack. See <function>SPI_push</function>.
272272
</para>
273273
</refsect1>
@@ -371,7 +371,7 @@ SPI_execute("INSERT INTO foo SELECT * FROM bar", false, 5);
371371
then you can use the
372372
global pointer <literal>SPITupleTable *SPI_tuptable</literal> to
373373
access the result rows. Some utility commands (such as
374-
<command>EXPLAIN</>) also return row sets, and <literal>SPI_tuptable</>
374+
<command>EXPLAIN</>) also return row sets, and <literal>SPI_tuptable</>
375375
will contain the result in these cases too.
376376
</para>
377377

@@ -676,6 +676,150 @@ int SPI_exec(const char * <parameter>command</parameter>, long <parameter>count<
676676

677677
<!-- *********************************************** -->
678678

679+
<refentry id="spi-spi-execute-with-args">
680+
<refmeta>
681+
<refentrytitle>SPI_execute_with_args</refentrytitle>
682+
</refmeta>
683+
684+
<refnamediv>
685+
<refname>SPI_execute_with_args</refname>
686+
<refpurpose>execute a command with out-of-line parameters</refpurpose>
687+
</refnamediv>
688+
689+
<indexterm><primary>SPI_execute_with_args</primary></indexterm>
690+
691+
<refsynopsisdiv>
692+
<synopsis>
693+
int SPI_execute_with_args(const char *<parameter>command</parameter>,
694+
int <parameter>nargs</parameter>, Oid *<parameter>argtypes</parameter>,
695+
Datum *<parameter>values</parameter>, const char *<parameter>nulls</parameter>,
696+
bool <parameter>read_only</parameter>, long <parameter>count</parameter>)
697+
</synopsis>
698+
</refsynopsisdiv>
699+
700+
<refsect1>
701+
<title>Description</title>
702+
703+
<para>
704+
<function>SPI_execute_with_args</function> executes a command that might
705+
include references to externally supplied parameters. The command text
706+
refers to a parameter as <literal>$<replaceable>n</></literal>, and
707+
the call specifies data types and values for each such symbol.
708+
<parameter>read_only</parameter> and <parameter>count</parameter> have
709+
the same interpretation as in <function>SPI_execute</function>.
710+
</para>
711+
712+
<para>
713+
The main advantage of this routine compared to
714+
<function>SPI_execute</function> is that data values can be inserted
715+
into the command without tedious quoting/escaping, and thus with much
716+
less risk of SQL-injection attacks.
717+
</para>
718+
719+
<para>
720+
Similar results can be achieved with <function>SPI_prepare</> followed by
721+
<function>SPI_execute_plan</function>; however, when using this function
722+
the query plan is customized to the specific parameter values provided.
723+
For one-time query execution, this function should be preferred.
724+
If the same command is to be executed with many different parameters,
725+
either method might be faster, depending on the cost of re-planning
726+
versus the benefit of custom plans.
727+
</para>
728+
</refsect1>
729+
730+
<refsect1>
731+
<title>Arguments</title>
732+
733+
<variablelist>
734+
<varlistentry>
735+
<term><literal>const char * <parameter>command</parameter></literal></term>
736+
<listitem>
737+
<para>
738+
command string
739+
</para>
740+
</listitem>
741+
</varlistentry>
742+
743+
<varlistentry>
744+
<term><literal>int <parameter>nargs</parameter></literal></term>
745+
<listitem>
746+
<para>
747+
number of input parameters (<literal>$1</>, <literal>$2</>, etc.)
748+
</para>
749+
</listitem>
750+
</varlistentry>
751+
752+
<varlistentry>
753+
<term><literal>Oid * <parameter>argtypes</parameter></literal></term>
754+
<listitem>
755+
<para>
756+
an array containing the <acronym>OID</acronym>s of
757+
the data types of the parameters
758+
</para>
759+
</listitem>
760+
</varlistentry>
761+
762+
<varlistentry>
763+
<term><literal>Datum * <parameter>values</parameter></literal></term>
764+
<listitem>
765+
<para>
766+
an array of actual parameter values
767+
</para>
768+
</listitem>
769+
</varlistentry>
770+
771+
<varlistentry>
772+
<term><literal>const char * <parameter>nulls</parameter></literal></term>
773+
<listitem>
774+
<para>
775+
an array describing which parameters are null
776+
</para>
777+
778+
<para>
779+
If <parameter>nulls</parameter> is <symbol>NULL</symbol> then
780+
<function>SPI_execute_with_args</function> assumes that no parameters are
781+
null.
782+
</para>
783+
</listitem>
784+
</varlistentry>
785+
786+
<varlistentry>
787+
<term><literal>bool <parameter>read_only</parameter></literal></term>
788+
<listitem>
789+
<para>
790+
<literal>true</> for read-only execution
791+
</para>
792+
</listitem>
793+
</varlistentry>
794+
795+
<varlistentry>
796+
<term><literal>long <parameter>count</parameter></literal></term>
797+
<listitem>
798+
<para>
799+
maximum number of rows to process or return
800+
</para>
801+
</listitem>
802+
</varlistentry>
803+
</variablelist>
804+
</refsect1>
805+
806+
<refsect1>
807+
<title>Return Value</title>
808+
809+
<para>
810+
The return value is the same as for <function>SPI_execute</function>.
811+
</para>
812+
813+
<para>
814+
<varname>SPI_processed</varname> and
815+
<varname>SPI_tuptable</varname> are set as in
816+
<function>SPI_execute</function> if successful.
817+
</para>
818+
</refsect1>
819+
</refentry>
820+
821+
<!-- *********************************************** -->
822+
679823
<refentry id="spi-spi-prepare">
680824
<refmeta>
681825
<refentrytitle>SPI_prepare</refentrytitle>
@@ -861,7 +1005,7 @@ SPIPlanPtr SPI_prepare_cursor(const char * <parameter>command</parameter>, int <
8611005
</para>
8621006
</listitem>
8631007
</varlistentry>
864-
1008+
8651009
<varlistentry>
8661010
<term><literal>int <parameter>cursorOptions</parameter></literal></term>
8671011
<listitem>
@@ -1453,6 +1597,152 @@ Portal SPI_cursor_open(const char * <parameter>name</parameter>, SPIPlanPtr <par
14531597

14541598
<!-- *********************************************** -->
14551599

1600+
<refentry id="spi-spi-cursor-open-with-args">
1601+
<refmeta>
1602+
<refentrytitle>SPI_cursor_open_with_args</refentrytitle>
1603+
</refmeta>
1604+
1605+
<refnamediv>
1606+
<refname>SPI_cursor_open_with_args</refname>
1607+
<refpurpose>set up a cursor using a query and parameters</refpurpose>
1608+
</refnamediv>
1609+
1610+
<indexterm><primary>SPI_cursor_open_with_args</primary></indexterm>
1611+
1612+
<refsynopsisdiv>
1613+
<synopsis>
1614+
Portal SPI_cursor_open_with_args(const char *<parameter>name</parameter>,
1615+
const char *<parameter>command</parameter>,
1616+
int <parameter>nargs</parameter>, Oid *<parameter>argtypes</parameter>,
1617+
Datum *<parameter>values</parameter>, const char *<parameter>nulls</parameter>,
1618+
bool <parameter>read_only</parameter>, int <parameter>cursorOptions</parameter>)
1619+
</synopsis>
1620+
</refsynopsisdiv>
1621+
1622+
<refsect1>
1623+
<title>Description</title>
1624+
1625+
<para>
1626+
<function>SPI_cursor_open_with_args</function> sets up a cursor
1627+
(internally, a portal) that will execute the specified query.
1628+
Most of the parameters have the same meanings as the corresponding
1629+
parameters to <function>SPI_prepare_cursor</function>
1630+
and <function>SPI_cursor_open</function>.
1631+
</para>
1632+
1633+
<para>
1634+
For one-time query execution, this function should be preferred
1635+
over <function>SPI_prepare_cursor</function> followed by
1636+
<function>SPI_cursor_open</function>.
1637+
If the same command is to be executed with many different parameters,
1638+
either method might be faster, depending on the cost of re-planning
1639+
versus the benefit of custom plans.
1640+
</para>
1641+
1642+
<para>
1643+
The passed-in data will be copied into the cursor's portal, so it
1644+
can be freed while the cursor still exists.
1645+
</para>
1646+
</refsect1>
1647+
1648+
<refsect1>
1649+
<title>Arguments</title>
1650+
1651+
<variablelist>
1652+
<varlistentry>
1653+
<term><literal>const char * <parameter>name</parameter></literal></term>
1654+
<listitem>
1655+
<para>
1656+
name for portal, or <symbol>NULL</symbol> to let the system
1657+
select a name
1658+
</para>
1659+
</listitem>
1660+
</varlistentry>
1661+
1662+
<varlistentry>
1663+
<term><literal>const char * <parameter>command</parameter></literal></term>
1664+
<listitem>
1665+
<para>
1666+
command string
1667+
</para>
1668+
</listitem>
1669+
</varlistentry>
1670+
1671+
<varlistentry>
1672+
<term><literal>int <parameter>nargs</parameter></literal></term>
1673+
<listitem>
1674+
<para>
1675+
number of input parameters (<literal>$1</>, <literal>$2</>, etc.)
1676+
</para>
1677+
</listitem>
1678+
</varlistentry>
1679+
1680+
<varlistentry>
1681+
<term><literal>Oid * <parameter>argtypes</parameter></literal></term>
1682+
<listitem>
1683+
<para>
1684+
an array containing the <acronym>OID</acronym>s of
1685+
the data types of the parameters
1686+
</para>
1687+
</listitem>
1688+
</varlistentry>
1689+
1690+
<varlistentry>
1691+
<term><literal>Datum * <parameter>values</parameter></literal></term>
1692+
<listitem>
1693+
<para>
1694+
an array of actual parameter values
1695+
</para>
1696+
</listitem>
1697+
</varlistentry>
1698+
1699+
<varlistentry>
1700+
<term><literal>const char * <parameter>nulls</parameter></literal></term>
1701+
<listitem>
1702+
<para>
1703+
an array describing which parameters are null
1704+
</para>
1705+
1706+
<para>
1707+
If <parameter>nulls</parameter> is <symbol>NULL</symbol> then
1708+
<function>SPI_cursor_open_with_args</function> assumes that no
1709+
parameters are null.
1710+
</para>
1711+
</listitem>
1712+
</varlistentry>
1713+
1714+
<varlistentry>
1715+
<term><literal>bool <parameter>read_only</parameter></literal></term>
1716+
<listitem>
1717+
<para>
1718+
<literal>true</> for read-only execution
1719+
</para>
1720+
</listitem>
1721+
</varlistentry>
1722+
1723+
<varlistentry>
1724+
<term><literal>int <parameter>cursorOptions</parameter></literal></term>
1725+
<listitem>
1726+
<para>
1727+
integer bitmask of cursor options; zero produces default behavior
1728+
</para>
1729+
</listitem>
1730+
</varlistentry>
1731+
</variablelist>
1732+
</refsect1>
1733+
1734+
<refsect1>
1735+
<title>Return Value</title>
1736+
1737+
<para>
1738+
Pointer to portal containing the cursor. Note there is no error
1739+
return convention; any error will be reported via <function>elog</>.
1740+
</para>
1741+
</refsect1>
1742+
</refentry>
1743+
1744+
<!-- *********************************************** -->
1745+
14561746
<refentry id="spi-spi-cursor-find">
14571747
<refmeta>
14581748
<refentrytitle>SPI_cursor_find</refentrytitle>
@@ -1748,7 +2038,7 @@ void SPI_scroll_cursor_fetch(Portal <parameter>portal</parameter>, FetchDirectio
17482038

17492039
<para>
17502040
See the SQL <xref linkend="sql-fetch" endterm="sql-fetch-title"> command
1751-
for details of the interpretation of the
2041+
for details of the interpretation of the
17522042
<parameter>direction</parameter> and
17532043
<parameter>count</parameter> parameters.
17542044
</para>
@@ -1847,7 +2137,7 @@ void SPI_scroll_cursor_move(Portal <parameter>portal</parameter>, FetchDirection
18472137

18482138
<para>
18492139
See the SQL <xref linkend="sql-fetch" endterm="sql-fetch-title"> command
1850-
for details of the interpretation of the
2140+
for details of the interpretation of the
18512141
<parameter>direction</parameter> and
18522142
<parameter>count</parameter> parameters.
18532143
</para>
@@ -3346,9 +3636,9 @@ execq(text *sql, int cnt)
33463636
command = text_to_cstring(sql);
33473637

33483638
SPI_connect();
3349-
3639+
33503640
ret = SPI_exec(command, cnt);
3351-
3641+
33523642
proc = SPI_processed;
33533643
/*
33543644
* If some rows were fetched, print them via elog(INFO).
@@ -3359,11 +3649,11 @@ execq(text *sql, int cnt)
33593649
SPITupleTable *tuptable = SPI_tuptable;
33603650
char buf[8192];
33613651
int i, j;
3362-
3652+
33633653
for (j = 0; j &lt; proc; j++)
33643654
{
33653655
HeapTuple tuple = tuptable-&gt;vals[j];
3366-
3656+
33673657
for (i = 1, buf[0] = 0; i &lt;= tupdesc-&gt;natts; i++)
33683658
snprintf(buf + strlen (buf), sizeof(buf) - strlen(buf), " %s%s",
33693659
SPI_getvalue(tuple, tupdesc, i),
@@ -3469,7 +3759,7 @@ INSERT 0 2
34693759
2
34703760
2 -- 2 rows * 1 (x in first row)
34713761
6 -- 3 rows (2 + 1 just inserted) * 2 (x in second row)
3472-
(4 rows) ^^^^^^
3762+
(4 rows) ^^^^^^
34733763
rows visible to execq() in different invocations
34743764
</programlisting>
34753765
</para>

0 commit comments

Comments
 (0)