Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 6b449d9

Browse files
committed
Fix declaration of $_TD in "strict" trigger functions
This was broken in commit ef19dc6 by the Bunce/Hunsaker/Dunstan team, which moved the declaration from plperl_create_sub to plperl_call_perl_trigger_func. This doesn't actually work because the validator code would not find the variable declared; and even if you manage to get past the validator, it still doesn't work because get_sv("_TD", GV_ADD) doesn't have the expected effect. The only reason this got beyond testing is that it only fails in strict mode. We need to declare it as a global just like %_SHARED; it is simpler than trying to actually do what the patch initially intended, and is said to have the same performance benefit. As a more serious issue, fix $_TD not being properly local()ized, meaning nested trigger functions would clobber $_TD. Alex Hunsaker, per test report from Greg Mullane
1 parent ea896da commit 6b449d9

File tree

4 files changed

+59
-3
lines changed

4 files changed

+59
-3
lines changed

src/pl/plperl/expected/plperl_trigger.out

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,35 @@ SELECT * FROM trigger_test;
255255
5 | third line(modified by trigger)(modified by trigger) | ("(5)")
256256
(4 rows)
257257

258+
DROP TRIGGER "test_valid_id_trig" ON trigger_test;
259+
CREATE OR REPLACE FUNCTION trigger_recurse() RETURNS trigger AS $$
260+
use strict;
261+
262+
if ($_TD->{new}{i} == 10000)
263+
{
264+
spi_exec_query("insert into trigger_test (i, v) values (20000, 'child');");
265+
266+
if ($_TD->{new}{i} != 10000)
267+
{
268+
die "recursive trigger modified: ". $_TD->{new}{i};
269+
}
270+
}
271+
return;
272+
$$ LANGUAGE plperl;
273+
CREATE TRIGGER "test_trigger_recurse" BEFORE INSERT ON trigger_test
274+
FOR EACH ROW EXECUTE PROCEDURE "trigger_recurse"();
275+
INSERT INTO trigger_test (i, v) values (10000, 'top');
276+
SELECT * FROM trigger_test;
277+
i | v | foo
278+
-------+------------------------------------------------------+---------
279+
1 | first line(modified by trigger) | ("(2)")
280+
2 | second line(modified by trigger) | ("(3)")
281+
4 | immortal | ("(4)")
282+
5 | third line(modified by trigger)(modified by trigger) | ("(5)")
283+
20000 | child |
284+
10000 | top |
285+
(6 rows)
286+
258287
CREATE OR REPLACE FUNCTION immortal() RETURNS trigger AS $$
259288
if ($_TD->{old}{v} eq $_TD->{args}[0])
260289
{

src/pl/plperl/plc_perlboot.pl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# src/pl/plperl/plc_perlboot.pl
22

33
use 5.008001;
4-
use vars qw(%_SHARED);
4+
use vars qw(%_SHARED $_TD);
55

66
PostgreSQL::InServer::Util::bootstrap();
77

src/pl/plperl/plperl.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1976,8 +1976,11 @@ plperl_call_perl_trigger_func(plperl_proc_desc *desc, FunctionCallInfo fcinfo,
19761976
ENTER;
19771977
SAVETMPS;
19781978

1979-
TDsv = get_sv("_TD", GV_ADD);
1980-
SAVESPTR(TDsv); /* local $_TD */
1979+
TDsv = get_sv("_TD", 0);
1980+
if (!TDsv)
1981+
elog(ERROR, "couldn't fetch $_TD");
1982+
1983+
save_item(TDsv); /* local $_TD */
19811984
sv_setsv(TDsv, td);
19821985

19831986
PUSHMARK(sp);

src/pl/plperl/sql/plperl_trigger.sql

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,30 @@ UPDATE trigger_test SET i = 100 where i=1;
122122

123123
SELECT * FROM trigger_test;
124124

125+
DROP TRIGGER "test_valid_id_trig" ON trigger_test;
126+
127+
CREATE OR REPLACE FUNCTION trigger_recurse() RETURNS trigger AS $$
128+
use strict;
129+
130+
if ($_TD->{new}{i} == 10000)
131+
{
132+
spi_exec_query("insert into trigger_test (i, v) values (20000, 'child');");
133+
134+
if ($_TD->{new}{i} != 10000)
135+
{
136+
die "recursive trigger modified: ". $_TD->{new}{i};
137+
}
138+
}
139+
return;
140+
$$ LANGUAGE plperl;
141+
142+
CREATE TRIGGER "test_trigger_recurse" BEFORE INSERT ON trigger_test
143+
FOR EACH ROW EXECUTE PROCEDURE "trigger_recurse"();
144+
145+
INSERT INTO trigger_test (i, v) values (10000, 'top');
146+
147+
SELECT * FROM trigger_test;
148+
125149
CREATE OR REPLACE FUNCTION immortal() RETURNS trigger AS $$
126150
if ($_TD->{old}{v} eq $_TD->{args}[0])
127151
{

0 commit comments

Comments
 (0)