Consultor Eletrônico



Kbase P156135: Default error handling for duplicate record in FOR block skips a record
Autor   Progress Software Corporation - Progress
Acesso   Público
Publicação   12/13/2010
Status: Verified

SYMPTOM(s):

Default error handling for duplicate record in FOR block skips a record

** <file-name> already exists with <field/value...>. (132)

When creating a duplicate record in a unique key the ABL seems to skip an iteration of the FOR

FACT(s) (Environment):

There is no transaction defined at the block level
The transaction is scoped to the procedure
All Supported Operating Systems
Products / Versions

CAUSE:

The following code sample is intended to transfer four records from table a to table b, however table b has a unique index defined on a field which has multiple entries in table a. This causes errors to be shown on the screen and results in only two records being created in table b.

DEFINE TEMP-TABLE a
FIELD akey AS CHARACTER.

DEFINE TEMP-TABLE b
FIELD akey AS CHARACTER
INDEX aindex IS UNIQUE PRIMARY akey.

CREATE a.
a.akey = "A".

CREATE a.
a.akey = "A".

CREATE a.
a.akey = "B".

CREATE a.
a.akey = "C".

FOR EACH a:
CREATE b.
b.akey = a.akey.
END.

FOR EACH b:
DISPLAY b.
END.

When the above code executes, the following behavior occurs:

1) A record is created in b and its key is assigned to "a".
2) A second record is created in b and its key is assigned to "a" which causes an error to be raised.
3) The default behavior of an untrapped error in a FOR block is to first UNDO, then to RETRY that block, however the ABL realizes at this point that it may end up in an infinite loop if it attempts to retry the block so it executes a NEXT.
4) Since the transaction is scoped to the procedure, not the block, the buffer with the duplicate record is never actually released/undone from the previous iteration of the block and, since there can only be one record in any buffer at a time, when another record is created in it the ABL forces the WRITE/RELEASE of the previous record "again" which causes another UNDO, NEXT to occur.
5) The second record is finally released/undone.
6) The error in the previous iteration of the FOR block prevented the legitimate next block, for key "b", from being executed because the error occurred at the CREATE statement, therefore the NEXT brought it to the next iteration of the FOR loop where a new record is finally created and its key assigned to "c".

NOTE: This is expected behavior.

FIX:

Add the TRANSACTION keyword to the block and error handling code, if you wish, to handle the error. See the following example:

DEFINE TEMP-TABLE a
FIELD akey AS CHARACTER.

DEFINE TEMP-TABLE b
FIELD akey AS CHARACTER
INDEX aindex IS UNIQUE PRIMARY akey.

CREATE a.
a.akey = "A".

CREATE a.
a.akey = "A".

CREATE a.
a.akey = "B".

CREATE a.
a.akey = "C".

FOR EACH a TRANSACTION: /* Make the loop a transaction block */
CREATE b.
b.akey = a.akey NO-ERROR. /* Trap the error condition to prevent its display
on the screen */
IF ERROR-STATUS:ERROR OR ERROR-STATUS:NUM-MESSAGES GT 0 THEN
UNDO, NEXT. /* Add your error handling functionality here or just
undo and proceed with the next iteration */
END.

FOR EACH b:
DISPLAY b.
END.