Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Path: utzoo!mnetor!uunet!seismo!columbia!rutgers!sri-spam!mordor!lll-lcc!ptsfa!rtech!jeff
From: jeff@rtech.UUCP (Jeff Lichtman)
Newsgroups: comp.databases
Subject: Re: BIG, BIG fun w/Informix cursors
Message-ID: <1076@rtech.UUCP>
Date: Tue, 21-Jul-87 01:56:35 EDT
Article-I.D.: rtech.1076
Posted: Tue Jul 21 01:56:35 1987
Date-Received: Wed, 22-Jul-87 06:27:29 EDT
References: <229@paisano.UUCP>
Organization: Relational Technology Inc. Alameda, CA 94501
Lines: 98

From article <229@paisano.UUCP>, by demasi@paisano.UUCP (Michael C. De Masi):
> To insure data integrity, I had put all update statements within the
> context of a 'begin work ... commit work else rollback work' structure.
> 
> IMPORTANT:  Both 'commit work' and 'rollback work' have the side effect
> of closing every active cursor in the whole damn program!
> 
> (FLAME ON!!!)
> Now this is not limited to cursors acted upon within the structure, or
> indeed to cursors declared for update, but all of them.  The nice person
> I spoke to at Informix assured me that this was indeed a documented
> feature of both 'commit work' and 'rollback work'.  Documented or not,
> I find this a rather bizarre concept.  I thought the purpose of this
> structure was to insure transaction integrity, not to do cleanup work
> of record locks, etc.  In my humble opinion, this is the kind of thing
> best left to the programmer or to the database administrator itself and
> should not be hidden within the context of a seemingly non-related
> functionality.
> (FLAME OFF!!!)  Lord, do I feel better.
> -- 
> Michael C. De Masi - AT&T Communications (For whom I work and not speak)

Closing all cursors when committing or rolling back a transaction makes
sense, and conforms to the ANSI SQL standard.

It is easier to explain why "rollback work" should close all open cursors,
so let me start with that.  The "rollback work" statement is supposed to
reset the database to the state it was in before the transaction began.
It would be nearly impossible, in the general case, to position cursors
properly after a "rollback work"; for example, suppose you had deleted
a bunch of rows from a table, positioned a cursor just before these
deleted rows, and then did a "rollback work".  The deleted rows have to
come back, so should the next row you fetch be the first deleted row or
the one after the deleted row?

Now, about releasing locks when committing or rolling back a transaction:
The purpose of a transaction is to provide atomicity.  That
is, transactions assure that you don't see anyone else's updates before
they're complete, and that no one sees your updates before they're complete.
Transactions are also the basic unit of recovery (in case of a
system crash, for example, all incomplete transactions will be backed out
during recovery).  Locking is only a technique for providing atomicity.
Database systems release locks at commit or rollback time because they
are no longer needed: the transaction has either been entirely committed
or entirely backed out, so the locks can be released safely without
jeopardizing consistency.  To hold the locks longer than this wouldn't
hurt consistency, but it would kill concurrency.  It would be possible
to build a system that would allow the programmer to control when the
locks were released, but that would be putting the burden of maintaining
database consistency on the programmer; that's a service that the DBMS
should provide, and is one of the things that distinguishes a DBMS from
a file system.

Now that we've established why the DBMS releases locks at commit or
rollback time, let's consider why cursors must be closed at commit
time.  Suppose you are in the middle of a transaction, and you have
a cursor positioned in the middle of a table.  Now you do a "commit work".
Suppose we want the cursor to remain open; the DBMS would still have
to release its locks, which would mean that the cursor couldn't maintain
whatever locks it had on its current position.  Suppose, before
you tried to fetch the next row from the cursor, that someone destroyed
the underlying table, or deleted the row that the cursor was going to
advance to, or added a row in front of the one it was to advance to.
What should happen?  Not only would it be extremely difficult to
implement the DBMS to account for all possible cases of trying to
use a cursor that has had the locks swept out from under it, it would
be difficult to define what should happen in all cases (and many
definitions would necessarily be arbitrary).

It seems that Mr. De Masi got into this mess by trying to use "commit
work" and "rollback work" to guarantee the success or failure of
individual database statements.  That is not a correct use of transactions.
It appears to me that Mr. De Masi is looking for statement atomicity; that is,
he wants every individual database statement to completely succeed or
be backed out.  This is something that every relational DBMS should provide for
the user.  I'm not familiar enough with Informix to say whether it does
this, but it's a pretty good bet that it does.  Therefore, there should
be no need to test every update and either commit it or roll it back;
the DBMS will leave in the effects of every successful statement, and
back out the effects of every statement that couldn't complete due to
some DBMS error.  In SQL, the effects of all successful statements in the
current transaction are committed at the time of a "commit work" statement, or
backed out at the time of a "rollback work" statement.

It's possible that I misinterpreted Mr. De Masi's statements, and what
he's really looking for is a general-purpose way of getting rid of
unwanted updates (e.g. a program makes a successful update, then
later on in the transaction it decides it shouldn't have made the update
and needs to get rid of it).  Standard SQL doesn't provide any tools
for doing this, and I'm not aware of any DBMS that makes this easy for
you.  If your tables all have unique primary keys (always a good idea),
you could write your program so that it remembers the old row and the
new key; that way, you could put back the old row if you wanted.
-- 
Jeff Lichtman at rtech (Relational Technology, Inc.)
"Saints should always be judged guilty until they are proved innocent..."
{amdahl, sun}!rtech!jeff
{ucbvax, decvax}!mtxinu!rtech!jeff