Thread: BUG #6360: with hold cursor, cause function executed twice and wrong results
BUG #6360: with hold cursor, cause function executed twice and wrong results
From
wcting163@163.com
Date:
The following bug has been logged on the website: Bug reference: 6360 Logged by: ctwang Email address: wcting163@163.com PostgreSQL version: 9.0.5 Operating system: linux 2.6.18-128.7AXS3=20 Description:=20=20=20=20=20=20=20=20 create table test_execute(id int,name varchar(40)); insert into test_execute values(1,'jack'); create or replace function p_test_execute() returns void as $$ begin raise notice 'hello world'; update test_execute set id=3Did*2; end; $$ LANGUAGE plpgsql; begin; declare JDBC_CURS_1 cursor with hold for select p_test_execute() from test_execute; fetch 50 from JDBC_CURS_1; NOTICE: hello world end; NOTICE: hello world COMMIT select * from test_execute; id | name ----+------ 4 | jack I expect id =3D 2, but it is **4** instead, The reason is that the function p_test_execute is executed twice, when *fetch*, it is first executed, and when transaction commit, because the cursor is a *holdable* cursor, it is executed again. I read the code, for holdable cursor, when commit, following call will execute: CommitHoldablePortals-->PersistHoldablePortal-->ExecutorRewind Is *ExecutorRewind* necessary, is it the root of this bug? Does *ExecutorRewind* cause plan re-execute?
Re: BUG #6360: with hold cursor, cause function executed twice and wrong results
From
Tom Lane
Date:
wcting163@163.com writes: > The reason is that the function p_test_execute is executed twice, when > *fetch*, it is first executed, and when transaction commit, because the > cursor is a *holdable* cursor, it is executed again. Yup. I don't particularly see this as a bug. If you were to manually rewind and rescan the cursor (ie, MOVE BACKWARD ALL and re-fetch), the function would be executed multiple times too. If you don't want that to happen, the best way would be to commit the transaction immediately, not fetch some rows and then commit. regards, tom lane
Re: BUG #6360: with hold cursor, cause function executed twice and wrong results
From
wcting163
Date:
At 2011-12-28 01:47:20,"Tom Lane" tgl@sss.pgh.pa.us> wrote: Yup. I don't particularly see this as a bug. If you were to manually >rewind and rescan the cursor (ie, MOVE BACKWARD ALL and re-fetch), >the function would be executed multiple times too. If you don't want >that to happen, the best way would be to commit the transaction >immediately, not fetch some rows and then commit. > > regards, tom lane Why *with hold cursor* acts as *MOVE BACKWARD ALL & FETCH*? Is this right or necessary? maybe they are not comparable, i doubt this analogy. MOVE BACKWARD ALL & FETCH will cause cursor re-fetch? Maybe pepole have different opinions for MOVE BACKWARD ALL & FETCH: 1. fetch from the old result-sets, not rescan(re-execute); 2. re-fetch and generate the new result-sets, cause plan re-execute again; Now, pg acts as the second; *Move* is not SQL standard, and does not clearly documented in pg document, If we create *DestTuplestore* when first fetch, not in commit transaction, then: 1. we always fetch results from *DestTuplestore*; 2. if *DestTuplestore* is empty, we execute-plan and fill the results into *DestTuplestore*; 3. when rewind, just rewind *DestTuplestore*, not executor; then we can implement the first action? So, there are two questions here: 1. the Standard action of *MOVE BACKWARD ALL & FETCH*; 2. *with hold cursor* acts as *MOVE BACKWARD ALL & FETCH*, is this right(necessary)?
Re: BUG #6360: with hold cursor, cause function executed twice and wrong results
From
Robert Haas
Date:
On Tue, Dec 27, 2011 at 12:47 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote: > wcting163@163.com writes: >> The reason is that the function p_test_execute is executed twice, when >> *fetch*, it is first executed, and when transaction commit, because the >> cursor is a *holdable* cursor, it is executed again. > > Yup. =A0I don't particularly see this as a bug. =A0If you were to manually > rewind and rescan the cursor (ie, MOVE BACKWARD ALL and re-fetch), > the function would be executed multiple times too. =A0If you don't want > that to happen, the best way would be to commit the transaction > immediately, not fetch some rows and then commit. Is that even per spec? I would not expect the results, or the side-effects, of a query to depend on the method used to retrieve its results. --=20 Robert Haas EnterpriseDB: http://www.enterprisedb.com The Enterprise PostgreSQL Company