Andrew Dunstan wrote:
>
>
> Andrew Dunstan wrote:
>
>>
>>
>>
>>
>> Looking further ... we already do this implicitly for prodesc in the
>> call handler - we would just need to do the same thing for per-call
>> structures and divorce them from prodesc, which can be repeated on
>> the implicit stack.
>>
>> I'll work on that - changes should be quite small.
>>
>
> Attached is a patch that fixes (I hope) both a recently introduced
> problem with recursion and a problem with array returns that became
> evident as a result of not throwing away non-fatal warnings (thanks to
> David Fetter for noticing this). Regression test updates to include
> both cases are included in the patch.
>
> I will start looking at putting the procedure descriptors in a dynahash.
>
>
and here's the patch this time.
cheers
andrew
Index: plperl.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/pl/plperl/plperl.c,v
retrieving revision 1.84
diff -c -r1.84 plperl.c
*** plperl.c 10 Jul 2005 16:13:13 -0000 1.84
--- plperl.c 11 Jul 2005 13:08:26 -0000
***************
*** 90,98 ****
FmgrInfo arg_out_func[FUNC_MAX_ARGS];
bool arg_is_rowtype[FUNC_MAX_ARGS];
SV *reference;
- FunctionCallInfo caller_info;
- Tuplestorestate *tuple_store;
- TupleDesc tuple_desc;
} plperl_proc_desc;
--- 90,95 ----
***************
*** 106,113 ****
static bool plperl_use_strict = false;
! /* this is saved and restored by plperl_call_handler */
static plperl_proc_desc *plperl_current_prodesc = NULL;
/**********************************************************************
* Forward declarations
--- 103,113 ----
static bool plperl_use_strict = false;
! /* these are saved and restored by plperl_call_handler */
static plperl_proc_desc *plperl_current_prodesc = NULL;
+ static FunctionCallInfo plperl_current_caller_info;
+ static Tuplestorestate *plperl_current_tuple_store;
+ static TupleDesc plperl_current_tuple_desc;
/**********************************************************************
* Forward declarations
***************
*** 577,586 ****
--- 577,592 ----
{
Datum retval;
plperl_proc_desc *save_prodesc;
+ FunctionCallInfo save_caller_info;
+ Tuplestorestate *save_tuple_store;
+ TupleDesc save_tuple_desc;
plperl_init_all();
save_prodesc = plperl_current_prodesc;
+ save_caller_info = plperl_current_caller_info;
+ save_tuple_store = plperl_current_tuple_store;
+ save_tuple_desc = plperl_current_tuple_desc;
PG_TRY();
{
***************
*** 592,602 ****
--- 598,614 ----
PG_CATCH();
{
plperl_current_prodesc = save_prodesc;
+ plperl_current_caller_info = save_caller_info;
+ plperl_current_tuple_store = save_tuple_store;
+ plperl_current_tuple_desc = save_tuple_desc;
PG_RE_THROW();
}
PG_END_TRY();
plperl_current_prodesc = save_prodesc;
+ plperl_current_caller_info = save_caller_info;
+ plperl_current_tuple_store = save_tuple_store;
+ plperl_current_tuple_desc = save_tuple_desc;
return retval;
}
***************
*** 897,902 ****
--- 909,915 ----
SV *perlret;
Datum retval;
ReturnSetInfo *rsi;
+ SV* array_ret = NULL;
if (SPI_connect() != SPI_OK_CONNECT)
elog(ERROR, "could not connect to SPI manager");
***************
*** 904,912 ****
prodesc = compile_plperl_function(fcinfo->flinfo->fn_oid, false);
plperl_current_prodesc = prodesc;
! prodesc->caller_info = fcinfo;
! prodesc->tuple_store = 0;
! prodesc->tuple_desc = 0;
perlret = plperl_call_perl_func(prodesc, fcinfo);
--- 917,925 ----
prodesc = compile_plperl_function(fcinfo->flinfo->fn_oid, false);
plperl_current_prodesc = prodesc;
! plperl_current_caller_info = fcinfo;
! plperl_current_tuple_store = 0;
! plperl_current_tuple_desc = 0;
perlret = plperl_call_perl_func(prodesc, fcinfo);
***************
*** 958,967 ****
}
rsi->returnMode = SFRM_Materialize;
! if (prodesc->tuple_store)
{
! rsi->setResult = prodesc->tuple_store;
! rsi->setDesc = prodesc->tuple_desc;
}
retval = (Datum)0;
}
--- 971,980 ----
}
rsi->returnMode = SFRM_Materialize;
! if (plperl_current_tuple_store)
{
! rsi->setResult = plperl_current_tuple_store;
! rsi->setDesc = plperl_current_tuple_desc;
}
retval = (Datum)0;
}
***************
*** 1006,1012 ****
{
/* Return a perl string converted to a Datum */
char *val;
- SV* array_ret;
if (prodesc->fn_retisarray && SvTYPE(SvRV(perlret)) == SVt_PVAV)
--- 1019,1024 ----
***************
*** 1024,1030 ****
Int32GetDatum(-1));
}
! SvREFCNT_dec(perlret);
return retval;
}
--- 1036,1044 ----
Int32GetDatum(-1));
}
! if (array_ret == NULL)
! SvREFCNT_dec(perlret);
!
return retval;
}
***************
*** 1526,1532 ****
plperl_return_next(SV *sv)
{
plperl_proc_desc *prodesc = plperl_current_prodesc;
! FunctionCallInfo fcinfo = prodesc->caller_info;
ReturnSetInfo *rsi = (ReturnSetInfo *)fcinfo->resultinfo;
MemoryContext cxt;
HeapTuple tuple;
--- 1540,1546 ----
plperl_return_next(SV *sv)
{
plperl_proc_desc *prodesc = plperl_current_prodesc;
! FunctionCallInfo fcinfo = plperl_current_caller_info;
ReturnSetInfo *rsi = (ReturnSetInfo *)fcinfo->resultinfo;
MemoryContext cxt;
HeapTuple tuple;
***************
*** 1553,1560 ****
cxt = MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory);
! if (!prodesc->tuple_store)
! prodesc->tuple_store = tuplestore_begin_heap(true, false, work_mem);
if (prodesc->fn_retistuple)
{
--- 1567,1575 ----
cxt = MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory);
! if (!plperl_current_tuple_store)
! plperl_current_tuple_store =
! tuplestore_begin_heap(true, false, work_mem);
if (prodesc->fn_retistuple)
{
***************
*** 1590,1599 ****
tuple = heap_form_tuple(tupdesc, &ret, &isNull);
}
! if (!prodesc->tuple_desc)
! prodesc->tuple_desc = tupdesc;
! tuplestore_puttuple(prodesc->tuple_store, tuple);
heap_freetuple(tuple);
MemoryContextSwitchTo(cxt);
}
--- 1605,1614 ----
tuple = heap_form_tuple(tupdesc, &ret, &isNull);
}
! if (!plperl_current_tuple_desc)
! plperl_current_tuple_desc = tupdesc;
! tuplestore_puttuple(plperl_current_tuple_store, tuple);
heap_freetuple(tuple);
MemoryContextSwitchTo(cxt);
}
Index: expected/plperl.out
===================================================================
RCS file: /projects/cvsroot/pgsql/src/pl/plperl/expected/plperl.out,v
retrieving revision 1.3
diff -c -r1.3 plperl.out
*** expected/plperl.out 10 Jul 2005 15:19:43 -0000 1.3
--- expected/plperl.out 11 Jul 2005 13:08:26 -0000
***************
*** 367,369 ****
--- 367,422 ----
2
(2 rows)
+ ---
+ --- Test recursion via SPI
+ ---
+ CREATE OR REPLACE FUNCTION recurse(i int) RETURNS SETOF TEXT LANGUAGE plperl
+ AS $$
+
+ my $i = shift;
+ foreach my $x (1..$i)
+ {
+ return_next "hello $x";
+ }
+ if ($i > 2)
+ {
+ my $z = $i-1;
+ my $cursor = spi_query("select * from recurse($z)");
+ while (defined(my $row = spi_fetchrow($cursor)))
+ {
+ return_next "recurse $i: $row->{recurse}";
+ }
+ }
+ return undef;
+
+ $$;
+ SELECT * FROM recurse(2);
+ recurse
+ ---------
+ hello 1
+ hello 2
+ (2 rows)
+
+ SELECT * FROM recurse(3);
+ recurse
+ --------------------
+ hello 1
+ hello 2
+ hello 3
+ recurse 3: hello 1
+ recurse 3: hello 2
+ (5 rows)
+
+ ---
+ --- Test arrary return
+ ---
+ CREATE OR REPLACE FUNCTION array_of_text() RETURNS TEXT[][]
+ LANGUAGE plperl as $$
+ return [['a"b','c,d'],['e\\f','g']];
+ $$;
+ SELECT array_of_text();
+ array_of_text
+ -----------------------------
+ {{"a\"b","c,d"},{"e\\f",g}}
+ (1 row)
+
Index: sql/plperl.sql
===================================================================
RCS file: /projects/cvsroot/pgsql/src/pl/plperl/sql/plperl.sql,v
retrieving revision 1.3
diff -c -r1.3 plperl.sql
*** sql/plperl.sql 10 Jul 2005 15:19:43 -0000 1.3
--- sql/plperl.sql 11 Jul 2005 13:08:26 -0000
***************
*** 260,262 ****
--- 260,303 ----
return;
$$ LANGUAGE plperl;
SELECT * from perl_spi_func();
+
+
+ ---
+ --- Test recursion via SPI
+ ---
+
+
+ CREATE OR REPLACE FUNCTION recurse(i int) RETURNS SETOF TEXT LANGUAGE plperl
+ AS $$
+
+ my $i = shift;
+ foreach my $x (1..$i)
+ {
+ return_next "hello $x";
+ }
+ if ($i > 2)
+ {
+ my $z = $i-1;
+ my $cursor = spi_query("select * from recurse($z)");
+ while (defined(my $row = spi_fetchrow($cursor)))
+ {
+ return_next "recurse $i: $row->{recurse}";
+ }
+ }
+ return undef;
+
+ $$;
+
+ SELECT * FROM recurse(2);
+ SELECT * FROM recurse(3);
+
+
+ ---
+ --- Test arrary return
+ ---
+ CREATE OR REPLACE FUNCTION array_of_text() RETURNS TEXT[][]
+ LANGUAGE plperl as $$
+ return [['a"b','c,d'],['e\\f','g']];
+ $$;
+
+ SELECT array_of_text();