Thread: Problem close curser after rollback

Problem close curser after rollback

From
"Wiltsch,Sigrid"
Date:
 
Hi, 

we use the following statements in our applications, as described on the site:
 
https://www.postgresql.org/docs/11/ecpg-commands.html#ECPG-TRANSACTIONS
 
EXEC SQL PREPARE stmt1 FROM "SELECT oid,datname FROM pg_database WHERE oid > ?";
EXEC SQL DECLARE foo_bar CURSOR FOR stmt1;
 
/* when end of result set reached, break out of while loop */
EXEC SQL WHENEVER NOT FOUND DO BREAK;
 
EXEC SQL OPEN foo_bar USING 100;
...
while (1)
{
    EXEC SQL FETCH NEXT FROM foo_bar INTO :dboid, :dbname;
    ...
}
EXEC SQL CLOSE foo_bar;
 


After every fetch we open a transaction which is terminated with a rollback in the event of an error.

The problem we now have with this is,  that the cursor is obviously closed with the rollback, so the next fetch ends
withthe error that the cursor no longer exists (sqlcode -400 

What can I do so that the cursor is retained despite rollback?

The procedure described is very often found in our applications, which have been ported from sybase to postgreSQL.

Thanks and kind regards,
Sigrid
 




Re: Problem close curser after rollback

From
Matthias Apitz
Date:
El día miércoles, septiembre 30, 2020 a las 01:32:41p. m. +0000, Wiltsch,Sigrid escribió:

>  
> Hi,  
> 
> we use the following statements in our applications, as described on the site: 
>  
> https://www.postgresql.org/docs/11/ecpg-commands.html#ECPG-TRANSACTIONS
>  
> EXEC SQL PREPARE stmt1 FROM "SELECT oid,datname FROM pg_database WHERE oid > ?";
> EXEC SQL DECLARE foo_bar CURSOR FOR stmt1;
>  
> ...

I forgot to mention that the problem is with PostgreSQL 11.4 on SuSE
Linux Enterprise. If the problem is not clear, we could rewrite this as
a ten-liner in ESQL/C to reproduce it.

The OP (Sigrid) and me we're working in the same team.

Thanks

    matthias
-- 
Matthias Apitz, ✉ guru@unixarea.de, http://www.unixarea.de/ +49-176-38902045
Public GnuPG key: http://www.unixarea.de/key.pub
Без книги нет знания, без знания нет коммунизма (Влaдимир Ильич Ленин)
Without books no knowledge - without knowledge no communism (Vladimir Ilyich Lenin)
Sin libros no hay saber - sin saber no hay comunismo. (Vladimir Ilich Lenin)



Re: Problem close curser after rollback

From
Laurenz Albe
Date:
On Wed, 2020-09-30 at 13:32 +0000, Wiltsch,Sigrid wrote:
> we use the following statements in our applications, as described on the site: 
> 
> https://www.postgresql.org/docs/11/ecpg-commands.html#ECPG-TRANSACTIONS
> 
> EXEC SQL PREPARE stmt1 FROM "SELECT oid,datname FROM pg_database WHERE oid > ?";
> EXEC SQL DECLARE foo_bar CURSOR FOR stmt1;
> 
> /* when end of result set reached, break out of while loop */
> EXEC SQL WHENEVER NOT FOUND DO BREAK;
> 
> EXEC SQL OPEN foo_bar USING 100;
> ...
> while (1)
> {
>     EXEC SQL FETCH NEXT FROM foo_bar INTO :dboid, :dbname;
>     ...
> }
> 
> EXEC SQL CLOSE foo_bar;
> 
> After every fetch we open a transaction which is terminated with a rollback in the event of an error.
> 
> The problem we now have with this is,  that the cursor is obviously closed with the rollback,
>  so the next fetch ends with the error that the cursor no longer exists (sqlcode -400
> 
> What can I do so that the cursor is retained despite rollback?
> 
> The procedure described is very often found in our applications, which have been ported from sybase to postgreSQL.

You cannot start a transaction while you are reading a cursor; you probably
get a warning "there is already a transaction in progress".

You could try using a CURSOR WITH HOLD.

Such cursors outlast a database transaction. They get materialized on the server
during commit.

So you could create the WITH HOLD cursor, commit and then start your individual transactions.

Don't forget to close the cursor when you are done, else it will use server resources
until you close the database connection.


Another option is to use savepoints, but you may run into performance problems
if you use more than 64 of them and have concurrent database activity.

Yours,
Laurenz Albe
-- 
Cybertec | https://www.cybertec-postgresql.com




Re: Problem close curser after rollback

From
Matthias Apitz
Date:
El día miércoles, septiembre 30, 2020 a las 05:26:39p. m. +0200, Laurenz Albe escribió:

> On Wed, 2020-09-30 at 13:32 +0000, Wiltsch,Sigrid wrote:
> > we use the following statements in our applications, as described on the site: 
> > 
> > https://www.postgresql.org/docs/11/ecpg-commands.html#ECPG-TRANSACTIONS
> > 
> > EXEC SQL PREPARE stmt1 FROM "SELECT oid,datname FROM pg_database WHERE oid > ?";
> > EXEC SQL DECLARE foo_bar CURSOR FOR stmt1;
> > 
> > /* when end of result set reached, break out of while loop */
> > EXEC SQL WHENEVER NOT FOUND DO BREAK;
> > 
> > EXEC SQL OPEN foo_bar USING 100;
> > ...
> > while (1)
> > {
> >     EXEC SQL FETCH NEXT FROM foo_bar INTO :dboid, :dbname;
> >     ...
> > }
> > 
> > EXEC SQL CLOSE foo_bar;
> > 
> > After every fetch we open a transaction which is terminated with a rollback in the event of an error.
> > 
> > The problem we now have with this is,  that the cursor is obviously closed with the rollback,
> >  so the next fetch ends with the error that the cursor no longer exists (sqlcode -400
> > 
> > What can I do so that the cursor is retained despite rollback?
> > 
> > The procedure described is very often found in our applications, which have been ported from sybase to postgreSQL.
> 
> You cannot start a transaction while you are reading a cursor; you probably
> get a warning "there is already a transaction in progress".

Sigrid was not fully correct saying 'After every fetch we open a transaction...'

Our layer between application and ESQL/C has a function call DB_strT()
to start a transaction. But this does nothing for PostgreSQL because in
PostgreSQL' ESQL/C there is no method "START TRANSACTION", see

https://www.postgresql.org/docs/11/ecpg-commands.html#ECPG-TRANSACTIONS

There are only COMMIT and ROLLBACK.

I think we will prepare the ten-liner in ESQL/C for further discussion.

    matthias


-- 
Matthias Apitz, ✉ guru@unixarea.de, http://www.unixarea.de/ +49-176-38902045
Public GnuPG key: http://www.unixarea.de/key.pub
Без книги нет знания, без знания нет коммунизма (Влaдимир Ильич Ленин)
Without books no knowledge - without knowledge no communism (Vladimir Ilyich Lenin)
Sin libros no hay saber - sin saber no hay comunismo. (Vladimir Ilich Lenin)



Re: Problem close curser after rollback

From
Tom Lane
Date:
Matthias Apitz <guru@unixarea.de> writes:
> El día miércoles, septiembre 30, 2020 a las 05:26:39p. m. +0200, Laurenz Albe escribió:
>> On Wed, 2020-09-30 at 13:32 +0000, Wiltsch,Sigrid wrote:
>>> What can I do so that the cursor is retained despite rollback?

>> You cannot start a transaction while you are reading a cursor; you probably
>> get a warning "there is already a transaction in progress".

> I think we will prepare the ten-liner in ESQL/C for further discussion.

I don't think you really need to: the point seems clear enough.

I don't especially like the idea you are suggesting though.  The general
principle in SQL is that a rolled-back transaction should have no effect
after it's been rolled back.  Allowing a cursor it creates to survive
the rollback would fly in the face of that principle.

Quite aside from that, there are technical issues.  As a perhaps
egregious case, what if the cursor's output depends on objects that
will disappear in the rollback?

    begin;
    create type rainbow as enum ('red', 'green', 'blue');
    create table r (f1 rainbow);
    insert into r values ('red');
    declare c cursor with hold for select * from r;
    rollback;

    fetch all from c;

Even if we surmount the implementation issues around holding onto the
bits emitted by the cursor, the FETCH is going to fail to return data
to the application, because it doesn't know how to interpret those bits
anymore.

So the short answer is you can't have that.  Find another way to design
your application.

            regards, tom lane



Re: Problem close curser after rollback

From
Matthias Apitz
Date:
On Wednesday, 30 September 2020 20:37:23 CEST, Tom Lane <tgl@sss.pgh.pa.us>
wrote:
> Matthias Apitz <guru@unixarea.de> writes:
>> El día miércoles, septiembre 30, 2020 a las 05:26:39p. m.
>> +0200, Laurenz Albe escribió:
>>> On Wed, 2020-09-30 at 13:32 +0000, Wiltsch,Sigrid wrote:
>>>> What can I do so that the cursor is retained despite rollback?
>
>>> You cannot start a transaction while you are reading a
>>> cursor; you probably
>>> get a warning "there is already a transaction in progress".
>
>> I think we will prepare the ten-liner in ESQL/C for further discussion.
>
> I don't think you really need to: the point seems clear enough.
>
> I don't especially like the idea you are suggesting though.  The general
> principle in SQL is that a rolled-back transaction should have no effect
> after it's been rolled back.  Allowing a cursor it creates to survive
> the rollback would fly in the face of that principle.

The general idea of transactions is that you START one at a moment,
go ahead and a ROLLBACK rolls back everything what was done *after* the
point of starting it.

We have here the case of not beeing able to define the start of
the transaction. The application wants to set it *after* the first (and
again after
each next) fetch. You say, the transaction starts already with that fetch.

We have to think how to deal with that missing feature in PostgreSQL
ESQL/C to define the point of where the transaction starts.

Btw: In all of the other DBS (Informix, Sybase, Oracle) we could define
that point
with START TRANSACTION.

Thanks

matthias





--
Sent from my Ubuntu phone
http://www.unixarea.de/
NO to the EU! NEIN zur EU!



Re: Problem close curser after rollback

From
Karsten Hilbert
Date:
On Wed, Sep 30, 2020 at 09:06:13PM +0200, Matthias Apitz wrote:

> Btw: In all of the other DBS (Informix, Sybase, Oracle) we could define that
> point with START TRANSACTION.

You can always use SET SAVEPOINT.

Karsten
--
GPG  40BE 5B0E C98E 1713 AFA6  5BC0 3BEA AC80 7D4F C89B



Re: Problem close curser after rollback

From
Matthias Apitz
Date:
El día miércoles, septiembre 30, 2020 a las 02:37:23p. m. -0400, Tom Lane escribió:

> Matthias Apitz <guru@unixarea.de> writes:
> > El día miércoles, septiembre 30, 2020 a las 05:26:39p. m. +0200, Laurenz Albe escribió:
> >> On Wed, 2020-09-30 at 13:32 +0000, Wiltsch,Sigrid wrote:
> >>> What can I do so that the cursor is retained despite rollback?
> 
> >> You cannot start a transaction while you are reading a cursor; you probably
> >> get a warning "there is already a transaction in progress".
> 
> > I think we will prepare the ten-liner in ESQL/C for further discussion.
> 
> I don't think you really need to: the point seems clear enough.

I did wrote the ten-liner to play around with. Interestingly, there exists an
undocumented ESQL/C statement 'EXEC SQL START TRANSACTION' which gives
in the esqlc log:

ECPGtrans on line 48: action "start transaction"; connection "sisis"

What as well does work is the following sequence:

        EXEC SQL PREPARE stmt1 FROM "SELECT tstchar25, tstint FROM dbctest WHERE tstint > ?";
        EXEC SQL DECLARE foo_bar CURSOR WITH HOLD  FOR stmt1 ;

        /* when end of result set reached, break out of while loop */
        EXEC SQL WHENEVER NOT FOUND DO BREAK;

        EXEC SQL OPEN foo_bar USING 1;

        while (1)
        {
                EXEC SQL FETCH NEXT FROM foo_bar INTO :tstchar25, :tstint;

                EXEC SQL COMMIT ;

                EXEC SQL START TRANSACTION ;
                printf("fetched: [%s] [%d] \n", tstchar25, tstint);

        // ... do something with the fetched data and because
        // it went wrong, we issue a ROLLBACK

                EXEC SQL ROLLBACK ;
        }

This fetches nicely through the table in the while-loop; without the
additional COMMIT, the START TRANSACTION gives

ECPGtrans on line 48: action "start transaction"; connection "sisis"
ECPGnoticeReceiver: there is already a transaction in progress

We will think now about what we have learned and how to repair our
application.

    matthias

-- 
Matthias Apitz, ✉ guru@unixarea.de, http://www.unixarea.de/ +49-176-38902045
Public GnuPG key: http://www.unixarea.de/key.pub
Без книги нет знания, без знания нет коммунизма (Влaдимир Ильич Ленин)
Without books no knowledge - without knowledge no communism (Vladimir Ilyich Lenin)
Sin libros no hay saber - sin saber no hay comunismo. (Vladimir Ilich Lenin)