Try OpenEdge Now
skip to main content
Updating Data with ProDataSets : Setting and using ERROR, ERROR-STRING, and REJECTED

Setting and using ERROR, ERROR-STRING, and REJECTED

So far, you have seen how everything works when your updates succeed. In this section, you will build in a simple example of rejecting a change and having that reflected in the user interface. Let us examine the three attributes, ERROR, REJECTED, and ERROR-STRING, that let you log and check the status of your updates.
Note: The ERROR, ERROR-STRING, and REJECTED attributes are effective only if a before-table is NO-UNDO during a Data Source update using the SAVE-ROW-CHANGES( ) method. If the before-table is UNDO, ERROR, ERROR-STRING, and REJECTED attributes are lost when a SAVE-ROW-CHANGES block is undone.
If necessary, you can temporarily apply the NO-UNDO attribute to a temp-table and change it back to UNDO after a SAVE-ROW-CHANGES completes.
ERROR is a logical attribute on a Data-Set, ProDataSet temp-table, and temp-table buffer that indicates whether any errors have occurred in applying changes back to the database.
The attribute is set by ABL when an error is encountered during FILL or SAVE-ROW-CHANGES. The FILL error condition sets ERROR to true for the ProDataSet and temp-table for which the error occurred. SAVE-ROW-CHANGES sets it to true for the ProDataSet and temp-table as well, but also for the particular buffer that failed in the save attempt. This might be because of a unique index violation or other constraint violation that generates a native AVM error, if a trigger procedure for the database table returns error, or if the record was changed by another user.
The ERROR attribute can also be set programmatically to signal an error condition of any kind. If you set ERROR to true for a buffer, it is not automatically set to true for the buffer's temp-table and for the ProDataSet. You can set the attribute at those levels yourself, if you wish. Setting the attribute at the level of a temp-table or the entire ProDataSet allows you to tell immediately whether there is an error anywhere in a set of changes. You can then check each individual row in the updated temp-table to locate one or more specific rows that have errors.
ERROR-STRING is a character attribute on each ProDataSet temp-table and on each temp-table row. This attribute is never set by the AVM because it is not always clear what error message (among several, for example) to store into the attribute. Your program can store a value into ERROR-STRING to return a useful message to the caller. Setting ERROR-STRING is independent of setting the ERROR condition.
REJECTED is a logical attribute for the ProDataSet, temp-table, and temp-table buffer. This is never set by the AVM, but can be set programmatically to indicate that a change was not saved to the database because of an error condition. The AVM does not set the attribute because it is not possible for it to automatically determine the scope of a failed update. This depends on the transaction scoping of the update process when multiple records are involved. The REJECTED attribute can be used to signal to the caller (and most specifically to the MERGE-CHANGES method) which rows were and were not successfully updated, so that the proper adjustments can be made to the client interface or to other logic.
For example, if your transaction scoping is such that a single error causes the whole set of changes to be rejected, then either you or the AVM can set the ERROR status for the one row that actually failed. Because the entire transaction was undone, however, you could set the REJECTED attribute to true for every affected row. In this way, the calling procedure can tell that all the changes were rejected and reset the origin ProDataSet and the user interface accordingly. At the same time, you can identify the single row that actually caused the update to fail, whose ERROR attribute is true, and flag that as the row that needs to be corrected. This is why ERROR and REJECTED are separate attributes.
If you use the MERGE-CHANGES method (or MERGE-ROW-CHANGES), it checks the REJECTED and ERROR attributes for each row and does the merge accordingly. For each row marked REJECTED or ERROR, MERGE-CHANGES effectively does a REJECT-ROW-CHANGES internally to restore the row in the origin ProDataSet to its original values. You can take advantage of this default behavior, or you can use the REJECT-CHANGES and REJECT-ROW-CHANGES methods yourself to get exactly the behavior you require.
In the event of an error, you might not want to use MERGE-CHANGES at all. For example, say the user updates a whole series of OrderLines and saves them. One of the OrderLines causes an error, and the nature of the transaction is that none of the changes are accepted. If you run MERGE-CHANGES on the change ProDataSet when you get it back on the client, it will restore the ttOline table and its browse to the state of the rows before the user made the changes. This does indeed reflect the state of the database, but it is almost certainly not the behavior you want. Now the user has to remake all the changes to all the rows in order to resubmit them for update.
Instead, you might check the ERROR attribute in your own code and use the REJECT-ROW-CHANGES method to restore just those rows that generated errors to their original values, so that just those rows need to be corrected. Or you might not restore any rows to their original values, but simply display the errors and let the user correct them and resubmit the changes. Then you can run MERGE-CHANGES when the updates succeed. This is why these different methods exist, so that you can determine the behavior you want and program accordingly. Do not blindly use the top-level methods like MERGE-CHANGES when they do not give you the behavior you want.
In principle, when you set any of these attributes at the individual row level, you set them and check them on the before-table buffer. However, to provide maximum flexibility, you can set them on either the before-table or after-table buffer and the effect is the same. If you set one of the attributes on the before-table buffer, you can check its value on the corresponding after-table buffer and vice versa. Remember in particular that for deleted rows, there will only be a before-table row that records the delete, so in general you should do your error setting and error checking on the before-table buffers.
As you learned earlier, there is also a DATA-SOURCE-MODIFIED attribute that indicates whether there was a conflict between the before-table values for a row being saved and what is currently in the database, indicating that the database has been changed by another transaction since the ProDataSet was filled. If this attribute is set for any row in a temp-table, it is also set for the temp-table itself, and for the ProDataSet. If a conflict results in a field value or an entire row not being saved, then the AVM sets the ERROR attribute. You can use the DATA-SOURCE-MODIFIED attribute to identify conflicts and flag them in the user interface, whether it is to signal why a change was unsuccessful, or to draw the user's attention to other changes that were either overwritten by the user's changes or combined with the user's changes, when the changes are to different fields.
The ERROR, ERROR-STRING, DATA-SOURCE-MODIFIED, and REJECTED attributes are all cleared for all tables and rows affected by an ACCEPT-CHANGES, REJECT-CHANGES, MERGE-CHANGES, or FILL method on a table or ProDataSet, or for an EMPTY-DATASET method on the ProDataSet or EMPTY-TEMP-TABLE method on a table.
* Using the error attributes in the sample procedures