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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy