index 1f2abbb5d17411c0a92d1df58e8f4019a99bd62d..f8c6435c50e5b3f2a94850ffff11dfcf4a5cce35 100644 (file)
@@ -3849,7 +3849,7 @@ ASSERT <replaceable class="parameter">condition</replaceable> <optional> , <repl
<para>
Data type <type>RECORD</type>; variable holding the new
database row for <command>INSERT</command>/<command>UPDATE</command> operations in row-level
- triggers. This variable is unassigned in statement-level triggers
+ triggers. This variable is null in statement-level triggers
and for <command>DELETE</command> operations.
</para>
</listitem>
@@ -3861,7 +3861,7 @@ ASSERT <replaceable class="parameter">condition</replaceable> <optional> , <repl
<para>
Data type <type>RECORD</type>; variable holding the old
database row for <command>UPDATE</command>/<command>DELETE</command> operations in row-level
- triggers. This variable is unassigned in statement-level triggers
+ triggers. This variable is null in statement-level triggers
and for <command>INSERT</command> operations.
</para>
</listitem>
index f35b0d8cc936e2a1039d7577c21fa009fd8a1412..b129d32264c5df1bc5f8b7e668f653beb79ce23c 100644 (file)
@@ -1033,6 +1033,23 @@ Branch: REL9_3_STABLE [84261eb10] 2018年10月19日 17:02:26 -0400
</para>
</listitem>
+ <listitem>
+<!--
+2018年02月13日 [4b93f5799] Make plpgsql use its DTYPE_REC code paths for composite-
+-->
+
+ <para>
+ In PL/pgSQL trigger functions, the <varname>OLD</varname>
+ and <varname>NEW</varname> variables now read as NULL when not
+ assigned (Tom Lane)
+ </para>
+
+ <para>
+ Previously, references to these variables could be parsed but not
+ executed.
+ </para>
+ </listitem>
+
</itemizedlist>
</sect2>
<listitem>
<!--
2018年02月13日 [4b93f5799] Make plpgsql use its DTYPE_REC code paths for composite-
-
-->
<para>
index 9dd4a74c3468f9366e6a73d1ea61a4ba41b4a54f..f5958d12675f969b66b43921cb751bd30242f198 100644 (file)
@@ -27,7 +27,7 @@ DATA = plpgsql.control plpgsql--1.0.sql plpgsql--unpackaged--1.0.sql
REGRESS_OPTS = --dbname=$(PL_TESTDB)
REGRESS = plpgsql_call plpgsql_control plpgsql_domain plpgsql_record \
- plpgsql_cache plpgsql_transaction plpgsql_varprops
+ plpgsql_cache plpgsql_transaction plpgsql_trigger plpgsql_varprops
GEN_KEYWORDLIST = $(top_srcdir)/src/tools/gen_keywordlist.pl
new file mode 100644
(file)
index 0000000..
3cc67ba
--- /dev/null
+-- Simple test to verify accessibility of the OLD and NEW trigger variables
+create table testtr (a int, b text);
+create function testtr_trigger() returns trigger language plpgsql as
+$$begin
+ raise notice 'tg_op = %', tg_op;
+ raise notice 'old(%) = %', old.a, row(old.*);
+ raise notice 'new(%) = %', new.a, row(new.*);
+ if (tg_op = 'DELETE') then
+ return old;
+ else
+ return new;
+ end if;
+end$$;
+create trigger testtr_trigger before insert or delete or update on testtr
+ for each row execute function testtr_trigger();
+insert into testtr values (1, 'one'), (2, 'two');
+NOTICE: tg_op = INSERT
+NOTICE: old(<NULL>) = (,)
+NOTICE: new(1) = (1,one)
+NOTICE: tg_op = INSERT
+NOTICE: old(<NULL>) = (,)
+NOTICE: new(2) = (2,two)
+update testtr set a = a + 1;
+NOTICE: tg_op = UPDATE
+NOTICE: old(1) = (1,one)
+NOTICE: new(2) = (2,one)
+NOTICE: tg_op = UPDATE
+NOTICE: old(2) = (2,two)
+NOTICE: new(3) = (3,two)
+delete from testtr;
+NOTICE: tg_op = DELETE
+NOTICE: old(2) = (2,one)
+NOTICE: new(<NULL>) = (,)
+NOTICE: tg_op = DELETE
+NOTICE: old(3) = (3,two)
+NOTICE: new(<NULL>) = (,)
index 92e7ec4c6075780389d447b46aecf38ce8c4468a..5c6dbe4c5faf0676567ff82f5dce46ff0f08e1ad 100644 (file)
/*
* Put the OLD and NEW tuples into record variables
*
- * We make the tupdescs available in both records even though only one may
- * have a value. This allows parsing of record references to succeed in
- * functions that are used for multiple trigger types. For example, we
- * might have a test like "if (TG_OP = 'INSERT' and NEW.foo = 'xyz')",
- * which should parse regardless of the current trigger type.
+ * We set up expanded records for both variables even though only one may
+ * have a value. This allows record references to succeed in functions
+ * that are used for multiple trigger types. For example, we might have a
+ * test like "if (TG_OP = 'INSERT' and NEW.foo = 'xyz')", which should
+ * work regardless of the current trigger type. If a value is actually
+ * fetched from an unsupplied tuple, it will read as NULL.
*/
tupdesc = RelationGetDescr(trigdata->tg_relation);
new file mode 100644
(file)
index 0000000..
e04c273
--- /dev/null
+-- Simple test to verify accessibility of the OLD and NEW trigger variables
+
+create table testtr (a int, b text);
+
+create function testtr_trigger() returns trigger language plpgsql as
+$$begin
+ raise notice 'tg_op = %', tg_op;
+ raise notice 'old(%) = %', old.a, row(old.*);
+ raise notice 'new(%) = %', new.a, row(new.*);
+ if (tg_op = 'DELETE') then
+ return old;
+ else
+ return new;
+ end if;
+end$$;
+
+create trigger testtr_trigger before insert or delete or update on testtr
+ for each row execute function testtr_trigger();
+
+insert into testtr values (1, 'one'), (2, 'two');
+
+update testtr set a = a + 1;
+
+delete from testtr;