mirror of
https://github.com/postgres/postgres.git
synced 2025-07-31 22:04:40 +03:00
Follow-on cleanup for the transition table patch.
Commit 59702716
added transition table support to PL/pgsql so that
SQL queries in trigger functions could access those transient
tables. In order to provide the same level of support for PL/perl,
PL/python and PL/tcl, refactor the relevant code into a new
function SPI_register_trigger_data. Call the new function in the
trigger handler of all four PLs, and document it as a public SPI
function so that authors of out-of-tree PLs can do the same.
Also get rid of a second QueryEnvironment object that was
maintained by PL/pgsql. That was previously used to deal with
cursors, but the same approach wasn't appropriate for PLs that are
less tangled up with core code. Instead, have SPI_cursor_open
install the connection's current QueryEnvironment, as already
happens for SPI_execute_plan.
While in the docs, remove the note that transition tables were only
supported in C and PL/pgSQL triggers, and correct some ommissions.
Thomas Munro with some work by Kevin Grittner (mostly docs)
This commit is contained in:
@ -8,6 +8,11 @@ PostgreSQL documentation
|
||||
<primary>CREATE TRIGGER</primary>
|
||||
</indexterm>
|
||||
|
||||
<indexterm>
|
||||
<primary>transition tables</primary>
|
||||
<seealso>ephemeral named relation</seealso>
|
||||
</indexterm>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>CREATE TRIGGER</refentrytitle>
|
||||
<manvolnum>7</manvolnum>
|
||||
@ -322,11 +327,6 @@ UPDATE OF <replaceable>column_name1</replaceable> [, <replaceable>column_name2</
|
||||
<para>
|
||||
The (unqualified) name to be used within the trigger for this relation.
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
So far only triggers written in C or PL/pgSQL support this.
|
||||
</para>
|
||||
</note>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
@ -2644,6 +2644,11 @@ SPIPlanPtr SPI_saveplan(SPIPlanPtr <parameter>plan</parameter>)
|
||||
<refentry id="spi-spi-register-relation">
|
||||
<indexterm><primary>SPI_register_relation</primary></indexterm>
|
||||
|
||||
<indexterm>
|
||||
<primary>ephemeral named relation</primary>
|
||||
<secondary>registering with SPI</secondary>
|
||||
</indexterm>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>SPI_register_relation</refentrytitle>
|
||||
<manvolnum>3</manvolnum>
|
||||
@ -2746,6 +2751,11 @@ int SPI_register_relation(EphemeralNamedRelation <parameter>enr</parameter>)
|
||||
<refentry id="spi-spi-unregister-relation">
|
||||
<indexterm><primary>SPI_unregister_relation</primary></indexterm>
|
||||
|
||||
<indexterm>
|
||||
<primary>ephemeral named relation</primary>
|
||||
<secondary>unregistering from SPI</secondary>
|
||||
</indexterm>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>SPI_unregister_relation</refentrytitle>
|
||||
<manvolnum>3</manvolnum>
|
||||
@ -2843,6 +2853,121 @@ int SPI_unregister_relation(const char * <parameter>name</parameter>)
|
||||
|
||||
<!-- *********************************************** -->
|
||||
|
||||
<refentry id="spi-spi-register-trigger-data">
|
||||
<indexterm><primary>SPI_register_trigger_data</primary></indexterm>
|
||||
|
||||
<indexterm>
|
||||
<primary>ephemeral named relation</primary>
|
||||
<secondary>registering with SPI</secondary>
|
||||
</indexterm>
|
||||
|
||||
<indexterm>
|
||||
<primary>transition tables</primary>
|
||||
<secondary>implementation in PLs</secondary>
|
||||
</indexterm>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>SPI_register_trigger_data</refentrytitle>
|
||||
<manvolnum>3</manvolnum>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>SPI_register_trigger_data</refname>
|
||||
<refpurpose>make ephemeral trigger data available in SPI queries</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<synopsis>
|
||||
int SPI_register_trigger_data(TriggerData *<parameter>tdata</parameter>)
|
||||
</synopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para>
|
||||
<function>SPI_register_trigger_data</function> makes any ephemeral
|
||||
relations captured by a trigger available to queries planned and executed
|
||||
through the current SPI connection. Currently, this means the transition
|
||||
tables captured by an <literal>AFTER</literal> trigger defined with a
|
||||
<literal>REFERENCING OLD/NEW TABLE AS</literal> ... clause. This function
|
||||
should be called by a PL trigger handler function after connecting.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Arguments</title>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><literal>TriggerData *<parameter>tdata</parameter></literal></term>
|
||||
<listitem>
|
||||
<para>
|
||||
the <structname>TriggerData</structname> object passed to a trigger
|
||||
handler function as <literal>fcinfo->context</literal>
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Return Value</title>
|
||||
|
||||
<para>
|
||||
If the execution of the command was successful then the following
|
||||
(nonnegative) value will be returned:
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><symbol>SPI_OK_TD_REGISTER</symbol></term>
|
||||
<listitem>
|
||||
<para>
|
||||
if the captured trigger data (if any) has been successfully registered
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
On error, one of the following negative values is returned:
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><symbol>SPI_ERROR_ARGUMENT</symbol></term>
|
||||
<listitem>
|
||||
<para>
|
||||
if <parameter>tdata</parameter> is <symbol>NULL</symbol>
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><symbol>SPI_ERROR_UNCONNECTED</symbol></term>
|
||||
<listitem>
|
||||
<para>
|
||||
if called from an unconnected procedure
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><symbol>SPI_ERROR_REL_DUPLICATE</symbol></term>
|
||||
<listitem>
|
||||
<para>
|
||||
if the name of any trigger data transient relation is already
|
||||
registered for this connection
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</para>
|
||||
</refsect1>
|
||||
</refentry>
|
||||
|
||||
<!-- *********************************************** -->
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="spi-interface-support">
|
||||
|
@ -395,6 +395,11 @@
|
||||
<secondary>in C</secondary>
|
||||
</indexterm>
|
||||
|
||||
<indexterm>
|
||||
<primary>transition tables</primary>
|
||||
<secondary>referencing from C trigger</secondary>
|
||||
</indexterm>
|
||||
|
||||
<para>
|
||||
This section describes the low-level details of the interface to a
|
||||
trigger function. This information is only needed when writing
|
||||
@ -438,14 +443,16 @@ CALLED_AS_TRIGGER(fcinfo)
|
||||
<programlisting>
|
||||
typedef struct TriggerData
|
||||
{
|
||||
NodeTag type;
|
||||
TriggerEvent tg_event;
|
||||
Relation tg_relation;
|
||||
HeapTuple tg_trigtuple;
|
||||
HeapTuple tg_newtuple;
|
||||
Trigger *tg_trigger;
|
||||
Buffer tg_trigtuplebuf;
|
||||
Buffer tg_newtuplebuf;
|
||||
NodeTag type;
|
||||
TriggerEvent tg_event;
|
||||
Relation tg_relation;
|
||||
HeapTuple tg_trigtuple;
|
||||
HeapTuple tg_newtuple;
|
||||
Trigger *tg_trigger;
|
||||
Buffer tg_trigtuplebuf;
|
||||
Buffer tg_newtuplebuf;
|
||||
Tuplestorestate *tg_oldtable;
|
||||
Tuplestorestate *tg_newtable;
|
||||
} TriggerData;
|
||||
</programlisting>
|
||||
|
||||
@ -629,6 +636,8 @@ typedef struct Trigger
|
||||
int16 *tgattr;
|
||||
char **tgargs;
|
||||
char *tgqual;
|
||||
char *tgoldtable;
|
||||
char *tgnewtable;
|
||||
} Trigger;
|
||||
</programlisting>
|
||||
|
||||
@ -662,9 +671,38 @@ typedef struct Trigger
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><structfield>tg_oldtable</></term>
|
||||
<listitem>
|
||||
<para>
|
||||
A pointer to a structure of type <structname>Tuplestorestate</structname>
|
||||
containing zero or more rows in the format specified by
|
||||
<structfield>tg_relation</structfield>, or a <symbol>NULL</> pointer
|
||||
if there is no <literal>OLD TABLE</literal> transition relation.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><structfield>tg_newtable</></term>
|
||||
<listitem>
|
||||
<para>
|
||||
A pointer to a structure of type <structname>Tuplestorestate</structname>
|
||||
containing zero or more rows in the format specified by
|
||||
<structfield>tg_relation</structfield>, or a <symbol>NULL</> pointer
|
||||
if there is no <literal>NEW TABLE</literal> transition relation.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
To allow queries issued through SPI to reference transition tables, see
|
||||
<xref linkend="spi-spi-register-trigger-data">.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
A trigger function must return either a
|
||||
<structname>HeapTuple</> pointer or a <symbol>NULL</> pointer
|
||||
|
Reference in New Issue
Block a user