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

Commit 9bedd12

Browse files
committed
Add support for invoking parser callback hooks via SPI and in cached plans.
As proof of concept, modify plpgsql to use the hooks. plpgsql is still inserting $n symbols textually, but the "back end" of the parsing process now goes through the ParamRef hook instead of using a fixed parameter-type array, and then execution only fetches actually-referenced parameters, using a hook added to ParamListInfo. Although there's a lot left to be done in plpgsql, this already cures the "if (TG_OP = 'INSERT' and NEW.foo ...)" problem, as illustrated by the changed regression test.
1 parent 48912ac commit 9bedd12

File tree

23 files changed

+1104
-527
lines changed

23 files changed

+1104
-527
lines changed

doc/src/sgml/spi.sgml

Lines changed: 281 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- $PostgreSQL: pgsql/doc/src/sgml/spi.sgml,v 1.65 2009/08/05 19:31:50 alvherre Exp $ -->
1+
<!-- $PostgreSQL: pgsql/doc/src/sgml/spi.sgml,v 1.66 2009/11/04 22:26:04 tgl Exp $ -->
22

33
<chapter id="spi">
44
<title>Server Programming Interface</title>
@@ -861,7 +861,7 @@ SPIPlanPtr SPI_prepare(const char * <parameter>command</parameter>, int <paramet
861861

862862
<para>
863863
<function>SPI_prepare</function> creates and returns an execution
864-
plan for the specified command but doesn't execute the command.
864+
plan for the specified command, but doesn't execute the command.
865865
This function should only be called from a connected procedure.
866866
</para>
867867

@@ -990,7 +990,7 @@ SPIPlanPtr SPI_prepare_cursor(const char * <parameter>command</parameter>, int <
990990
of the planner's <quote>cursor options</> parameter. This is a bitmask
991991
having the values shown in <filename>nodes/parsenodes.h</filename>
992992
for the <structfield>options</> field of <structname>DeclareCursorStmt</>.
993-
<function>SPI_prepare</function> always takes these options as zero.
993+
<function>SPI_prepare</function> always takes the cursor options as zero.
994994
</para>
995995
</refsect1>
996996

@@ -1061,6 +1061,94 @@ SPIPlanPtr SPI_prepare_cursor(const char * <parameter>command</parameter>, int <
10611061

10621062
<!-- *********************************************** -->
10631063

1064+
<refentry id="spi-spi-prepare-params">
1065+
<refmeta>
1066+
<refentrytitle>SPI_prepare_params</refentrytitle>
1067+
<manvolnum>3</manvolnum>
1068+
</refmeta>
1069+
1070+
<refnamediv>
1071+
<refname>SPI_prepare_params</refname>
1072+
<refpurpose>prepare a plan for a command, without executing it yet</refpurpose>
1073+
</refnamediv>
1074+
1075+
<indexterm><primary>SPI_prepare_params</primary></indexterm>
1076+
1077+
<refsynopsisdiv>
1078+
<synopsis>
1079+
SPIPlanPtr SPI_prepare_params(const char * <parameter>command</parameter>,
1080+
ParserSetupHook <parameter>parserSetup</parameter>,
1081+
void * <parameter>parserSetupArg</parameter>,
1082+
int <parameter>cursorOptions</parameter>)
1083+
</synopsis>
1084+
</refsynopsisdiv>
1085+
1086+
<refsect1>
1087+
<title>Description</title>
1088+
1089+
<para>
1090+
<function>SPI_prepare_params</function> creates and returns an execution
1091+
plan for the specified command, but doesn't execute the command.
1092+
This function is equivalent to <function>SPI_prepare_cursor</function>,
1093+
with the addition that the caller can specify parser hook functions
1094+
to control the parsing of external parameter references.
1095+
</para>
1096+
</refsect1>
1097+
1098+
<refsect1>
1099+
<title>Arguments</title>
1100+
1101+
<variablelist>
1102+
<varlistentry>
1103+
<term><literal>const char * <parameter>command</parameter></literal></term>
1104+
<listitem>
1105+
<para>
1106+
command string
1107+
</para>
1108+
</listitem>
1109+
</varlistentry>
1110+
1111+
<varlistentry>
1112+
<term><literal>ParserSetupHook <parameter>parserSetup</parameter></literal></term>
1113+
<listitem>
1114+
<para>
1115+
Parser hook setup function
1116+
</para>
1117+
</listitem>
1118+
</varlistentry>
1119+
1120+
<varlistentry>
1121+
<term><literal>void * <parameter>parserSetupArg</parameter></literal></term>
1122+
<listitem>
1123+
<para>
1124+
passthrough argument for <parameter>parserSetup</parameter>
1125+
</para>
1126+
</listitem>
1127+
</varlistentry>
1128+
1129+
<varlistentry>
1130+
<term><literal>int <parameter>cursorOptions</parameter></literal></term>
1131+
<listitem>
1132+
<para>
1133+
integer bitmask of cursor options; zero produces default behavior
1134+
</para>
1135+
</listitem>
1136+
</varlistentry>
1137+
</variablelist>
1138+
</refsect1>
1139+
1140+
<refsect1>
1141+
<title>Return Value</title>
1142+
1143+
<para>
1144+
<function>SPI_prepare_params</function> has the same return conventions as
1145+
<function>SPI_prepare</function>.
1146+
</para>
1147+
</refsect1>
1148+
</refentry>
1149+
1150+
<!-- *********************************************** -->
1151+
10641152
<refentry id="spi-spi-getargcount">
10651153
<refmeta>
10661154
<refentrytitle>SPI_getargcount</refentrytitle>
@@ -1386,14 +1474,100 @@ int SPI_execute_plan(SPIPlanPtr <parameter>plan</parameter>, Datum * <parameter>
13861474
<function>SPI_execute</function> if successful.
13871475
</para>
13881476
</refsect1>
1477+
</refentry>
1478+
1479+
<!-- *********************************************** -->
1480+
1481+
<refentry id="spi-spi-execute-plan-with-paramlist">
1482+
<refmeta>
1483+
<refentrytitle>SPI_execute_plan_with_paramlist</refentrytitle>
1484+
<manvolnum>3</manvolnum>
1485+
</refmeta>
1486+
1487+
<refnamediv>
1488+
<refname>SPI_execute_plan_with_paramlist</refname>
1489+
<refpurpose>execute a plan prepared by <function>SPI_prepare</function></refpurpose>
1490+
</refnamediv>
1491+
1492+
<indexterm><primary>SPI_execute_plan_with_paramlist</primary></indexterm>
1493+
1494+
<refsynopsisdiv>
1495+
<synopsis>
1496+
int SPI_execute_plan_with_paramlist(SPIPlanPtr <parameter>plan</parameter>,
1497+
ParamListInfo <parameter>params</parameter>,
1498+
bool <parameter>read_only</parameter>,
1499+
long <parameter>count</parameter>)
1500+
</synopsis>
1501+
</refsynopsisdiv>
13891502

13901503
<refsect1>
1391-
<title>Notes</title>
1504+
<title>Description</title>
13921505

13931506
<para>
1394-
If one of the objects (a table, function, etc.) referenced by the
1395-
prepared plan is dropped during the session then the result of
1396-
<function>SPI_execute_plan</function> for this plan will be unpredictable.
1507+
<function>SPI_execute_plan_with_paramlist</function> executes a plan
1508+
prepared by <function>SPI_prepare</function>.
1509+
This function is equivalent to <function>SPI_execute_plan</function>
1510+
except that information about the parameter values to be passed to the
1511+
query is presented differently. The <literal>ParamListInfo</>
1512+
representation can be convenient for passing down values that are
1513+
already available in that format. It also supports use of dynamic
1514+
parameter sets via hook functions specified in <literal>ParamListInfo</>.
1515+
</para>
1516+
</refsect1>
1517+
1518+
<refsect1>
1519+
<title>Arguments</title>
1520+
1521+
<variablelist>
1522+
<varlistentry>
1523+
<term><literal>SPIPlanPtr <parameter>plan</parameter></literal></term>
1524+
<listitem>
1525+
<para>
1526+
execution plan (returned by <function>SPI_prepare</function>)
1527+
</para>
1528+
</listitem>
1529+
</varlistentry>
1530+
1531+
<varlistentry>
1532+
<term><literal>ParamListInfo <parameter>params</parameter></literal></term>
1533+
<listitem>
1534+
<para>
1535+
data structure containing parameter types and values; NULL if none
1536+
</para>
1537+
</listitem>
1538+
</varlistentry>
1539+
1540+
<varlistentry>
1541+
<term><literal>bool <parameter>read_only</parameter></literal></term>
1542+
<listitem>
1543+
<para>
1544+
<literal>true</> for read-only execution
1545+
</para>
1546+
</listitem>
1547+
</varlistentry>
1548+
1549+
<varlistentry>
1550+
<term><literal>long <parameter>count</parameter></literal></term>
1551+
<listitem>
1552+
<para>
1553+
maximum number of rows to process or return
1554+
</para>
1555+
</listitem>
1556+
</varlistentry>
1557+
</variablelist>
1558+
</refsect1>
1559+
1560+
<refsect1>
1561+
<title>Return Value</title>
1562+
1563+
<para>
1564+
The return value is the same as for <function>SPI_execute_plan</function>.
1565+
</para>
1566+
1567+
<para>
1568+
<varname>SPI_processed</varname> and
1569+
<varname>SPI_tuptable</varname> are set as in
1570+
<function>SPI_execute_plan</function> if successful.
13971571
</para>
13981572
</refsect1>
13991573
</refentry>
@@ -1543,7 +1717,7 @@ Portal SPI_cursor_open(const char * <parameter>name</parameter>, SPIPlanPtr <par
15431717
</para>
15441718

15451719
<para>
1546-
The passed-in data will be copied into the cursor's portal, so it
1720+
The passed-in parameter data will be copied into the cursor's portal, so it
15471721
can be freed while the cursor still exists.
15481722
</para>
15491723
</refsect1>
@@ -1667,7 +1841,7 @@ Portal SPI_cursor_open_with_args(const char *<parameter>name</parameter>,
16671841
</para>
16681842

16691843
<para>
1670-
The passed-in data will be copied into the cursor's portal, so it
1844+
The passed-in parameter data will be copied into the cursor's portal, so it
16711845
can be freed while the cursor still exists.
16721846
</para>
16731847
</refsect1>
@@ -1770,6 +1944,104 @@ Portal SPI_cursor_open_with_args(const char *<parameter>name</parameter>,
17701944

17711945
<!-- *********************************************** -->
17721946

1947+
<refentry id="spi-spi-cursor-open-with-paramlist">
1948+
<refmeta>
1949+
<refentrytitle>SPI_cursor_open_with_paramlist</refentrytitle>
1950+
<manvolnum>3</manvolnum>
1951+
</refmeta>
1952+
1953+
<refnamediv>
1954+
<refname>SPI_cursor_open_with_paramlist</refname>
1955+
<refpurpose>set up a cursor using parameters</refpurpose>
1956+
</refnamediv>
1957+
1958+
<indexterm><primary>SPI_cursor_open_with_paramlist</primary></indexterm>
1959+
1960+
<refsynopsisdiv>
1961+
<synopsis>
1962+
Portal SPI_cursor_open_with_paramlist(const char *<parameter>name</parameter>,
1963+
SPIPlanPtr <parameter>plan</parameter>,
1964+
ParamListInfo <parameter>params</parameter>,
1965+
bool <parameter>read_only</parameter>)
1966+
</synopsis>
1967+
</refsynopsisdiv>
1968+
1969+
<refsect1>
1970+
<title>Description</title>
1971+
1972+
<para>
1973+
<function>SPI_cursor_open_with_paramlist</function> sets up a cursor
1974+
(internally, a portal) that will execute a plan prepared by
1975+
<function>SPI_prepare</function>.
1976+
This function is equivalent to <function>SPI_cursor_open</function>
1977+
except that information about the parameter values to be passed to the
1978+
query is presented differently. The <literal>ParamListInfo</>
1979+
representation can be convenient for passing down values that are
1980+
already available in that format. It also supports use of dynamic
1981+
parameter sets via hook functions specified in <literal>ParamListInfo</>.
1982+
</para>
1983+
1984+
<para>
1985+
The passed-in parameter data will be copied into the cursor's portal, so it
1986+
can be freed while the cursor still exists.
1987+
</para>
1988+
</refsect1>
1989+
1990+
<refsect1>
1991+
<title>Arguments</title>
1992+
1993+
<variablelist>
1994+
<varlistentry>
1995+
<term><literal>const char * <parameter>name</parameter></literal></term>
1996+
<listitem>
1997+
<para>
1998+
name for portal, or <symbol>NULL</symbol> to let the system
1999+
select a name
2000+
</para>
2001+
</listitem>
2002+
</varlistentry>
2003+
2004+
<varlistentry>
2005+
<term><literal>SPIPlanPtr <parameter>plan</parameter></literal></term>
2006+
<listitem>
2007+
<para>
2008+
execution plan (returned by <function>SPI_prepare</function>)
2009+
</para>
2010+
</listitem>
2011+
</varlistentry>
2012+
2013+
<varlistentry>
2014+
<term><literal>ParamListInfo <parameter>params</parameter></literal></term>
2015+
<listitem>
2016+
<para>
2017+
data structure containing parameter types and values; NULL if none
2018+
</para>
2019+
</listitem>
2020+
</varlistentry>
2021+
2022+
<varlistentry>
2023+
<term><literal>bool <parameter>read_only</parameter></literal></term>
2024+
<listitem>
2025+
<para>
2026+
<literal>true</> for read-only execution
2027+
</para>
2028+
</listitem>
2029+
</varlistentry>
2030+
</variablelist>
2031+
</refsect1>
2032+
2033+
<refsect1>
2034+
<title>Return Value</title>
2035+
2036+
<para>
2037+
Pointer to portal containing the cursor. Note there is no error
2038+
return convention; any error will be reported via <function>elog</>.
2039+
</para>
2040+
</refsect1>
2041+
</refentry>
2042+
2043+
<!-- *********************************************** -->
2044+
17732045
<refentry id="spi-spi-cursor-find">
17742046
<refmeta>
17752047
<refentrytitle>SPI_cursor_find</refentrytitle>

src/backend/commands/explain.c

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1994-5, Regents of the University of California
88
*
99
* IDENTIFICATION
10-
* $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.192 2009/10/12 18:10:41 tgl Exp $
10+
* $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.193 2009/11/04 22:26:04 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -107,8 +107,6 @@ ExplainQuery(ExplainStmt *stmt, const char *queryString,
107107
ParamListInfo params, DestReceiver *dest)
108108
{
109109
ExplainState es;
110-
Oid *param_types;
111-
int num_params;
112110
TupOutputState *tstate;
113111
List *rewritten;
114112
ListCell *lc;
@@ -150,9 +148,6 @@ ExplainQuery(ExplainStmt *stmt, const char *queryString,
150148
opt->defname)));
151149
}
152150

153-
/* Convert parameter type data to the form parser wants */
154-
getParamListTypes(params, &param_types, &num_params);
155-
156151
/*
157152
* Run parse analysis and rewrite. Note this also acquires sufficient
158153
* locks on the source table(s).
@@ -163,8 +158,10 @@ ExplainQuery(ExplainStmt *stmt, const char *queryString,
163158
* executed repeatedly. (See also the same hack in DECLARE CURSOR and
164159
* PREPARE.) XXX FIXME someday.
165160
*/
166-
rewritten = pg_analyze_and_rewrite((Node *) copyObject(stmt->query),
167-
queryString, param_types, num_params);
161+
rewritten = pg_analyze_and_rewrite_params((Node *) copyObject(stmt->query),
162+
queryString,
163+
(ParserSetupHook) setupParserWithParamList,
164+
params);
168165

169166
/* emit opening boilerplate */
170167
ExplainBeginOutput(&es);

0 commit comments

Comments
 (0)