Subject Re: [IBO] Strange behaviour
Author Helen Borrie
At 02:41 AM 9/03/2003 +0100, you wrote:
>hello Helen,
>ok, ok, timeout, I am an IBO student at the first year :-) Maybe I
>haven't explained myself correctly, and having now read the Tech Info
>about transactions, maybe I can see more light :-) I try to explain
>myself again with very few words:
>- When my query is opened, IBO automatically starts a *physical*
>transaction because I don't explicitly start the transaction by
>myself. Infact Transaction.Started is True and
>Transaction.InTransaction is False at this point.
>- After query opening, there are no logical transactions started or
>active because I haven't performed any operation yet. Infact
>Transaction.TransactionIsActive is False at this point because there
>is *nothing* to commit or rollback.
>- Being *nothing* to commit or rollback, why the commit and rollback
>buttons of the transaction bar are enabled?

They are enabled because a *physical* transaction is started. Every
transaction that is started has to be finished by either commit or rollback
- even just a fact, even a read-only transaction has to
committed or rolled back. Commit is better, because it uses less resources.

>This is my bug doubt. In my opinion the commit and rollback buttons
>should be enabled only when some data has been posted and have to be
>committed or rolled back; in this case (query opened, physical
>transaction started) only the *close transaction* button should be
>enabled (in effect it is), because as far as I know (very little :-)
>the *close transaction* button purpose is to close a *physical*
>transaction, isn't it?

Close transaction? See below.

>In my opinion this different behaviour would only be confusing for the
>programmer and end user. Suppose that I write this hypothetical phrase
>in the manual of my application:
>"Dear end user, when you will add a new customer, or you will edit or
>delete an existing customer, you will see the Commit and Rollback
>buttons illuminate (enable), giving you the ability to permanently
>store your changes into the database or discard them as a whole".

The Transaction Bar in general isn't a great interface to offer to
end-users. Either you are providing them with an Autocommit transaction
(in which case, the TransactionBar would add to the confusion); or you are
controlling the transaction in your code. A transaction is hard enough for
developers to understand! <g> It's useful in client programs written for
developers or SYSDBAs (see IB_SQL). For end users, if you don't want to
use Autocommit (and there are often good reasons not to), provide a
Save/Cancel button to call a procedure that tests the states of the
transaction and performs the appropriate Commit or/and Rollback.

>Well, don't you think that this end user will scratch his head when he
>will see the aforementioned buttons illuminated (enabled) having done
>nothing yet? And don't you think that this end user will scratch his
>head even more, seeing that the illuminated buttons will become grayed
>after two minutes without any intervention by himself?


>I gave a look at the source code in IB_TransactionBar.pas and I have
>noticed this snippet of code:
> Buttons[tbCommit].Enabled := Started or
> TransactionIsActive or InTransaction;
> Buttons[tbRollback].Enabled := Started or
> TransactionIsActive or InTransaction;
> Buttons[tbClose].Enabled := Started or
> TransactionIsActive or InTransaction;
>What is the behaviour difference for the three buttons?

The Commit button calls Commit. InTransaction returns the physical status
of the transaction (i.e. a transaction is/is not still running across the
interface); TransactionIsActive returns True if a DML task has been posted
but has not yet been committed (via Commit or CommitRetaining). If a
transaction is InTransaction (a physical transaction is running) but not
TransactionIsActive it still has to be committed or rolled back to end it.

The Rollback button rolls back the transaction - whatever state it is
in. TransactionIsActive will be True if Post was called and either the
work was successfully posted, or the request raised an exception. One
option the "operator" would have would be to rollback this failed a programmer, you should not try to make your poor user
decide. Rather, you should handle the exception by either rolling it back
yourself, or providing the means for the user to remediate it. But, in a
client app written for developers, you are more likely to want to provide a
more "raw" response to a failed request.

"Close transaction" is just a cleanup mechanism. It does what both of the
others do: it will try to commit posted work and it will rollback
everything if the commit fails. AFAIK, it will call a hard commit,
regardless of whether CommitRetaining would have been called otherwise.

>And this could be the corrected code for the two buttons?
> Buttons[tbCommit].Enabled := TransactionIsActive;
> Buttons[tbRollback].Enabled := TransactionIsActive;

Oh dear, no! In this case, if TransactionIsActive returns False, a running
transaction will just stay running forever. This looks like a highly
effective way to slow down and finally crash the server.

>Ok, even this time I have written too much :-) I hope I have been more
>clear though.

I think you might now be able to see that "corrected code" is not
required.<g> Apply the "horses for courses" rule to your UI
design. Except for the more technical, just protect the users from even
knowing about transactions! Users understand terms like "Save", "Confirm",
"Undo" and "Cancel" and they understand buttons.