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