From be18a12b663181f304d49022a452e31e4df42ff2 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Tue, 7 May 2024 18:15:00 -0400 Subject: Don't corrupt plpython's "TD" dictionary in a recursive trigger call. If a plpython-language trigger caused another one to be invoked, the "TD" dictionary created for the inner one would overwrite the outer one's "TD" dictionary. This is more or less the same problem that 1d2fe56e4 fixed for ordinary functions in plpython, so fix it the same way, by saving and restoring "TD" during a recursive invocation. This fix makes an ABI-incompatible change in struct PLySavedArgs. I'm not too worried about that because it seems highly unlikely that any extension is messing with those structs. We could imagine doing something weird to preserve nominal ABI compatibility in the back branches, like keeping the saved TD object in an extra element of namedargs[]. However, that would only be very nominal compatibility: if anything *is* touching PLySavedArgs, it would likely do the wrong thing due to not knowing about the additional value. So I judge it not worth the ugliness to do something different there. (I also changed struct PLyProcedure, but its added field fits into formerly-padding space, so that should be safe.) Per bug #18456 from Jacques Combrink. This bug is very ancient, so back-patch to all supported branches. Discussion: https://postgr.es/m/3008982.1714853799@sss.pgh.pa.us --- src/pl/plpython/sql/plpython_trigger.sql | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'src/pl/plpython/sql/plpython_trigger.sql') diff --git a/src/pl/plpython/sql/plpython_trigger.sql b/src/pl/plpython/sql/plpython_trigger.sql index e5504b9ab1d..f6c2ef8d6a0 100644 --- a/src/pl/plpython/sql/plpython_trigger.sql +++ b/src/pl/plpython/sql/plpython_trigger.sql @@ -467,3 +467,27 @@ FOR EACH ROW EXECUTE PROCEDURE generated_test_func1(); TRUNCATE trigger_test_generated; INSERT INTO trigger_test_generated (i) VALUES (1); SELECT * FROM trigger_test_generated; + + +-- recursive call of a trigger mustn't corrupt TD (bug #18456) + +CREATE TABLE recursive_trigger_test (a int, b int); + +CREATE FUNCTION recursive_trigger_func() RETURNS trigger +LANGUAGE plpython3u +AS $$ +if TD["event"] == "UPDATE": + plpy.execute("INSERT INTO recursive_trigger_test VALUES (1, 2)") + plpy.notice("TD[event] => " + str(TD["event"]) + ", expecting UPDATE"); +else: + plpy.notice("TD[event] => " + str(TD["event"]) + ", expecting INSERT"); +return None +$$; + +CREATE TRIGGER recursive_trigger_trig + AFTER INSERT OR UPDATE ON recursive_trigger_test + FOR EACH ROW EXECUTE PROCEDURE recursive_trigger_func(); + +INSERT INTO recursive_trigger_test VALUES (0, 0); +UPDATE recursive_trigger_test SET a = 11 WHERE b = 0; +SELECT * FROM recursive_trigger_test; -- cgit v1.2.3