BUG #5872: Function call in SQL function executed only once - Mailing list pgsql-bugs

From Rodolfo Campero
Subject BUG #5872: Function call in SQL function executed only once
Date
Msg-id 201102082000.p18K0cWN037750@wwwmaster.postgresql.org
Whole thread Raw
Responses Re: BUG #5872: Function call in SQL function executed only once  (Tom Lane <tgl@sss.pgh.pa.us>)
List pgsql-bugs
The following bug has been logged online:

Bug reference:      5872
Logged by:          Rodolfo Campero
Email address:      rodolfo.campero@anachronics.com
PostgreSQL version: 8.4.5
Operating system:   Debian 6.0 - Linux 2.6.32-5-amd64
Description:        Function call in SQL function executed only once
Details:

Hello,

I stumbled upon a weird behavior of postgresql, I don't know if it's a bug
or not, but I find it counterintuitive: when then last statement of a SQL
function is a SELECT statement with calls another function, the call is
executed only once, regardless of the number of rows returned by the FROM
clause. This happens even if the called function is volatile.

Here goes a test case:

8<-----------------------------------------------
CREATE TABLE counter (cnt INTEGER NOT NULL);
INSERT INTO counter VALUES (0);

CREATE OR REPLACE FUNCTION increment_counter()
RETURNS void AS $$
UPDATE counter SET cnt = cnt + 1;
$$ LANGUAGE sql VOLATILE;

CREATE OR REPLACE FUNCTION test()
RETURNS void AS $$
SELECT increment_counter() FROM generate_series(1,10);
$$ LANGUAGE sql VOLATILE;

postgres=# select test();
 test
------

(1 row)

postgres=# select cnt from counter; --should return 10
 cnt
-----
   1
(1 row)
8<-----------------------------------------------

If a dummy statement is appended to the function body, we get the expected
behavior:

8<-----------------------------------------------
postgres=# CREATE OR REPLACE FUNCTION test()
RETURNS void AS $$
SELECT increment_counter() FROM generate_series(1,10);
SELECT null::void; --this dummy SELECT works around the problem
$$ LANGUAGE sql VOLATILE;
CREATE FUNCTION

postgres=# update counter set cnt = 0;
UPDATE 1

postgres=# select test();
 test
------

(1 row)

postgres=# select cnt from counter;
 cnt
-----
  10
(1 row)
8<-----------------------------------------------

Maybe this was intended as an optimization for the case when a regular
function calls a set-returning function (because the first row is returned
and the remaining rows would get discarded anyway), but I think the call
must be performed every time if the invoked function is volatile.

Best regards,
Rodolfo

pgsql-bugs by date:

Previous
From: mark
Date:
Subject: Re: BUG #5851: ROHS (read only hot standby) needs to be restarted manually in somecases.
Next
From: Tom Lane
Date:
Subject: Re: BUG #5872: Function call in SQL function executed only once