aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/pl/plperl/expected/plperl_elog.out42
-rw-r--r--src/pl/plperl/plperl.c42
-rw-r--r--src/pl/plperl/sql/plperl_elog.sql30
3 files changed, 91 insertions, 23 deletions
diff --git a/src/pl/plperl/expected/plperl_elog.out b/src/pl/plperl/expected/plperl_elog.out
index 02497d9e02b..ad8fb38b8af 100644
--- a/src/pl/plperl/expected/plperl_elog.out
+++ b/src/pl/plperl/expected/plperl_elog.out
@@ -58,3 +58,45 @@ select uses_global();
uses_global worked
(1 row)
+-- test recovery after "die"
+create or replace function just_die() returns void language plperl AS $$
+die "just die";
+$$;
+select just_die();
+ERROR: just die at line 2.
+CONTEXT: PL/Perl function "just_die"
+create or replace function die_caller() returns int language plpgsql as $$
+BEGIN
+ BEGIN
+ PERFORM just_die();
+ EXCEPTION WHEN OTHERS THEN
+ RAISE NOTICE 'caught die';
+ END;
+ RETURN 1;
+END;
+$$;
+select die_caller();
+NOTICE: caught die
+ die_caller
+------------
+ 1
+(1 row)
+
+create or replace function indirect_die_caller() returns int language plperl as $$
+my $prepared = spi_prepare('SELECT die_caller() AS fx');
+my $a = spi_exec_prepared($prepared)->{rows}->[0]->{fx};
+my $b = spi_exec_prepared($prepared)->{rows}->[0]->{fx};
+return $a + $b;
+$$;
+select indirect_die_caller();
+NOTICE: caught die
+CONTEXT: SQL statement "SELECT die_caller() AS fx"
+PL/Perl function "indirect_die_caller"
+NOTICE: caught die
+CONTEXT: SQL statement "SELECT die_caller() AS fx"
+PL/Perl function "indirect_die_caller"
+ indirect_die_caller
+---------------------
+ 2
+(1 row)
+
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 7c34f14b566..3334ca6d7a6 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1244,10 +1244,15 @@ plperl_call_handler(PG_FUNCTION_ARGS)
Datum retval;
plperl_call_data *save_call_data = current_call_data;
plperl_interp_desc *oldinterp = plperl_active_interp;
+ plperl_call_data this_call_data;
+
+ /* Initialize current-call status record */
+ MemSet(&this_call_data, 0, sizeof(this_call_data));
+ this_call_data.fcinfo = fcinfo;
PG_TRY();
{
- current_call_data = NULL;
+ current_call_data = &this_call_data;
if (CALLED_AS_TRIGGER(fcinfo))
retval = PointerGetDatum(plperl_trigger_handler(fcinfo));
else
@@ -1255,16 +1260,16 @@ plperl_call_handler(PG_FUNCTION_ARGS)
}
PG_CATCH();
{
- if (current_call_data && current_call_data->prodesc)
- decrement_prodesc_refcount(current_call_data->prodesc);
+ if (this_call_data.prodesc)
+ decrement_prodesc_refcount(this_call_data.prodesc);
current_call_data = save_call_data;
activate_interpreter(oldinterp);
PG_RE_THROW();
}
PG_END_TRY();
- if (current_call_data && current_call_data->prodesc)
- decrement_prodesc_refcount(current_call_data->prodesc);
+ if (this_call_data.prodesc)
+ decrement_prodesc_refcount(this_call_data.prodesc);
current_call_data = save_call_data;
activate_interpreter(oldinterp);
return retval;
@@ -1284,8 +1289,12 @@ plperl_inline_handler(PG_FUNCTION_ARGS)
plperl_proc_desc desc;
plperl_call_data *save_call_data = current_call_data;
plperl_interp_desc *oldinterp = plperl_active_interp;
+ plperl_call_data this_call_data;
ErrorContextCallback pl_error_context;
+ /* Initialize current-call status record */
+ MemSet(&this_call_data, 0, sizeof(this_call_data));
+
/* Set up a callback for error reporting */
pl_error_context.callback = plperl_inline_callback;
pl_error_context.previous = error_context_stack;
@@ -1316,14 +1325,15 @@ plperl_inline_handler(PG_FUNCTION_ARGS)
desc.nargs = 0;
desc.reference = NULL;
+ this_call_data.fcinfo = &fake_fcinfo;
+ this_call_data.prodesc = &desc;
+ /* we do not bother with refcounting the fake prodesc */
+
PG_TRY();
{
SV *perlret;
- current_call_data = (plperl_call_data *) palloc0(sizeof(plperl_call_data));
- current_call_data->fcinfo = &fake_fcinfo;
- current_call_data->prodesc = &desc;
- /* we do not bother with refcounting the fake prodesc */
+ current_call_data = &this_call_data;
if (SPI_connect() != SPI_OK_CONNECT)
elog(ERROR, "could not connect to SPI manager");
@@ -1672,13 +1682,6 @@ plperl_func_handler(PG_FUNCTION_ARGS)
SV *array_ret = NULL;
ErrorContextCallback pl_error_context;
- /*
- * Create the call_data beforing connecting to SPI, so that it is not
- * allocated in the SPI memory context
- */
- current_call_data = (plperl_call_data *) palloc0(sizeof(plperl_call_data));
- current_call_data->fcinfo = fcinfo;
-
if (SPI_connect() != SPI_OK_CONNECT)
elog(ERROR, "could not connect to SPI manager");
@@ -1832,13 +1835,6 @@ plperl_trigger_handler(PG_FUNCTION_ARGS)
HV *hvTD;
ErrorContextCallback pl_error_context;
- /*
- * Create the call_data beforing connecting to SPI, so that it is not
- * allocated in the SPI memory context
- */
- current_call_data = (plperl_call_data *) palloc0(sizeof(plperl_call_data));
- current_call_data->fcinfo = fcinfo;
-
/* Connect to SPI manager */
if (SPI_connect() != SPI_OK_CONNECT)
elog(ERROR, "could not connect to SPI manager");
diff --git a/src/pl/plperl/sql/plperl_elog.sql b/src/pl/plperl/sql/plperl_elog.sql
index 4f1c014efbd..1d58182e181 100644
--- a/src/pl/plperl/sql/plperl_elog.sql
+++ b/src/pl/plperl/sql/plperl_elog.sql
@@ -43,3 +43,33 @@ create or replace function uses_global() returns text language plperl as $$
$$;
select uses_global();
+
+-- test recovery after "die"
+
+create or replace function just_die() returns void language plperl AS $$
+die "just die";
+$$;
+
+select just_die();
+
+create or replace function die_caller() returns int language plpgsql as $$
+BEGIN
+ BEGIN
+ PERFORM just_die();
+ EXCEPTION WHEN OTHERS THEN
+ RAISE NOTICE 'caught die';
+ END;
+ RETURN 1;
+END;
+$$;
+
+select die_caller();
+
+create or replace function indirect_die_caller() returns int language plperl as $$
+my $prepared = spi_prepare('SELECT die_caller() AS fx');
+my $a = spi_exec_prepared($prepared)->{rows}->[0]->{fx};
+my $b = spi_exec_prepared($prepared)->{rows}->[0]->{fx};
+return $a + $b;
+$$;
+
+select indirect_die_caller();