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

Commit 220e6bf

Browse files
committed
Fix plperl to do recursion safely, and fix a problem with array results.
Add suitable regression tests. Andrew Dunstan
1 parent a1a64bb commit 220e6bf

File tree

3 files changed

+128
-19
lines changed

3 files changed

+128
-19
lines changed

src/pl/plperl/expected/plperl.out

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,3 +367,56 @@ SELECT * from perl_spi_func();
367367
2
368368
(2 rows)
369369

370+
---
371+
--- Test recursion via SPI
372+
---
373+
CREATE OR REPLACE FUNCTION recurse(i int) RETURNS SETOF TEXT LANGUAGE plperl
374+
AS $$
375+
376+
my $i = shift;
377+
foreach my $x (1..$i)
378+
{
379+
return_next "hello $x";
380+
}
381+
if ($i > 2)
382+
{
383+
my $z = $i-1;
384+
my $cursor = spi_query("select * from recurse($z)");
385+
while (defined(my $row = spi_fetchrow($cursor)))
386+
{
387+
return_next "recurse $i: $row->{recurse}";
388+
}
389+
}
390+
return undef;
391+
392+
$$;
393+
SELECT * FROM recurse(2);
394+
recurse
395+
---------
396+
hello 1
397+
hello 2
398+
(2 rows)
399+
400+
SELECT * FROM recurse(3);
401+
recurse
402+
--------------------
403+
hello 1
404+
hello 2
405+
hello 3
406+
recurse 3: hello 1
407+
recurse 3: hello 2
408+
(5 rows)
409+
410+
---
411+
--- Test arrary return
412+
---
413+
CREATE OR REPLACE FUNCTION array_of_text() RETURNS TEXT[][]
414+
LANGUAGE plperl as $$
415+
return [['a"b','c,d'],['e\\f','g']];
416+
$$;
417+
SELECT array_of_text();
418+
array_of_text
419+
-----------------------------
420+
{{"a\"b","c,d"},{"e\\f",g}}
421+
(1 row)
422+

src/pl/plperl/plperl.c

Lines changed: 34 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
* ENHANCEMENTS, OR MODIFICATIONS.
3434
*
3535
* IDENTIFICATION
36-
* $PostgreSQL: pgsql/src/pl/plperl/plperl.c,v 1.84 2005/07/10 16:13:13 momjian Exp $
36+
* $PostgreSQL: pgsql/src/pl/plperl/plperl.c,v 1.85 2005/07/12 01:16:21 tgl Exp $
3737
*
3838
**********************************************************************/
3939

@@ -90,9 +90,6 @@ typedef struct plperl_proc_desc
9090
FmgrInfo arg_out_func[FUNC_MAX_ARGS];
9191
bool arg_is_rowtype[FUNC_MAX_ARGS];
9292
SV *reference;
93-
FunctionCallInfo caller_info;
94-
Tuplestorestate *tuple_store;
95-
TupleDesc tuple_desc;
9693
} plperl_proc_desc;
9794

9895

@@ -106,8 +103,11 @@ static HV *plperl_proc_hash = NULL;
106103

107104
static bool plperl_use_strict = false;
108105

109-
/* this is saved and restored by plperl_call_handler */
106+
/* these are saved and restored by plperl_call_handler */
110107
static plperl_proc_desc *plperl_current_prodesc = NULL;
108+
static FunctionCallInfo plperl_current_caller_info;
109+
static Tuplestorestate *plperl_current_tuple_store;
110+
static TupleDesc plperl_current_tuple_desc;
111111

112112
/**********************************************************************
113113
* Forward declarations
@@ -577,10 +577,16 @@ plperl_call_handler(PG_FUNCTION_ARGS)
577577
{
578578
Datum retval;
579579
plperl_proc_desc *save_prodesc;
580+
FunctionCallInfo save_caller_info;
581+
Tuplestorestate *save_tuple_store;
582+
TupleDesc save_tuple_desc;
580583

581584
plperl_init_all();
582585

583586
save_prodesc = plperl_current_prodesc;
587+
save_caller_info = plperl_current_caller_info;
588+
save_tuple_store = plperl_current_tuple_store;
589+
save_tuple_desc = plperl_current_tuple_desc;
584590

585591
PG_TRY();
586592
{
@@ -592,11 +598,17 @@ plperl_call_handler(PG_FUNCTION_ARGS)
592598
PG_CATCH();
593599
{
594600
plperl_current_prodesc = save_prodesc;
601+
plperl_current_caller_info = save_caller_info;
602+
plperl_current_tuple_store = save_tuple_store;
603+
plperl_current_tuple_desc = save_tuple_desc;
595604
PG_RE_THROW();
596605
}
597606
PG_END_TRY();
598607

599608
plperl_current_prodesc = save_prodesc;
609+
plperl_current_caller_info = save_caller_info;
610+
plperl_current_tuple_store = save_tuple_store;
611+
plperl_current_tuple_desc = save_tuple_desc;
600612

601613
return retval;
602614
}
@@ -897,16 +909,17 @@ plperl_func_handler(PG_FUNCTION_ARGS)
897909
SV *perlret;
898910
Datum retval;
899911
ReturnSetInfo *rsi;
912+
SV* array_ret = NULL;
900913

901914
if (SPI_connect() != SPI_OK_CONNECT)
902915
elog(ERROR, "could not connect to SPI manager");
903916

904917
prodesc = compile_plperl_function(fcinfo->flinfo->fn_oid, false);
905918

906919
plperl_current_prodesc = prodesc;
907-
prodesc->caller_info = fcinfo;
908-
prodesc->tuple_store = 0;
909-
prodesc->tuple_desc = 0;
920+
plperl_current_caller_info = fcinfo;
921+
plperl_current_tuple_store = 0;
922+
plperl_current_tuple_desc = 0;
910923

911924
perlret = plperl_call_perl_func(prodesc, fcinfo);
912925

@@ -958,10 +971,10 @@ plperl_func_handler(PG_FUNCTION_ARGS)
958971
}
959972

960973
rsi->returnMode = SFRM_Materialize;
961-
if (prodesc->tuple_store)
974+
if (plperl_current_tuple_store)
962975
{
963-
rsi->setResult = prodesc->tuple_store;
964-
rsi->setDesc = prodesc->tuple_desc;
976+
rsi->setResult = plperl_current_tuple_store;
977+
rsi->setDesc = plperl_current_tuple_desc;
965978
}
966979
retval = (Datum)0;
967980
}
@@ -1006,7 +1019,6 @@ plperl_func_handler(PG_FUNCTION_ARGS)
10061019
{
10071020
/* Return a perl string converted to a Datum */
10081021
char *val;
1009-
SV* array_ret;
10101022

