Re: BUG #17050: cursor with for update + commit in loop
Tom Lane <tgl@sss.pgh.pa.us>
From: Tom Lane <tgl@sss.pgh.pa.us>
To: bulgakovalexey1980@gmail.com
Cc: pgsql-bugs@lists.postgresql.org
Date: 2021-06-08T18:54:15Z
Lists: pgsql-bugs
PG Bug reporting form <noreply@postgresql.org> writes: > If run procedure test_tuple_stream then in result updated 2 rows of 3. > Why? So what's happening here is that at the point of the first COMMIT, we need to save the output of the cursor query, because we have to release locks and so forth. The expectation is that subsequent fetches will read from a tuplestore rather than the live query. To do that, PersistHoldablePortal supposes that it can rewind and re-read the query's executor run. But that only works if the query is guaranteed stable, which anything involving FOR UPDATE is not. In the example at hand, when we re-read the row with ID 1, nodeLockRows sees that its state is now TM_SelfModified thanks to the UPDATE we just did. This causes it to not return that row, so that what ends up in the tuplestore is only the rows with IDs 2 and 3. But since the cursor "knows" that one row has already been read out, the next fetch will return the row with ID 3, and the procedure's loop never visits the row with ID 2. I imagine that similar misbehavior could be constructed around queries containing volatile functions (e.g. random()), rather than FOR UPDATE. The only obvious way to fix this is to always save aside the output of a cursor query in case we need to persist it later, so that PersistHoldablePortal doesn't have to assume that rewinding is safe. That would be pretty catastrophic for performance, though, so I doubt anybody will be happy with that answer. For cursors that aren't marked scrollable, we might be able to say that we only save the *rest* of the query output, and then adjust the cursor state appropriately for that choice. Seems possibly nontrivial though, and there's still the question of what to do for scrollable ones. Anyway, many thanks for the report! But don't hold your breath for a fix; this is going to take some thought. regards, tom lane
Commits
-
Force NO SCROLL for plpgsql's implicit cursors.
- c5b28184132d 13.4 landed
- be9009890747 14.0 landed
- 5b7bf9f72ab5 11.13 landed
- 182323300620 12.8 landed
-
Avoid misbehavior when persisting a non-stable cursor.
- ba2c6d6cec00 14.0 landed
- c3b5082685dd 12.8 landed
- c1fd756fd23f 13.4 landed
- 2757865fa7fb 11.13 landed