On Thu, May 5, 2011 at 06:51, Alvaro Herrera <alvhe...@commandprompt.com> wrote: > Excerpts from Alex Hunsaker's message of mié may 04 23:53:34 -0300 2011: > >> After playing with it a bit more I see 2 clear options: >> 1) make $_TD global like %_SHARED. This should not cause any problems >> as we make $_TD private via local() before each trigger call. Also pre >> 9.1 non trigger functions could still access and check the definedness >> of $_TD so if someone was relying on that (for whatever unknown >> reason) that will work again. > > This is strange. Are you saying that there's no decent way to make a > variable global in C code?
Im sure we could... I don't see any reason to do it in C. (performance or otherwise) In other news I found another bug with this-- it was trying to local($_TD) by using SAVESPTR() when it seems it really should be using save_item(). Currently its not really localizing $_TD, which at the very least means recursive triggers might modify the callers $_TD. Ugh. Fixed in the attached plus added regression tests for both issues (use strict; && Global symbol "$_TD" requires explicit package name, test recursive trigger calls). Although Ill admit, given the point we are in the release I could see a revert also being justified. Greg, big thanks for testing! keep it up! :)
*** a/src/pl/plperl/expected/plperl_trigger.out --- b/src/pl/plperl/expected/plperl_trigger.out *************** *** 255,260 **** SELECT * FROM trigger_test; --- 255,289 ---- 5 | third line(modified by trigger)(modified by trigger) | ("(5)") (4 rows) + DROP TRIGGER "test_valid_id_trig" ON trigger_test; + CREATE OR REPLACE FUNCTION trigger_recurse() RETURNS trigger AS $$ + use strict; + + if ($_TD->{new}{i} == 10000) + { + spi_exec_query("insert into trigger_test (i, v) values (20000, 'child');"); + + if ($_TD->{new}{i} != 10000) + { + die "recursive trigger modified: ". $_TD->{new}{i}; + } + } + return; + $$ LANGUAGE plperl; + CREATE TRIGGER "test_trigger_recurse" BEFORE INSERT ON trigger_test + FOR EACH ROW EXECUTE PROCEDURE "trigger_recurse"(); + INSERT INTO trigger_test (i, v) values (10000, 'top'); + SELECT * FROM trigger_test; + i | v | foo + -------+------------------------------------------------------+--------- + 1 | first line(modified by trigger) | ("(2)") + 2 | second line(modified by trigger) | ("(3)") + 4 | immortal | ("(4)") + 5 | third line(modified by trigger)(modified by trigger) | ("(5)") + 20000 | child | + 10000 | top | + (6 rows) + CREATE OR REPLACE FUNCTION immortal() RETURNS trigger AS $$ if ($_TD->{old}{v} eq $_TD->{args}[0]) { *** a/src/pl/plperl/plc_perlboot.pl --- b/src/pl/plperl/plc_perlboot.pl *************** *** 1,7 **** # src/pl/plperl/plc_perlboot.pl use 5.008001; ! use vars qw(%_SHARED); PostgreSQL::InServer::Util::bootstrap(); --- 1,7 ---- # src/pl/plperl/plc_perlboot.pl use 5.008001; ! use vars qw(%_SHARED $_TD); PostgreSQL::InServer::Util::bootstrap(); *** a/src/pl/plperl/plperl.c --- b/src/pl/plperl/plperl.c *************** *** 1976,1983 **** plperl_call_perl_trigger_func(plperl_proc_desc *desc, FunctionCallInfo fcinfo, ENTER; SAVETMPS; ! TDsv = get_sv("_TD", GV_ADD); ! SAVESPTR(TDsv); /* local $_TD */ sv_setsv(TDsv, td); PUSHMARK(sp); --- 1976,1986 ---- ENTER; SAVETMPS; ! TDsv = get_sv("_TD", 0); ! if(!TDsv) ! elog(ERROR, "couldn't fetch $_TD"); ! ! save_item(TDsv); /* local $_TD */ sv_setsv(TDsv, td); PUSHMARK(sp); *** a/src/pl/plperl/sql/plperl_trigger.sql --- b/src/pl/plperl/sql/plperl_trigger.sql *************** *** 122,127 **** UPDATE trigger_test SET i = 100 where i=1; --- 122,151 ---- SELECT * FROM trigger_test; + DROP TRIGGER "test_valid_id_trig" ON trigger_test; + + CREATE OR REPLACE FUNCTION trigger_recurse() RETURNS trigger AS $$ + use strict; + + if ($_TD->{new}{i} == 10000) + { + spi_exec_query("insert into trigger_test (i, v) values (20000, 'child');"); + + if ($_TD->{new}{i} != 10000) + { + die "recursive trigger modified: ". $_TD->{new}{i}; + } + } + return; + $$ LANGUAGE plperl; + + CREATE TRIGGER "test_trigger_recurse" BEFORE INSERT ON trigger_test + FOR EACH ROW EXECUTE PROCEDURE "trigger_recurse"(); + + INSERT INTO trigger_test (i, v) values (10000, 'top'); + + SELECT * FROM trigger_test; + CREATE OR REPLACE FUNCTION immortal() RETURNS trigger AS $$ if ($_TD->{old}{v} eq $_TD->{args}[0]) {
-- Sent via pgsql-bugs mailing list (pgsql-bugs@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-bugs