10111023

10121024
if (prodesc->fn_retisarray && SvTYPE(SvRV(perlret)) == SVt_PVAV)
@@ -1024,7 +1036,9 @@ plperl_func_handler(PG_FUNCTION_ARGS)
10241036
Int32GetDatum(-1));
10251037
}
10261038

1027-
SvREFCNT_dec(perlret);
1039+
if (array_ret == NULL)
1040+
SvREFCNT_dec(perlret);
1041+
10281042
return retval;
10291043
}
10301044

@@ -1526,7 +1540,7 @@ void
15261540
plperl_return_next(SV *sv)
15271541
{
15281542
plperl_proc_desc *prodesc = plperl_current_prodesc;
1529-
FunctionCallInfo fcinfo = prodesc->caller_info;
1543+
FunctionCallInfo fcinfo = plperl_current_caller_info;
15301544
ReturnSetInfo *rsi = (ReturnSetInfo *)fcinfo->resultinfo;
15311545
MemoryContext cxt;
15321546
HeapTuple tuple;
@@ -1553,8 +1567,9 @@ plperl_return_next(SV *sv)
15531567

15541568
cxt = MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory);
15551569

1556-
if (!prodesc->tuple_store)
1557-
prodesc->tuple_store = tuplestore_begin_heap(true, false, work_mem);
1570+
if (!plperl_current_tuple_store)
1571+
plperl_current_tuple_store =
1572+
tuplestore_begin_heap(true, false, work_mem);
15581573

15591574
if (prodesc->fn_retistuple)
15601575
{
@@ -1590,10 +1605,10 @@ plperl_return_next(SV *sv)
15901605
tuple = heap_form_tuple(tupdesc, &ret, &isNull);
15911606
}
15921607

1593-
if (!prodesc->tuple_desc)
1594-
prodesc->tuple_desc = tupdesc;
1608+
if (!plperl_current_tuple_desc)
1609+
plperl_current_tuple_desc = tupdesc;
15951610

1596-
tuplestore_puttuple(prodesc->tuple_store, tuple);
1611+
tuplestore_puttuple(plperl_current_tuple_store, tuple);
15971612
heap_freetuple(tuple);
15981613
MemoryContextSwitchTo(cxt);
15991614
}

src/pl/plperl/sql/plperl.sql

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,3 +260,44 @@ while (defined ($y = spi_fetchrow($x))) {
260260
return;
261261
$$ LANGUAGE plperl;
262262
SELECT * from perl_spi_func();
263+
264+
265+
---
266+
--- Test recursion via SPI
267+
---
268+
269+
270+
CREATE OR REPLACE FUNCTION recurse(i int) RETURNS SETOF TEXT LANGUAGE plperl
271+
AS $$
272+
273+
my $i = shift;
274+
foreach my $x (1..$i)
275+
{
276+
return_next "hello $x";
277+
}
278+
if ($i > 2)
279+
{
280+
my $z = $i-1;
281+
my $cursor = spi_query("select * from recurse($z)");
282+
while (defined(my $row = spi_fetchrow($cursor)))
283+
{
284+
return_next "recurse $i: $row->{recurse}";
285+
}
286+
}
287+
return undef;
288+
289+
$$;
290+
291+
SELECT * FROM recurse(2);
292+
SELECT * FROM recurse(3);
293+
294+
295+
---
296+
--- Test arrary return
297+
---
298+
CREATE OR REPLACE FUNCTION array_of_text() RETURNS TEXT[][]
299+
LANGUAGE plperl as $$
300+
return [['a"b','c,d'],['e\\f','g']];
301+
$$;
302+
303+
SELECT array_of_text();

0 commit comments

Comments
 (0)