PDA

View Full Version : Is it possible to ignore an error in a transaction (df3.2 CM)



Bernhard Mandl
22-Jun-2005, 10:53 AM
I would like to execute a piece of code that may trigger a dataflex error
within a transaction without being kicked out of the transaction.

Something like (pseudo code)

begin_transaction
begin_ignore_errors
gosub my_dangerous_operation
end_ignore_errors
// some other code to be executed here
end_transaction

possible ?

Thanks
Bernhard

Ben Weijers
22-Jun-2005, 01:54 PM
You could do this by setting the global attribute DF_TRANABORT_ONERROR to
false and using implicit transaction (lock .. unlock instead of
begin_transaction .. end_transaction). Why do you want to do this?

Regards,

Ben Weijers
Data Access Worldwide

Bernhard Mandl
22-Jun-2005, 02:11 PM
I need a "high concurrency" way to insert records into a table (PSQL in my
case), but only if the record does not exist.

This code is inherintly not multiuser safe:

find eq mytable by index.1
[not found] saverecord mytable

If two or more clients execute this code it will happen that both execute
the find at the same time. The first will successfully insert the new record
and the 2nd cleint will fail.

I need a way to catch this condition without being kicked out of the
transaction.

Regards,
Bernhard

"Ben Weijers" <ben.weijers@dataaccess.nl> schrieb im Newsbeitrag
news:d1kHhv1dFHA.1112@dacmail.dataaccess.com...
> You could do this by setting the global attribute DF_TRANABORT_ONERROR to
> false and using implicit transaction (lock .. unlock instead of
> begin_transaction .. end_transaction). Why do you want to do this?
>
> Regards,
>
> Ben Weijers
> Data Access Worldwide
>

Roger Loftus
22-Jun-2005, 02:46 PM
Bernhard Mandl wrote:

> I would like to execute a piece of code that may trigger a dataflex
> error within a transaction without being kicked out of the
> transaction.
>
> Something like (pseudo code)
>
> begin_transaction
> begin_ignore_errors
> gosub my_dangerous_operation
> end_ignore_errors
> // some other code to be executed here
> end_transaction
>
> possible ?
>
> Thanks
> Bernhard

Bernhard,

If that is close to the psudo-code you would be using, maybe you could
do this:
-------------------------------

begin_transaction
gosub my_dangerous_operation
// some other code to be executed here
end_transaction

my_dangerous_operation:
move |VI31 to strmark // save current (default) error routine
on error gosub JumpError // redirect all errors to dummy subroutine
// dangerous code here
move strmark to |VI31 // restore error routine number
[~err] begin
// code for no error
end
[err] begin
// code for error condition
indicate err false // be sure to restore err indicator
end
return

JumpError: // this traps all errors until |VI31 is restored
return

-------------------------------

This should kill all error handling from the point of error until |VI31
is restored. Be sure that is what you want to do!

Roger Loftus

Bernhard Mandl
22-Jun-2005, 03:01 PM
I tried this but it does not work (at least I was not successful).

the "on error" subroutine is executed but execution jumps to the
"end_transaction" command immediately after return from "JumpError"



"Roger Loftus" <rloftus@plantingstock.com> schrieb im Newsbeitrag
news:gAy2HM2dFHA.5304@dacmail.dataaccess.com...
> Bernhard Mandl wrote:
>
>> I would like to execute a piece of code that may trigger a dataflex
>> error within a transaction without being kicked out of the
>> transaction.
>>
>> Something like (pseudo code)
>>
>> begin_transaction
>> begin_ignore_errors
>> gosub my_dangerous_operation
>> end_ignore_errors
>> // some other code to be executed here
>> end_transaction
>>
>> possible ?
>>
>> Thanks
>> Bernhard
>
> Bernhard,
>
> If that is close to the psudo-code you would be using, maybe you could
> do this:
> -------------------------------
>
> begin_transaction
> gosub my_dangerous_operation
> // some other code to be executed here
> end_transaction
>
> my_dangerous_operation:
> move |VI31 to strmark // save current (default) error routine
> on error gosub JumpError // redirect all errors to dummy subroutine
> // dangerous code here
> move strmark to |VI31 // restore error routine number
> [~err] begin
> // code for no error
> end
> [err] begin
> // code for error condition
> indicate err false // be sure to restore err indicator
> end
> return
>
> JumpError: // this traps all errors until |VI31 is restored
> return
>
> -------------------------------
>
> This should kill all error handling from the point of error until |VI31
> is restored. Be sure that is what you want to do!
>
> Roger Loftus

