There is a dynamic navigation method for each of the corresponding GET statements: GET-FIRST( ) method, GET-NEXT( ) method, GET-PREV( ) method, and GET-LAST( ) method. There is also a GET-CURRENT( ) method that corresponds to the GET CURRENT statement, which again retrieves the current record from the database, normally to check to see whether it has been changed since you last read it.

These methods can take optional arguments that you can use to specify the lock mode (NO-LOCK, SHARE-LOCK, or EXCLUSIVE-LOCK) and wait mode (if it is NO-WAIT). The default lock mode is SHARE-LOCK. You generally want to change this default to specify either NO-LOCK or EXCLUSIVE-LOCK, depending on whether you need to prepare for it to be changed and protect the record against changes by other users.

Here’s a completion of the simple procedure used throughout this section, showing the QUERY-PREPARE(), QUERY-OPEN(), and GET-NEXT() methods and the use of the QUERY-OFF-END attribute:

VAR HANDLE hQuery.
VAR INTEGER iBufNum.
VAR CHARACTER cBufNames.
VAR LOGICAL lSuccess.

CREATE QUERY hQuery.
hQuery:SET-BUFFERS(BUFFER Order:HANDLE, BUFFER Customer:HANDLE).
hQuery:ADD-BUFFER(BUFFER SalesRep:HANDLE).
lSuccess =
  hQuery:QUERY-PREPARE("FOR EACH Order WHERE OrderStatus = 'Ordered', "
    + "FIRST Customer OF Order, "
    + "FIRST SalesRep OF Order "
    + "BY SalesRep").
IF NOT lSuccess OR ERROR-STATUS:NUM-MESSAGES NE 0 THEN
DO:
  /* Deal with possible errors in the Query Prepare. */
END.
hQuery:QUERY-OPEN().
REPEAT WHILE NOT hQuery:QUERY-OFF-END:
  hQuery:GET-NEXT().
  DISPLAY Order.OrderNum Customer.NAME FORMAT "x(20)"
    SalesRep.RepName WITH FRAME OrderFrame 10 DOWN.
END.
hQuery:QUERY-CLOSE().
DELETE OBJECT hQuery.
Note: Using the structured error handling model, built-in ABL methods like QUERY-PREPARE() raise ERROR if the block they occur in contains a CATCH block. Thus, you could replace the IF statement with a CATCH block for more readable code. See ABL Error Handling for more information.
This is the result: