1-- these triggers are dedicated to HPHC of RI who
2-- decided that my kid's name was william not willem, and
3-- vigorously resisted all efforts at correction.  they have
4-- since gone bankrupt...
5CREATE FUNCTION users_insert() returns trigger
6	AS
7'if TD["new"]["fname"] == None or TD["new"]["lname"] == None:
8	return "SKIP"
9if TD["new"]["username"] == None:
10	TD["new"]["username"] = TD["new"]["fname"][:1] + "_" + TD["new"]["lname"]
11	rv = "MODIFY"
12else:
13	rv = None
14if TD["new"]["fname"] == "william":
15	TD["new"]["fname"] = TD["args"][0]
16	rv = "MODIFY"
17return rv'
18	LANGUAGE plpythonu;
19CREATE FUNCTION users_update() returns trigger
20	AS
21'if TD["event"] == "UPDATE":
22	if TD["old"]["fname"] != TD["new"]["fname"] and TD["old"]["fname"] == TD["args"][0]:
23		return "SKIP"
24return None'
25	LANGUAGE plpythonu;
26CREATE FUNCTION users_delete() RETURNS trigger
27	AS
28'if TD["old"]["fname"] == TD["args"][0]:
29	return "SKIP"
30return None'
31	LANGUAGE plpythonu;
32CREATE TRIGGER users_insert_trig BEFORE INSERT ON users FOR EACH ROW
33	EXECUTE PROCEDURE users_insert ('willem');
34CREATE TRIGGER users_update_trig BEFORE UPDATE ON users FOR EACH ROW
35	EXECUTE PROCEDURE users_update ('willem');
36CREATE TRIGGER users_delete_trig BEFORE DELETE ON users FOR EACH ROW
37	EXECUTE PROCEDURE users_delete ('willem');
38-- quick peek at the table
39--
40SELECT * FROM users;
41 fname  | lname | username | userid
42--------+-------+----------+--------
43 jane   | doe   | j_doe    |      1
44 john   | doe   | johnd    |      2
45 willem | doe   | w_doe    |      3
46 rick   | smith | slash    |      4
47(4 rows)
48
49-- should fail
50--
51UPDATE users SET fname = 'william' WHERE fname = 'willem';
52-- should modify william to willem and create username
53--
54INSERT INTO users (fname, lname) VALUES ('william', 'smith');
55INSERT INTO users (fname, lname, username) VALUES ('charles', 'darwin', 'beagle');
56SELECT * FROM users;
57  fname  | lname  | username | userid
58---------+--------+----------+--------
59 jane    | doe    | j_doe    |      1
60 john    | doe    | johnd    |      2
61 willem  | doe    | w_doe    |      3
62 rick    | smith  | slash    |      4
63 willem  | smith  | w_smith  |      5
64 charles | darwin | beagle   |      6
65(6 rows)
66
67-- dump trigger data
68CREATE TABLE trigger_test
69	(i int, v text );
70CREATE FUNCTION trigger_data() RETURNS trigger LANGUAGE plpythonu AS $$
71
72if 'relid' in TD:
73	TD['relid'] = "bogus:12345"
74
75skeys = list(TD.keys())
76skeys.sort()
77for key in skeys:
78    val = TD[key]
79    if not isinstance(val, dict):
80        plpy.notice("TD[" + key + "] => " + str(val))
81    else:
82        # print dicts the hard way because otherwise the order is implementation-dependent
83        valkeys = list(val.keys())
84        valkeys.sort()
85        plpy.notice("TD[" + key + "] => " + '{' + ', '.join([repr(k) + ': ' + repr(val[k]) for k in valkeys]) + '}')
86
87return None
88
89$$;
90CREATE TRIGGER show_trigger_data_trig_before
91BEFORE INSERT OR UPDATE OR DELETE ON trigger_test
92FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
93CREATE TRIGGER show_trigger_data_trig_after
94AFTER INSERT OR UPDATE OR DELETE ON trigger_test
95FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
96CREATE TRIGGER show_trigger_data_trig_stmt
97BEFORE INSERT OR UPDATE OR DELETE OR TRUNCATE ON trigger_test
98FOR EACH STATEMENT EXECUTE PROCEDURE trigger_data(23,'skidoo');
99insert into trigger_test values(1,'insert');
100NOTICE:  TD[args] => ['23', 'skidoo']
101NOTICE:  TD[event] => INSERT
102NOTICE:  TD[level] => STATEMENT
103NOTICE:  TD[name] => show_trigger_data_trig_stmt
104NOTICE:  TD[new] => None
105NOTICE:  TD[old] => None
106NOTICE:  TD[relid] => bogus:12345
107NOTICE:  TD[table_name] => trigger_test
108NOTICE:  TD[table_schema] => public
109NOTICE:  TD[when] => BEFORE
110NOTICE:  TD[args] => ['23', 'skidoo']
111NOTICE:  TD[event] => INSERT
112NOTICE:  TD[level] => ROW
113NOTICE:  TD[name] => show_trigger_data_trig_before
114NOTICE:  TD[new] => {'i': 1, 'v': 'insert'}
115NOTICE:  TD[old] => None
116NOTICE:  TD[relid] => bogus:12345
117NOTICE:  TD[table_name] => trigger_test
118NOTICE:  TD[table_schema] => public
119NOTICE:  TD[when] => BEFORE
120NOTICE:  TD[args] => ['23', 'skidoo']
121NOTICE:  TD[event] => INSERT
122NOTICE:  TD[level] => ROW
123NOTICE:  TD[name] => show_trigger_data_trig_after
124NOTICE:  TD[new] => {'i': 1, 'v': 'insert'}
125NOTICE:  TD[old] => None
126NOTICE:  TD[relid] => bogus:12345
127NOTICE:  TD[table_name] => trigger_test
128NOTICE:  TD[table_schema] => public
129NOTICE:  TD[when] => AFTER
130update trigger_test set v = 'update' where i = 1;
131NOTICE:  TD[args] => ['23', 'skidoo']
132NOTICE:  TD[event] => UPDATE
133NOTICE:  TD[level] => STATEMENT
134NOTICE:  TD[name] => show_trigger_data_trig_stmt
135NOTICE:  TD[new] => None
136NOTICE:  TD[old] => None
137NOTICE:  TD[relid] => bogus:12345
138NOTICE:  TD[table_name] => trigger_test
139NOTICE:  TD[table_schema] => public
140NOTICE:  TD[when] => BEFORE
141NOTICE:  TD[args] => ['23', 'skidoo']
142NOTICE:  TD[event] => UPDATE
143NOTICE:  TD[level] => ROW
144NOTICE:  TD[name] => show_trigger_data_trig_before
145NOTICE:  TD[new] => {'i': 1, 'v': 'update'}
146NOTICE:  TD[old] => {'i': 1, 'v': 'insert'}
147NOTICE:  TD[relid] => bogus:12345
148NOTICE:  TD[table_name] => trigger_test
149NOTICE:  TD[table_schema] => public
150NOTICE:  TD[when] => BEFORE
151NOTICE:  TD[args] => ['23', 'skidoo']
152NOTICE:  TD[event] => UPDATE
153NOTICE:  TD[level] => ROW
154NOTICE:  TD[name] => show_trigger_data_trig_after
155NOTICE:  TD[new] => {'i': 1, 'v': 'update'}
156NOTICE:  TD[old] => {'i': 1, 'v': 'insert'}
157NOTICE:  TD[relid] => bogus:12345
158NOTICE:  TD[table_name] => trigger_test
159NOTICE:  TD[table_schema] => public
160NOTICE:  TD[when] => AFTER
161delete from trigger_test;
162NOTICE:  TD[args] => ['23', 'skidoo']
163NOTICE:  TD[event] => DELETE
164NOTICE:  TD[level] => STATEMENT
165NOTICE:  TD[name] => show_trigger_data_trig_stmt
166NOTICE:  TD[new] => None
167NOTICE:  TD[old] => None
168NOTICE:  TD[relid] => bogus:12345
169NOTICE:  TD[table_name] => trigger_test
170NOTICE:  TD[table_schema] => public
171NOTICE:  TD[when] => BEFORE
172NOTICE:  TD[args] => ['23', 'skidoo']
173NOTICE:  TD[event] => DELETE
174NOTICE:  TD[level] => ROW
175NOTICE:  TD[name] => show_trigger_data_trig_before
176NOTICE:  TD[new] => None
177NOTICE:  TD[old] => {'i': 1, 'v': 'update'}
178NOTICE:  TD[relid] => bogus:12345
179NOTICE:  TD[table_name] => trigger_test
180NOTICE:  TD[table_schema] => public
181NOTICE:  TD[when] => BEFORE
182NOTICE:  TD[args] => ['23', 'skidoo']
183NOTICE:  TD[event] => DELETE
184NOTICE:  TD[level] => ROW
185NOTICE:  TD[name] => show_trigger_data_trig_after
186NOTICE:  TD[new] => None
187NOTICE:  TD[old] => {'i': 1, 'v': 'update'}
188NOTICE:  TD[relid] => bogus:12345
189NOTICE:  TD[table_name] => trigger_test
190NOTICE:  TD[table_schema] => public
191NOTICE:  TD[when] => AFTER
192truncate table trigger_test;
193NOTICE:  TD[args] => ['23', 'skidoo']
194NOTICE:  TD[event] => TRUNCATE
195NOTICE:  TD[level] => STATEMENT
196NOTICE:  TD[name] => show_trigger_data_trig_stmt
197NOTICE:  TD[new] => None
198NOTICE:  TD[old] => None
199NOTICE:  TD[relid] => bogus:12345
200NOTICE:  TD[table_name] => trigger_test
201NOTICE:  TD[table_schema] => public
202NOTICE:  TD[when] => BEFORE
203DROP TRIGGER show_trigger_data_trig_stmt on trigger_test;
204DROP TRIGGER show_trigger_data_trig_before on trigger_test;
205DROP TRIGGER show_trigger_data_trig_after on trigger_test;
206insert into trigger_test values(1,'insert');
207CREATE VIEW trigger_test_view AS SELECT * FROM trigger_test;
208CREATE TRIGGER show_trigger_data_trig
209INSTEAD OF INSERT OR UPDATE OR DELETE ON trigger_test_view
210FOR EACH ROW EXECUTE PROCEDURE trigger_data(24,'skidoo view');
211insert into trigger_test_view values(2,'insert');
212NOTICE:  TD[args] => ['24', 'skidoo view']
213NOTICE:  TD[event] => INSERT
214NOTICE:  TD[level] => ROW
215NOTICE:  TD[name] => show_trigger_data_trig
216NOTICE:  TD[new] => {'i': 2, 'v': 'insert'}
217NOTICE:  TD[old] => None
218NOTICE:  TD[relid] => bogus:12345
219NOTICE:  TD[table_name] => trigger_test_view
220NOTICE:  TD[table_schema] => public
221NOTICE:  TD[when] => INSTEAD OF
222update trigger_test_view set v = 'update' where i = 1;
223NOTICE:  TD[args] => ['24', 'skidoo view']
224NOTICE:  TD[event] => UPDATE
225NOTICE:  TD[level] => ROW
226NOTICE:  TD[name] => show_trigger_data_trig
227NOTICE:  TD[new] => {'i': 1, 'v': 'update'}
228NOTICE:  TD[old] => {'i': 1, 'v': 'insert'}
229NOTICE:  TD[relid] => bogus:12345
230NOTICE:  TD[table_name] => trigger_test_view
231NOTICE:  TD[table_schema] => public
232NOTICE:  TD[when] => INSTEAD OF
233delete from trigger_test_view;
234NOTICE:  TD[args] => ['24', 'skidoo view']
235NOTICE:  TD[event] => DELETE
236NOTICE:  TD[level] => ROW
237NOTICE:  TD[name] => show_trigger_data_trig
238NOTICE:  TD[new] => None
239NOTICE:  TD[old] => {'i': 1, 'v': 'insert'}
240NOTICE:  TD[relid] => bogus:12345
241NOTICE:  TD[table_name] => trigger_test_view
242NOTICE:  TD[table_schema] => public
243NOTICE:  TD[when] => INSTEAD OF
244DROP FUNCTION trigger_data() CASCADE;
245NOTICE:  drop cascades to trigger show_trigger_data_trig on view trigger_test_view
246DROP VIEW trigger_test_view;
247delete from trigger_test;
248--
249-- trigger error handling
250--
251INSERT INTO trigger_test VALUES (0, 'zero');
252-- returning non-string from trigger function
253CREATE FUNCTION stupid1() RETURNS trigger
254AS $$
255    return 37
256$$ LANGUAGE plpythonu;
257CREATE TRIGGER stupid_trigger1
258BEFORE INSERT ON trigger_test
259FOR EACH ROW EXECUTE PROCEDURE stupid1();
260INSERT INTO trigger_test VALUES (1, 'one');
261ERROR:  unexpected return value from trigger procedure
262DETAIL:  Expected None or a string.
263CONTEXT:  PL/Python function "stupid1"
264DROP TRIGGER stupid_trigger1 ON trigger_test;
265-- returning MODIFY from DELETE trigger
266CREATE FUNCTION stupid2() RETURNS trigger
267AS $$
268    return "MODIFY"
269$$ LANGUAGE plpythonu;
270CREATE TRIGGER stupid_trigger2
271BEFORE DELETE ON trigger_test
272FOR EACH ROW EXECUTE PROCEDURE stupid2();
273DELETE FROM trigger_test WHERE i = 0;
274WARNING:  PL/Python trigger function returned "MODIFY" in a DELETE trigger -- ignored
275DROP TRIGGER stupid_trigger2 ON trigger_test;
276INSERT INTO trigger_test VALUES (0, 'zero');
277-- returning unrecognized string from trigger function
278CREATE FUNCTION stupid3() RETURNS trigger
279AS $$
280    return "foo"
281$$ LANGUAGE plpythonu;
282CREATE TRIGGER stupid_trigger3
283BEFORE UPDATE ON trigger_test
284FOR EACH ROW EXECUTE PROCEDURE stupid3();
285UPDATE trigger_test SET v = 'null' WHERE i = 0;
286ERROR:  unexpected return value from trigger procedure
287DETAIL:  Expected None, "OK", "SKIP", or "MODIFY".
288CONTEXT:  PL/Python function "stupid3"
289DROP TRIGGER stupid_trigger3 ON trigger_test;
290-- Unicode variant
291CREATE FUNCTION stupid3u() RETURNS trigger
292AS $$
293    return u"foo"
294$$ LANGUAGE plpythonu;
295CREATE TRIGGER stupid_trigger3
296BEFORE UPDATE ON trigger_test
297FOR EACH ROW EXECUTE PROCEDURE stupid3u();
298UPDATE trigger_test SET v = 'null' WHERE i = 0;
299ERROR:  unexpected return value from trigger procedure
300DETAIL:  Expected None, "OK", "SKIP", or "MODIFY".
301CONTEXT:  PL/Python function "stupid3u"
302DROP TRIGGER stupid_trigger3 ON trigger_test;
303-- deleting the TD dictionary
304CREATE FUNCTION stupid4() RETURNS trigger
305AS $$
306    del TD["new"]
307    return "MODIFY";
308$$ LANGUAGE plpythonu;
309CREATE TRIGGER stupid_trigger4
310BEFORE UPDATE ON trigger_test
311FOR EACH ROW EXECUTE PROCEDURE stupid4();
312UPDATE trigger_test SET v = 'null' WHERE i = 0;
313ERROR:  TD["new"] deleted, cannot modify row
314CONTEXT:  while modifying trigger row
315PL/Python function "stupid4"
316DROP TRIGGER stupid_trigger4 ON trigger_test;
317-- TD not a dictionary
318CREATE FUNCTION stupid5() RETURNS trigger
319AS $$
320    TD["new"] = ['foo', 'bar']
321    return "MODIFY";
322$$ LANGUAGE plpythonu;
323CREATE TRIGGER stupid_trigger5
324BEFORE UPDATE ON trigger_test
325FOR EACH ROW EXECUTE PROCEDURE stupid5();
326UPDATE trigger_test SET v = 'null' WHERE i = 0;
327ERROR:  TD["new"] is not a dictionary
328CONTEXT:  while modifying trigger row
329PL/Python function "stupid5"
330DROP TRIGGER stupid_trigger5 ON trigger_test;
331-- TD not having string keys
332CREATE FUNCTION stupid6() RETURNS trigger
333AS $$
334    TD["new"] = {1: 'foo', 2: 'bar'}
335    return "MODIFY";
336$$ LANGUAGE plpythonu;
337CREATE TRIGGER stupid_trigger6
338BEFORE UPDATE ON trigger_test
339FOR EACH ROW EXECUTE PROCEDURE stupid6();
340UPDATE trigger_test SET v = 'null' WHERE i = 0;
341ERROR:  TD["new"] dictionary key at ordinal position 0 is not a string
342CONTEXT:  while modifying trigger row
343PL/Python function "stupid6"
344DROP TRIGGER stupid_trigger6 ON trigger_test;
345-- TD keys not corresponding to row columns
346CREATE FUNCTION stupid7() RETURNS trigger
347AS $$
348    TD["new"] = {'v': 'foo', 'a': 'bar'}
349    return "MODIFY";
350$$ LANGUAGE plpythonu;
351CREATE TRIGGER stupid_trigger7
352BEFORE UPDATE ON trigger_test
353FOR EACH ROW EXECUTE PROCEDURE stupid7();
354UPDATE trigger_test SET v = 'null' WHERE i = 0;
355ERROR:  key "a" found in TD["new"] does not exist as a column in the triggering row
356CONTEXT:  while modifying trigger row
357PL/Python function "stupid7"
358DROP TRIGGER stupid_trigger7 ON trigger_test;
359-- Unicode variant
360CREATE FUNCTION stupid7u() RETURNS trigger
361AS $$
362    TD["new"] = {u'v': 'foo', u'a': 'bar'}
363    return "MODIFY"
364$$ LANGUAGE plpythonu;
365CREATE TRIGGER stupid_trigger7
366BEFORE UPDATE ON trigger_test
367FOR EACH ROW EXECUTE PROCEDURE stupid7u();
368UPDATE trigger_test SET v = 'null' WHERE i = 0;
369ERROR:  key "a" found in TD["new"] does not exist as a column in the triggering row
370CONTEXT:  while modifying trigger row
371PL/Python function "stupid7u"
372DROP TRIGGER stupid_trigger7 ON trigger_test;
373-- calling a trigger function directly
374SELECT stupid7();
375ERROR:  trigger functions can only be called as triggers
376--
377-- Null values
378--
379SELECT * FROM trigger_test;
380 i |  v
381---+------
382 0 | zero
383(1 row)
384
385CREATE FUNCTION test_null() RETURNS trigger
386AS $$
387    TD["new"]['v'] = None
388    return "MODIFY"
389$$ LANGUAGE plpythonu;
390CREATE TRIGGER test_null_trigger
391BEFORE UPDATE ON trigger_test
392FOR EACH ROW EXECUTE PROCEDURE test_null();
393UPDATE trigger_test SET v = 'null' WHERE i = 0;
394DROP TRIGGER test_null_trigger ON trigger_test;
395SELECT * FROM trigger_test;
396 i | v
397---+---
398 0 |
399(1 row)
400
401--
402-- Test that triggers honor typmod when assigning to tuple fields,
403-- as per an early 9.0 bug report
404--
405SET DateStyle = 'ISO';
406CREATE FUNCTION set_modif_time() RETURNS trigger AS $$
407    TD['new']['modif_time'] = '2010-10-13 21:57:28.930486'
408    return 'MODIFY'
409$$ LANGUAGE plpythonu;
410CREATE TABLE pb (a TEXT, modif_time TIMESTAMP(0) WITHOUT TIME ZONE);
411CREATE TRIGGER set_modif_time BEFORE UPDATE ON pb
412  FOR EACH ROW EXECUTE PROCEDURE set_modif_time();
413INSERT INTO pb VALUES ('a', '2010-10-09 21:57:33.930486');
414SELECT * FROM pb;
415 a |     modif_time
416---+---------------------
417 a | 2010-10-09 21:57:34
418(1 row)
419
420UPDATE pb SET a = 'b';
421SELECT * FROM pb;
422 a |     modif_time
423---+---------------------
424 b | 2010-10-13 21:57:29
425(1 row)
426
427-- triggers for tables with composite types
428CREATE TABLE comp1 (i integer, j boolean);
429CREATE TYPE comp2 AS (k integer, l boolean);
430CREATE TABLE composite_trigger_test (f1 comp1, f2 comp2);
431CREATE FUNCTION composite_trigger_f() RETURNS trigger AS $$
432    TD['new']['f1'] = (3, False)
433    TD['new']['f2'] = {'k': 7, 'l': 'yes', 'ignored': 10}
434    return 'MODIFY'
435$$ LANGUAGE plpythonu;
436CREATE TRIGGER composite_trigger BEFORE INSERT ON composite_trigger_test
437  FOR EACH ROW EXECUTE PROCEDURE composite_trigger_f();
438INSERT INTO composite_trigger_test VALUES (NULL, NULL);
439SELECT * FROM composite_trigger_test;
440  f1   |  f2
441-------+-------
442 (3,f) | (7,t)
443(1 row)
444
445-- triggers with composite type columns (bug #6559)
446CREATE TABLE composite_trigger_noop_test (f1 comp1, f2 comp2);
447CREATE FUNCTION composite_trigger_noop_f() RETURNS trigger AS $$
448    return 'MODIFY'
449$$ LANGUAGE plpythonu;
450CREATE TRIGGER composite_trigger_noop BEFORE INSERT ON composite_trigger_noop_test
451  FOR EACH ROW EXECUTE PROCEDURE composite_trigger_noop_f();
452INSERT INTO composite_trigger_noop_test VALUES (NULL, NULL);
453INSERT INTO composite_trigger_noop_test VALUES (ROW(1, 'f'), NULL);
454INSERT INTO composite_trigger_noop_test VALUES (ROW(NULL, 't'), ROW(1, 'f'));
455SELECT * FROM composite_trigger_noop_test;
456  f1   |  f2
457-------+-------
458       |
459 (1,f) |
460 (,t)  | (1,f)
461(3 rows)
462
463-- nested composite types
464CREATE TYPE comp3 AS (c1 comp1, c2 comp2, m integer);
465CREATE TABLE composite_trigger_nested_test(c comp3);
466CREATE FUNCTION composite_trigger_nested_f() RETURNS trigger AS $$
467    return 'MODIFY'
468$$ LANGUAGE plpythonu;
469CREATE TRIGGER composite_trigger_nested BEFORE INSERT ON composite_trigger_nested_test
470  FOR EACH ROW EXECUTE PROCEDURE composite_trigger_nested_f();
471INSERT INTO composite_trigger_nested_test VALUES (NULL);
472INSERT INTO composite_trigger_nested_test VALUES (ROW(ROW(1, 'f'), NULL, 3));
473INSERT INTO composite_trigger_nested_test VALUES (ROW(ROW(NULL, 't'), ROW(1, 'f'), NULL));
474SELECT * FROM composite_trigger_nested_test;
475         c
476-------------------
477
478 ("(1,f)",,3)
479 ("(,t)","(1,f)",)
480(3 rows)
481
482-- check that using a function as a trigger over two tables works correctly
483CREATE FUNCTION trig1234() RETURNS trigger LANGUAGE plpythonu AS $$
484    TD["new"]["data"] = '1234'
485    return 'MODIFY'
486$$;
487CREATE TABLE a(data text);
488CREATE TABLE b(data int); -- different type conversion
489CREATE TRIGGER a_t BEFORE INSERT ON a FOR EACH ROW EXECUTE PROCEDURE trig1234();
490CREATE TRIGGER b_t BEFORE INSERT ON b FOR EACH ROW EXECUTE PROCEDURE trig1234();
491INSERT INTO a DEFAULT VALUES;
492SELECT * FROM a;
493 data
494------
495 1234
496(1 row)
497
498DROP TABLE a;
499INSERT INTO b DEFAULT VALUES;
500SELECT * FROM b;
501 data
502------
503 1234
504(1 row)
505
506-- check that SQL run in trigger code can see transition tables
507CREATE TABLE transition_table_test (id int, name text);
508INSERT INTO transition_table_test VALUES (1, 'a');
509CREATE FUNCTION transition_table_test_f() RETURNS trigger LANGUAGE plpythonu AS
510$$
511    rv = plpy.execute("SELECT * FROM old_table")
512    assert(rv.nrows() == 1)
513    plpy.info("old: " + str(rv[0]["id"]) + " -> " + rv[0]["name"])
514    rv = plpy.execute("SELECT * FROM new_table")
515    assert(rv.nrows() == 1)
516    plpy.info("new: " + str(rv[0]["id"]) + " -> " + rv[0]["name"])
517    return None
518$$;
519CREATE TRIGGER a_t AFTER UPDATE ON transition_table_test
520  REFERENCING OLD TABLE AS old_table NEW TABLE AS new_table
521  FOR EACH STATEMENT EXECUTE PROCEDURE transition_table_test_f();
522UPDATE transition_table_test SET name = 'b';
523INFO:  old: 1 -> a
524INFO:  new: 1 -> b
525DROP TABLE transition_table_test;
526DROP FUNCTION transition_table_test_f();
527