Roger Loftus
22-Jun-2005, 07:08 PM
Bernhard Mandl wrote:

> I tried this but it does not work (at least I was not successful).
>
> the "on error" subroutine is executed but execution jumps to the
> "end_transaction" command immediately after return from "JumpError"
>

Bernhard,

Did you try resetting [err] false inside the error trap subroutine
(JumpError)? I suspicion the transaction aborts when an error is
triggered and is sensed within the transaction code. The question is
is probably whether the error trap subroutine can hide the the error
event from the transaction. If the on error subroutine is called
within the transaction structure, I would think that there is hope the
error could be absorbed.

Roger Loftus

Danny Berman
22-Jun-2005, 09:18 PM
Bernhard,

Perhaps you have oversimplified the situation when giving us this example,
but it appears that a simple lock before the find and unlock after the save
would solve the problem. Since that would be too obvious, I am curious what
other factors are involved.

-Danny-

"Bernhard Mandl" <b.mandl@_NOSPAM_a1.nat> wrote in message
news:P1v%23W41dFHA.788@dacmail.dataaccess.com...
I need a "high concurrency" way to insert records into a table (PSQL in my
case), but only if the record does not exist.

This code is inherintly not multiuser safe:

find eq mytable by index.1
[not found] saverecord mytable

If two or more clients execute this code it will happen that both execute
the find at the same time. The first will successfully insert the new record
and the 2nd cleint will fail.

I need a way to catch this condition without being kicked out of the
transaction.

Regards,
Bernhard

"Ben Weijers" <ben.weijers@dataaccess.nl> schrieb im Newsbeitrag
news:d1kHhv1dFHA.1112@dacmail.dataaccess.com...
> You could do this by setting the global attribute DF_TRANABORT_ONERROR to
> false and using implicit transaction (lock .. unlock instead of
> begin_transaction .. end_transaction). Why do you want to do this?
>
> Regards,
>
> Ben Weijers
> Data Access Worldwide
>

Ben Weijers
23-Jun-2005, 02:32 AM
You canot do this. If you use explicit transactions control will jump to the
end of the trasnaction whenver an error occurs.

Regards,

Ben Weijers
Data Access Worldwide

Bernhard Mandl
23-Jun-2005, 02:38 AM
We are using the PSQL CK with concurrent transactions enabled. This means
that a record is locked when it is read for the first time in the
transacton.

As the record does not exist when the find is executed no lock will be
applied. The insert will work at the first client, all other clients that
execute the same code at (almost) the same time will receive "duplicate
record not allowed" at the "saverecord" statement.

Strictly speaking this is a CK deficiency. Ideally the CK should handle the
situatian as follows:

If a "find eq" by the primary key or a non-modifiable index in a transaction
fails we know that the record does not exist. So the first "insert" into the
table for the same index value MUST be successful. If it is not we know that
another client inserted the record. In this case the transaction should be
retried because we just detected a multi user conflicting change.

But until this is implemented I need a workaround.

/Bernhard

