setll and setgt move the position of a keyed file without returning a record. The next read or readp then starts from that position. This page covers the syntax, the search argument, where the file is left, what %found and %equal mean after each, and the existence test.
It is a focused page. The short entry for each file operation is in the RPGLE File I/O Opcodes Reference, reading one record by key is in the RPGLE CHAIN Opcode Reference, and the functions that report the result are in the RPGLE File and Error BIFs Reference.
The examples are free-form RPGLE. They use a keyed file with the key fields CUSTKEY and ORDNO, which holds three records: C0001 / 1, C0001 / 2 and C0002 / 3.
dcl-f ordWork keyed usage(*input) extfile('*LIBL/ORDERW') rename(ORDERW : ordRec);
dcl-ds keyDs likerec(ordRec : *key);
dcl-s exists ind;
Syntax
setll{(EHMR)} search-arg name;
setgt{(EHMR)} search-arg name;
| Part | Meaning |
|---|---|
search-arg | The key, or the relative record number, to position at |
name | The file name, or for an externally described file the record format name |
(E) | Errors are not fatal. Test %error afterwards |
(H), (M), (R) | Rounding and precision, allowed only when the search argument is a list of values or %kds |
The file must be a full procedural file. The search argument can be a field, a named constant, a figurative constant or a literal. For an externally described file it can also be a list of values in parentheses, a KLIST name in older code, or %kds with a data structure. For access by relative record number it is an integer literal or a numeric field with no decimal places.
Where the file is left
| Operation | Positions the file | If no record qualifies |
|---|---|---|
setll | At the first record whose key is equal to or greater than the search argument | At the end of the file |
setgt | Immediately before the first record whose key is greater than the search argument | At the end of the file |
Neither operation reads a record. You get the record at the new position with read, or the record before it with readp. IBM warns that another job can delete the record between the positioning and the read, so a record that %equal reported may not be the one you read.
With the three records above:
| Operation | %found | %equal | read then returns |
|---|---|---|---|
setll to C0001 / 2 | on | on | C0001 / 2 |
setll to C0001 / 5 | on | off | C0002 / 3 |
setll to C0009 / 1 | off | off | End of file |
setgt to C0001 (first key field only) | on | not set | C0002 / 3 |
setgt to C0002 (first key field only) | off | not set | End of file |
SETLL then READ
Use setll to start reading at a key. If the exact key is missing, the file is left at the next higher key.
keyDs.CUSTKEY = 'C0001';
keyDs.ORDNO = 2;
setll %kds(keyDs) ordWork;
read ordWork; // the C0001 / 2 record
keyDs.ORDNO = 5;
setll %kds(keyDs) ordWork;
read ordWork; // C0002 / 3, the next higher key
SETLL as an existence test
setll does not access a data record. IBM says that if you only need to know whether a key exists, setll with %equal is in most cases a better performing choice than chain. The exception IBM names is a multiple format logical file with sparse keys, where chain can be faster.
keyDs.CUSTKEY = 'C0001';
keyDs.ORDNO = 2;
setll %kds(keyDs) ordWork;
exists = %equal(ordWork); // *on: that exact key is in the file
%found is not the existence test. It is on whenever a record at or above the key exists, so it stays on when only a higher key is present. Use %equal when the question is whether this key exists, and chain when you also need the data.
SETGT then READ
setgt skips every record that has the search key. A read after it returns the first record with a higher key, which makes it a way to skip a group.
keyDs.CUSTKEY = 'C0001';
setgt %kds(keyDs : 1) ordWork;
read ordWork; // C0002 / 3, the first record after the C0001 group
To get the last record of a group, read backwards from the position setgt leaves. This is IBM’s own pattern.
keyDs.CUSTKEY = 'C0001';
setgt %kds(keyDs : 1) ordWork;
readp ordWork; // C0001 / 2, the last C0001 record
Partial keys
For a composite key, %kds(ds : n) uses only the first n key fields. A partial setll positions at the first record whose leading key fields are equal to or greater than the values given.
keyDs.CUSTKEY = 'C0001';
setll %kds(keyDs : 1) ordWork;
read ordWork; // C0001 / 1, the first C0001 record
Give the values in key order and with the type of each key field. The reade loop that follows a partial setll is in the RPGLE READ, READE and READP Opcode Reference.
Start and end of the file
setll *start ordWork;
read ordWork; // C0001 / 1, the first record
setll *end ordWork;
readp ordWork; // C0002 / 3, the last record
*start and *end are search arguments for setll. They position at the beginning or the end of the file independently of the collating sequence and of null-valued keys, and the file name must be given as the name operand. IBM recommends them when you want the first or last record, because *loval and *hival do not always land there. This page does not state the release that introduced *start and *end, so check it before you use them on an older release.
*loval and *hival still work in the common case, and older code uses them.
setll *loval ordWork;
read ordWork; // the record with the lowest key
setgt *hival ordWork;
readp ordWork; // the record with the highest key
IBM lists the cases where they miss: a descending key, a record added or a key changed after the positioning, null-capable key fields, some numeric key types, and date and time keys that depend on the format. In a file with duplicate keys, *hival also may not place a readp on the last record.
Testing the result
| Test | After setll | After setgt |
|---|---|---|
%found(file) | On when a record at or above the key exists | On when a record above the key exists |
%equal(file) | On when a record with exactly that key exists | Not set. Do not use it |
%error | On after (e) when the operation failed | On after (e) when the operation failed |
Older code puts NR in positions 71 to 72, which is on when no record qualifies and so is the opposite of %found, and for setll EQ in positions 75 to 76, which is %equal. The Fixed-Format to Free-Format Opcode Mapping shows the conversion. Use the (e) extender or the ER indicator for real file errors, but not both. For how fixed-format specifications describe a file and its keys, see RPGLE Input and Output Specifications.
IBM notes that %equal is normally decided by data management, and in some cases it is not, so the comparison uses the hexadecimal collating sequence and can differ from what you expect. This matters for keys with an alternate collating sequence or a different CCSID.
SETLL, SETGT and CHAIN
setll | setgt | chain | |
|---|---|---|---|
| Reads a record | No | No | Yes |
| Exact key missing | Positions at the next higher key | Positions after the key | Not found. Nothing is read |
%equal | Set | Not set | Not set |
| Typical use | Start of a range, or an existence test | Skip a group, or find its last record | One record by key |
Common mistakes
- Using
%foundaftersetllas an existence test. Use%equal. - Testing
%equalaftersetgt, where it is not set. - Reading after a
setllorsetgtthat found nothing. The file is at the end, so thereadreports end of file. - Giving key values in the wrong order or with the wrong type.
- Using
*lovalor*hivalon a descending key or a file with null-capable keys, where*startand*endare safer. - Assuming the record that
%equalfound is still there when you read it.
FAQ
What is the difference between SETLL and SETGT?
setll lands on the first record equal to or greater than the key, so an exact match is the next record read. setgt lands after every record with the key, so the next record read has a higher key.
Does SETLL read a record?
No. It only positions the file. Use read for the record at that position, or chain to position and read in one step.
How do I test that a key exists?
Code setll, then test %equal(file). It is on only when a record with exactly that key exists.
Summary
setllpositions at the first key equal to or greater than the search argument, andsetgtpositions after the last record with it. Neither reads a record.- Test
%equalaftersetllfor an exact match.%foundonly says that a record at or above the key exists. - Use
%kds(ds : n)for a partial key,setll *startandsetll *endfor the ends of the file, andreadpaftersetgtfor the last record of a group. - Reading records one by one is covered in the RPGLE READ, READE and READP Opcode Reference, changing them in the RPGLE UPDATE, WRITE and DELETE Opcode Reference, and reading one record by key in the RPGLE CHAIN Opcode Reference.