diff options
-rw-r--r-- | src/pl/plperl/expected/plperl_elog.out | 42 | ||||
-rw-r--r-- | src/pl/plperl/plperl.c | 42 | ||||
-rw-r--r-- | src/pl/plperl/sql/plperl_elog.sql | 30 |
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(); |