1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-28 23:42:10 +03:00

Repair mishandling of cached cast-expression trees in plpgsql.

In commit 1345cc67bb, I introduced caching
of expressions representing type-cast operations into plpgsql.  However,
I supposed that I could cache both the expression trees and the evaluation
state trees derived from them for the life of the session.  This doesn't
work, because we execute the expressions in plpgsql's simple_eval_estate,
which has an ecxt_per_query_memory that is only transaction-lifespan.
Therefore we can end up putting pointers into the evaluation state tree
that point to transaction-lifespan memory; in particular this happens if
the cast expression calls a SQL-language function, as reported by Geoff
Winkless.

The minimum-risk fix seems to be to treat the state trees the same way
we do for "simple expression" trees in plpgsql, ie create them in the
simple_eval_estate's ecxt_per_query_memory, which means recreating them
once per transaction.

Since I had to introduce bookkeeping overhead for that anyway, I bought
back some of the added cost by sharing the read-only expression trees
across all functions in the session, instead of using a per-function
table as originally.  The simple-expression bookkeeping takes care of
the recursive-usage risk that I was concerned about avoiding before.

At some point we should take a harder look at how all this works,
and see if we can't reduce the amount of tree reinitialization needed.
But that won't happen for 9.5.
This commit is contained in:
Tom Lane
2015-07-17 15:53:09 -04:00
parent 266e771435
commit 0fc94a5bab
4 changed files with 265 additions and 127 deletions

View File

@ -4702,6 +4702,68 @@ select error2('public.stuffs');
rollback;
drop function error2(p_name_table text);
drop function error1(text);
-- Test for proper handling of cast-expression caching
create function sql_to_date(integer) returns date as $$
select $1::text::date
$$ language sql immutable strict;
create cast (integer as date) with function sql_to_date(integer) as assignment;
create function cast_invoker(integer) returns date as $$
begin
return $1;
end$$ language plpgsql;
select cast_invoker(20150717);
cast_invoker
--------------
07-17-2015
(1 row)
select cast_invoker(20150718); -- second call crashed in pre-release 9.5
cast_invoker
--------------
07-18-2015
(1 row)
begin;
select cast_invoker(20150717);
cast_invoker
--------------
07-17-2015
(1 row)
select cast_invoker(20150718);
cast_invoker
--------------
07-18-2015
(1 row)
savepoint s1;
select cast_invoker(20150718);
cast_invoker
--------------
07-18-2015
(1 row)
select cast_invoker(-1); -- fails
ERROR: invalid input syntax for type date: "-1"
CONTEXT: SQL function "sql_to_date" statement 1
PL/pgSQL function cast_invoker(integer) while casting return value to function's return type
rollback to savepoint s1;
select cast_invoker(20150719);
cast_invoker
--------------
07-19-2015
(1 row)
select cast_invoker(20150720);
cast_invoker
--------------
07-20-2015
(1 row)
commit;
drop function cast_invoker(integer);
drop function sql_to_date(integer) cascade;
NOTICE: drop cascades to cast from integer to date
-- Test for consistent reporting of error context
create function fail() returns int language plpgsql as $$
begin

View File

@ -3806,6 +3806,36 @@ rollback;
drop function error2(p_name_table text);
drop function error1(text);
-- Test for proper handling of cast-expression caching
create function sql_to_date(integer) returns date as $$
select $1::text::date
$$ language sql immutable strict;
create cast (integer as date) with function sql_to_date(integer) as assignment;
create function cast_invoker(integer) returns date as $$
begin
return $1;
end$$ language plpgsql;
select cast_invoker(20150717);
select cast_invoker(20150718); -- second call crashed in pre-release 9.5
begin;
select cast_invoker(20150717);
select cast_invoker(20150718);
savepoint s1;
select cast_invoker(20150718);
select cast_invoker(-1); -- fails
rollback to savepoint s1;
select cast_invoker(20150719);
select cast_invoker(20150720);
commit;
drop function cast_invoker(integer);
drop function sql_to_date(integer) cascade;
-- Test for consistent reporting of error context
create function fail() returns int language plpgsql as $$