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)
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