BUG #5611: SQL Function STABLE promoting to VOLATILE - Mailing list pgsql-bugs

From Brian Ceccarelli
Subject BUG #5611: SQL Function STABLE promoting to VOLATILE
Date
Msg-id 201008102030.o7AKUo5E022936@wwwmaster.postgresql.org
Whole thread Raw
Responses Re: BUG #5611: SQL Function STABLE promoting to VOLATILE
List pgsql-bugs
The following bug has been logged online:

Bug reference:      5611
Logged by:          Brian Ceccarelli
Email address:      bceccarelli@net32.com
PostgreSQL version: 8.4.4
Operating system:   Windows XP 32 bit and Red Hat 5.4 64 bit
Description:        SQL Function STABLE promoting to VOLATILE
Details:

----------------------------------------------------------------------------
-----
--
--    Demonstration of a PL/PGSQL stable-scoped function not working.
--
--        To see the problem, run this entire script from PGAdmin.   Bring
up Task Manager too.
--        After you the run this entire script, you can repeat the specific
problem by running:
--
--                select * from f_pass_4();
--
--        Note that "I am in f_return_ver_id_4() repeats once for every row
returned from f_get_table_4().
--        Postgres should only call f_return_ver_id_4() once.

--    The Problems:
--
--        1.  It seems that STABLE functions called within a SQL language
get promoted to VOLATILE.
--            Even though I declare a function STABLE, Postgres calls it
multiple times within a tranasaction.
--
--        2.  The raise notice in f_return_ver_id_4() also causes a memory
leak in PGAdmin (on Windows).
--
--    Related Problems:
--
--         Even the now() function gets called repeatedly within a stable
SQL function.
--
--    Postgres Version:
--
--        I am running Postgres 8.4.4-1 on Windows.   (Windows XP 32 bit)
--        Same problem occurs on Postgres 8.4.4 on Linux-64.   Red Hat 5.4.
--
--    Problem NOT in Postgres 8.2.
--
--         This problem does not happen in Postgres 8.2.
--
----------------------------------------------------------------------------
-----

drop type if exists type_pass_test cascade;
create type type_pass_test as (ver_id int8);

CREATE OR REPLACE FUNCTION f_get_table_4()
   RETURNS setof type_pass_test AS
$BODY$
----------------------------------------------------------------------------
-----
--
--
----------------------------------------------------------------------------
-----
declare
     r          type_pass_test;
     i          int8;
begin

   for i in 1..5
   loop
      r.ver_id := i;
      return next r;
   end loop;

   return;
end;
$BODY$
  language 'plpgsql' volatile;



CREATE OR REPLACE FUNCTION f_return_ver_id_4()
   RETURNS int8 AS
$BODY$
----------------------------------------------------------------------------
-----
--
--
----------------------------------------------------------------------------
-----
declare
begin
   raise notice 'I am in f_return_ver_id_4()';
   return 1;
end;
$BODY$
  language 'plpgsql' stable;



CREATE OR REPLACE FUNCTION f_do_4(ver_id_in  int8)
   RETURNS setof type_pass_test AS
$BODY$
----------------------------------------------------------------------------
-----
--
--   When you run f_pass_4(), f_pass_4() calls f_do_4() passing ver_id_in as
f_return_ver_id_4().
--
--   The error:
--
--       Even though f_return_ver_id_4() is a STABLE function, the select
--   statement below calls f_return_ver_id_4() once for every row coming
back from
--   f_get_table_4().
--
--       The repeat appears when I write the function in the SQL language.
--       The repeat disappears when I write the function in the PL/PGSQL
language.
--       If I add now() to the where clause, you will even see that Postgres
calls now() multiple times.
--
----------------------------------------------------------------------------
-----

 select *
   from f_get_table_4()
  where ver_id = $1;

$BODY$
  language 'SQL' stable;


/*
CREATE OR REPLACE FUNCTION f_do_4(ver_id_in  int8)
   RETURNS setof type_pass_test AS
$BODY$
----------------------------------------------------------------------------
-----
--
--   If I make the f_do_4(ver_id_in int8) a PL/PGSQL function, the problem
goes away.
--
----------------------------------------------------------------------------
-----
begin

   return query
     select *
       from f_get_table_4()
      where ver_id = $1;

   return;

end;
$BODY$
  language 'plpgsql' stable;

*/

CREATE OR REPLACE FUNCTION f_pass_4()
   RETURNS int4 AS
$BODY$
----------------------------------------------------------------------------
-----
--
--    Example:
--
--    select * from f_pass_4();
--
----------------------------------------------------------------------------
-----
declare
   rows_affected_w  int4;
begin



   select into rows_affected_w
               count(*)
          from f_do_4(f_return_ver_id_4());

   return rows_affected_w;
end;
$BODY$
  language 'plpgsql' stable;

----------------------------------------

select * from f_pass_4();

pgsql-bugs by date:

Previous
From: Alex Hunsaker
Date:
Subject: Re: BUG #5601: cannot create language plperl;
Next
From: Tom Lane
Date:
Subject: Re: BUG #5611: SQL Function STABLE promoting to VOLATILE