"Danny Berman" <dberman@CustomizedData.com> schrieb im Newsbeitrag
news:3AA3fn5dFHA.1112@dacmail.dataaccess.com...
> Bernhard,
>
> Perhaps you have oversimplified the situation when giving us this example,
> but it appears that a simple lock before the find and unlock after the
> save
> would solve the problem. Since that would be too obvious, I am curious
> what
> other factors are involved.
>
> -Danny-
>
> "Bernhard Mandl" <b.mandl@_NOSPAM_a1.nat> wrote in message
> news:P1v%23W41dFHA.788@dacmail.dataaccess.com...
> I need a "high concurrency" way to insert records into a table (PSQL in my
> case), but only if the record does not exist.
>
> This code is inherintly not multiuser safe:
>
> find eq mytable by index.1
> [not found] saverecord mytable
>
> If two or more clients execute this code it will happen that both execute
> the find at the same time. The first will successfully insert the new
> record
> and the 2nd cleint will fail.
>
> I need a way to catch this condition without being kicked out of the
> transaction.
>
> Regards,
> Bernhard
>
> "Ben Weijers" <ben.weijers@dataaccess.nl> schrieb im Newsbeitrag
> news:d1kHhv1dFHA.1112@dacmail.dataaccess.com...
>> You could do this by setting the global attribute DF_TRANABORT_ONERROR to
>> false and using implicit transaction (lock .. unlock instead of
>> begin_transaction .. end_transaction). Why do you want to do this?
>>
>> Regards,
>>
>> Ben Weijers
>> Data Access Worldwide
>>
>
>
>

Ben Weijers
23-Jun-2005, 02:38 AM
I am not sure what you are saying here. Put a lock around this and it is
multi user safe. I really do not understand why you want to take this
dangerous route. If I remember correctly you are using P.SQL. If you are
looking for ways to speed up insert logic I personally would look into ESQL
or look into butil -load.

It never was (and never will be) a good idea to write multi use unsafe code.

Regards,

Ben Weijers
Data Access Worldwide

Bernhard Mandl
23-Jun-2005, 02:55 AM
Ben,

I think you misunderstand what I am after.

I have code where I have to make sure that a record with a certain index
value exists. Something that executes the following code atomically:

find eq mytable by index.1
[not found] saverecord mytable

The affected table is a table that is used by a very many clients at the
same time, so I must make sure that I do not produce unnecessary locks.

We are using concurrent transaction with the PSQL CK and locking does not
help here because records are locked when they are found, but the
unsuccessful find will not lock anything, so the "saverecord" is potentially
unsafe.

I do not see how ESQL could help me here.

I think I found a workaround that I will use if I get no better suggestion:

integer bInsertFailed
repeat
begin_transaction
move (false) to bInsertFailed
find eq mytable by index.1
[not found] begin
move (true) to bInsertFailed
saverecord mytable
move (false) to bInsertFailed
end
end_transaction
if (bInsertFailed) loop


Regards,
Bernhard

"Ben Weijers" <ben.weijers@dataaccess.nl> schrieb im Newsbeitrag
news:6X6AFa8dFHA.1112@dacmail.dataaccess.com...
>I am not sure what you are saying here. Put a lock around this and it is
>multi user safe. I really do not understand why you want to take this
>dangerous route. If I remember correctly you are using P.SQL. If you are
>looking for ways to speed up insert logic I personally would look into ESQL
>or look into butil -load.
>
> It never was (and never will be) a good idea to write multi use unsafe
> code.
>
> Regards,
>
> Ben Weijers
> Data Access Worldwide
>

Ben Weijers
23-Jun-2005, 08:05 AM
Barnhard,

I cannot think of a way to do this elegantly in na record locking
envirinment. Mind you this has nothing to do with VDF or the CK as far as I
can see you simply cannot do this elegantly in a record locking environment.
Your suggested code could work but why not use the DF_TRANSACTION_ABORT
attribute.
Regards,

Ben Weijers
Data Access Worldwide

Bernhard Mandl
23-Jun-2005, 08:37 AM
As I understand it "DF_TRANSACTION_ABORT " works only with LOCK/UNLOCK, not
with begin_transaction/end_transaction

I am working on a function that is supposed to be called from existing
programs that use begin_transaction/end_transaction and rely on the
behaviour that errors do automatically abort the transaction. I may not
change this.

