mirror of
https://github.com/postgres/postgres.git
synced 2025-07-11 10:01:57 +03:00
Back-patch fix and test case for bug #7516.
Back-patch commits9afc648111
andb8fbbcf37f
. The first of these is really a minor code cleanup to save a few cycles, but it turns out to provide a workaround for the misoptimization problem described in bug #7516. The second commit adds a regression test case. Back-patch the fix to all active branches. The test case only works as far back as 9.0, because it relies on plpgsql which isn't installed by default before that. (I didn't have success modifying it into an all-plperl form that still provoked a crash, though this may just reflect my lack of Perl-fu.)
This commit is contained in:
@ -62,3 +62,45 @@ select uses_global();
|
|||||||
do language plperl $$ elog(NOTICE, ${^TAINT}); $$;
|
do language plperl $$ elog(NOTICE, ${^TAINT}); $$;
|
||||||
NOTICE: 0
|
NOTICE: 0
|
||||||
CONTEXT: PL/Perl anonymous code block
|
CONTEXT: PL/Perl anonymous code block
|
||||||
|
-- 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)
|
||||||
|
|
||||||
|
@ -1696,10 +1696,15 @@ plperl_call_handler(PG_FUNCTION_ARGS)
|
|||||||
Datum retval;
|
Datum retval;
|
||||||
plperl_call_data *save_call_data = current_call_data;
|
plperl_call_data *save_call_data = current_call_data;
|
||||||
plperl_interp_desc *oldinterp = plperl_active_interp;
|
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();
|
PG_TRY();
|
||||||
{
|
{
|
||||||
current_call_data = NULL;
|
current_call_data = &this_call_data;
|
||||||
if (CALLED_AS_TRIGGER(fcinfo))
|
if (CALLED_AS_TRIGGER(fcinfo))
|
||||||
retval = PointerGetDatum(plperl_trigger_handler(fcinfo));
|
retval = PointerGetDatum(plperl_trigger_handler(fcinfo));
|
||||||
else
|
else
|
||||||
@ -1707,16 +1712,16 @@ plperl_call_handler(PG_FUNCTION_ARGS)
|
|||||||
}
|
}
|
||||||
PG_CATCH();
|
PG_CATCH();
|
||||||
{
|
{
|
||||||
if (current_call_data && current_call_data->prodesc)
|
if (this_call_data.prodesc)
|
||||||
decrement_prodesc_refcount(current_call_data->prodesc);
|
decrement_prodesc_refcount(this_call_data.prodesc);
|
||||||
current_call_data = save_call_data;
|
current_call_data = save_call_data;
|
||||||
activate_interpreter(oldinterp);
|
activate_interpreter(oldinterp);
|
||||||
PG_RE_THROW();
|
PG_RE_THROW();
|
||||||
}
|
}
|
||||||
PG_END_TRY();
|
PG_END_TRY();
|
||||||
|
|
||||||
if (current_call_data && current_call_data->prodesc)
|
if (this_call_data.prodesc)
|
||||||
decrement_prodesc_refcount(current_call_data->prodesc);
|
decrement_prodesc_refcount(this_call_data.prodesc);
|
||||||
current_call_data = save_call_data;
|
current_call_data = save_call_data;
|
||||||
activate_interpreter(oldinterp);
|
activate_interpreter(oldinterp);
|
||||||
return retval;
|
return retval;
|
||||||
@ -1736,8 +1741,12 @@ plperl_inline_handler(PG_FUNCTION_ARGS)
|
|||||||
plperl_proc_desc desc;
|
plperl_proc_desc desc;
|
||||||
plperl_call_data *save_call_data = current_call_data;
|
plperl_call_data *save_call_data = current_call_data;
|
||||||
plperl_interp_desc *oldinterp = plperl_active_interp;
|
plperl_interp_desc *oldinterp = plperl_active_interp;
|
||||||
|
plperl_call_data this_call_data;
|
||||||
ErrorContextCallback pl_error_context;
|
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 */
|
/* Set up a callback for error reporting */
|
||||||
pl_error_context.callback = plperl_inline_callback;
|
pl_error_context.callback = plperl_inline_callback;
|
||||||
pl_error_context.previous = error_context_stack;
|
pl_error_context.previous = error_context_stack;
|
||||||
@ -1768,14 +1777,15 @@ plperl_inline_handler(PG_FUNCTION_ARGS)
|
|||||||
desc.nargs = 0;
|
desc.nargs = 0;
|
||||||
desc.reference = NULL;
|
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();
|
PG_TRY();
|
||||||
{
|
{
|
||||||
SV *perlret;
|
SV *perlret;
|
||||||
|
|
||||||
current_call_data = (plperl_call_data *) palloc0(sizeof(plperl_call_data));
|
current_call_data = &this_call_data;
|
||||||
current_call_data->fcinfo = &fake_fcinfo;
|
|
||||||
current_call_data->prodesc = &desc;
|
|
||||||
/* we do not bother with refcounting the fake prodesc */
|
|
||||||
|
|
||||||
if (SPI_connect() != SPI_OK_CONNECT)
|
if (SPI_connect() != SPI_OK_CONNECT)
|
||||||
elog(ERROR, "could not connect to SPI manager");
|
elog(ERROR, "could not connect to SPI manager");
|
||||||
@ -2158,13 +2168,6 @@ plperl_func_handler(PG_FUNCTION_ARGS)
|
|||||||
ReturnSetInfo *rsi;
|
ReturnSetInfo *rsi;
|
||||||
ErrorContextCallback pl_error_context;
|
ErrorContextCallback pl_error_context;
|
||||||
|
|
||||||
/*
|
|
||||||
* Create the call_data before 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)
|
if (SPI_connect() != SPI_OK_CONNECT)
|
||||||
elog(ERROR, "could not connect to SPI manager");
|
elog(ERROR, "could not connect to SPI manager");
|
||||||
|
|
||||||
@ -2277,13 +2280,6 @@ plperl_trigger_handler(PG_FUNCTION_ARGS)
|
|||||||
HV *hvTD;
|
HV *hvTD;
|
||||||
ErrorContextCallback pl_error_context;
|
ErrorContextCallback pl_error_context;
|
||||||
|
|
||||||
/*
|
|
||||||
* Create the call_data before 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 */
|
/* Connect to SPI manager */
|
||||||
if (SPI_connect() != SPI_OK_CONNECT)
|
if (SPI_connect() != SPI_OK_CONNECT)
|
||||||
elog(ERROR, "could not connect to SPI manager");
|
elog(ERROR, "could not connect to SPI manager");
|
||||||
|
@ -46,3 +46,33 @@ select uses_global();
|
|||||||
|
|
||||||
-- make sure we don't choke on readonly values
|
-- make sure we don't choke on readonly values
|
||||||
do language plperl $$ elog(NOTICE, ${^TAINT}); $$;
|
do language plperl $$ elog(NOTICE, ${^TAINT}); $$;
|
||||||
|
|
||||||
|
-- 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();
|
||||||
|
Reference in New Issue
Block a user