I think it has to do with the CK in the sense that there is no mechanism to
ignore expected errors in a transaction. For situations like this it would
be helpful to be able to temporarily disable the "abort transaction on
error" behaviour.

An elegant code would look like this:

begin_transaction
find eq mytable by index.1
[not found] begin
SET_ABORT_TRANSACTION_ON_ERROR 0 // this is what is missing
indicate err false
saverecord mytable
SET_ABORT_TRANSACTION_ON_ERROR 1
if (err and lasterr = DFERR_DUPLICATE_REC) begin
find eq mytable by index.1
[not found] error DFERR_REC_NOT_FOUND // unexpected
end
end
end_transaction


"Ben Weijers" <ben.weijers@dataaccess.nl> schrieb im Newsbeitrag
news:8kT48Q$dFHA.5304@dacmail.dataaccess.com...
> Barnhard,
>
> I cannot think of a way to do this elegantly in na record locking
> envirinment. Mind you this has nothing to do with VDF or the CK as far as
> I can see you simply cannot do this elegantly in a record locking
> environment. Your suggested code could work but why not use the
> DF_TRANSACTION_ABORT attribute.
> Regards,
>
> Ben Weijers
> Data Access Worldwide
>

Larry Heiges
23-Jun-2005, 11:54 AM
Can't this be done outside of the transaction?

Do you need to also rollback the parent if it doesn't exist?

The saverecord will do its own internal lock/unlock if the saverecord
is required and you will be sure it's available inside the
transaction. The only thing lacking would be the auto rollback, which
you may be able to do manually if the transaction fails, after
checking that another user hasn't used the "new" parent.


Larry Heiges
App-2-Win Systems, Inc.
LookFeel for Windows
http://app-2-win.com
LFW7sp3
LFW10
LFW11

Bernhard Mandl
23-Jun-2005, 01:10 PM
> Can't this be done outside of the transaction?

Unfortunately no because the fact that a certain record is required is
detected in a transaction, so I must find or create the record in the
transaction.

Ben Weijers
23-Jun-2005, 01:43 PM
The DF_TRANSACTION_ABORT attribute works for biot expicit and implicit
tranactions. Why do yoiu thiink otherwise.

Remember that a database has a mind of its own. When an error occurs inside
a transaction most databases will rolback no matter what the program thinks
it shoud do. So even if we would just go on with the trasnaction, the
database server already rolled it back. It is just a "not done thing"...

Regards,

Ben Weijers
Data Access Worldwide

Bernhard Mandl
23-Jun-2005, 02:42 PM
> The DF_TRANSACTION_ABORT attribute works for biot expicit and implicit
> tranactions. Why do yoiu thiink otherwise.

I mixed this up with DF_TRANABORT_ONERROR (which has no effect for
begin/end_transaction)

How can DF_TRANSACTION_ABORT help me?

>
> Remember that a database has a mind of its own. When an error occurs
> inside a transaction most databases will rolback no matter what the
> program thinks it shoud do. So even if we would just go on with the
> trasnaction, the database server already rolled it back. It is just a "not
> done thing"...

I tried the same from java with the pervasive class library for java (aka
btrieve API from java) and it works, so btrieve does not abort the
transaction if insert of a row is refused because of a constaint violation.

Regards,
Bernhard

Larry Heiges
23-Jun-2005, 05:31 PM
No way to pre-process the transaction or parts of it far enough to
determine the parent? The tmp results could be kept in an array,
actually written to the DB in the transaction to avoid reprocessing.

Larry Heiges
App-2-Win Systems, Inc.
LookFeel for Windows
http://app-2-win.com
LFW7sp3
LFW10
LFW11

Ben Weijers
24-Jun-2005, 02:47 PM
How can DF_TRANSACTION_ABORT help me?

It wil tell you fi the transaction failed.

Well as I told you if you use implicit transactions and set
DF_TRANABORT_ONERROR you'll get the behavior you want.

Regards,

Ben Weijers
Data Access Worldwide