The INREC control statement reformats input records before the sort or merge phase runs. You use INREC FIELDS= or INREC BUILD= to define a new record layout: copy only the fields you need from the input, insert constants, reorder columns, or shorten the record. The result of INREC is what the sort sees—so SORT FIELDS= and any INCLUDE or OMIT conditions use positions in the reformatted record, not the original input. INREC is the right place to build sort keys, drop unneeded data to improve performance, or normalize the record before sorting. This page covers INREC syntax, FIELDS= and BUILD=, copying fields and inserting constants, when to use INREC versus OUTREC, and how INREC fits into the input phase.
INREC (Input Record) runs in the input phase. For each record read from SORTIN, DFSORT applies the INREC specification and produces a new record. That new record replaces the original for all later processing: it is the record that INCLUDE/OMIT (if present) evaluates, the record that the sort or merge phase orders, and—if you do not use OUTREC—the record that is written to SORTOUT. So INREC does not change how many records you have (unless you use IFTHEN to drop some); it changes the content and length of each record before sorting.
Why reformat before sort? Common reasons: (1) Shorten the record so the sort uses less memory and sortwork and runs faster. (2) Build a sort key that does not exist in the input—for example, concatenate two fields or convert a date so you can sort by it. (3) Reorder or drop fields so the layout going into the sort is exactly what you need for SORT FIELDS= and for downstream steps. (4) Insert constants or fill positions so that every record has a uniform layout before the sort.
The most common form is INREC FIELDS=(item1,item2,...). Each item is either a field copy or a constant. Items are placed into the output record in the order you list them, one after the other. The output record length is the sum of the lengths of all items.
A pair (position,length) means: copy length bytes from the input record starting at byte position. Positions are 1-based: position 1 is the first byte of the record. So (1,20) copies bytes 1 through 20 from the input into the next 20 bytes of the output. (50,10) copies bytes 50 through 59. The order in the FIELDS= list is the order in the output—so FIELDS=(50,10,1,20) puts the 10-byte block first, then the 20-byte block, giving a 30-byte output record with a different column order than the input.
Position and length always refer to the input record (the record as read from SORTIN). So when you write INREC, you are describing "take these pieces from the input and assemble them." The output has no gaps unless you explicitly insert constants (e.g. spaces) between field copies.
You can insert fixed data that does not come from the input:
Constants are useful for inserting delimiters, padding, or fixed prefixes/suffixes so that every record has the same structure before the sort.
INREC BUILD= is another way to define the output record. Like FIELDS=, you list items in order: field copies (position,length) and constants (C'...', X'...'). BUILD= and FIELDS= are equivalent for basic reformatting—both let you copy fields and insert constants in sequence. Some documentation and shops prefer BUILD= to make it explicit that you are "building" a new record; the behavior is the same. Example:
1INREC BUILD=(1,20,C' ',21,30,52,8)
This builds: 20 bytes from input positions 1–20, then one space, then 30 bytes from positions 21–50, then 8 bytes from positions 52–59. Total output length: 20 + 1 + 30 + 8 = 59 bytes.
Suppose the input is an 80-byte fixed-length file. You only need bytes 1–29 (e.g. ID and name) and bytes 45–74 (e.g. amount and date) for the sort and for the rest of the job. You can drop the middle section and the last few bytes with INREC:
12INREC FIELDS=(1,29,45,30) SORT FIELDS=(1,5,ZD,A)
INREC FIELDS=(1,29,45,30): copy bytes 1–29 (29 bytes) and bytes 45–74 (30 bytes) from the input. The output record is 59 bytes. No constants are inserted; the two blocks are concatenated. After INREC, every record is 59 bytes, so the sort phase sorts 59-byte records instead of 80. That reduces memory and sortwork. SORT FIELDS=(1,5,ZD,A) then sorts by the first 5 bytes of the reformatted record (which are the same as input bytes 1–5), as zoned decimal, ascending.
You want the output of the sort (before OUTREC) to have: a 10-byte key, then a comma and space, then 20 bytes of data. The key is at input positions 1–10 and the data at 31–50:
12INREC FIELDS=(1,10,C', ',31,20) SORT FIELDS=(1,10,CH,A)
The reformatted record is 10 + 2 + 20 = 32 bytes: key, then the literal ", " (comma and space), then the 20-byte data. The sort orders by the first 10 bytes (the key). If you did not use INREC and tried to sort the original 80-byte record, you would still sort by 1–10, but the record would be longer and the sort would do more work. Here, INREC both reorders and shortens.
After INREC, all control statements that refer to record positions use the reformatted record, not the original. So:
This is why building a new key in INREC is useful: you put the key at a known position (e.g. 1–20) in the reformatted record, and then SORT FIELDS=(1,20,CH,A) sorts by it. The original input might have had the key parts in different places or in a different format.
INREC runs before the sort/merge; OUTREC runs after. So:
If you need both—for example, shorten before sort (INREC) and then format the sorted result for a report (OUTREC)—you use both. The sort sees the INREC record; the output file gets the OUTREC record.
For variable-length (VB) input, the first 4 bytes of each record are the Record Descriptor Word (RDW). DFSORT often expects the first INREC item to be 1,4 so that the RDW is copied into the output and the record remains valid variable-length. Then you add the data fields you want. If you omit the RDW or change its meaning, the output may not be a valid VB record. For fixed-length (FB) input, there is no RDW; you just list the (position,length) pairs and constants for the data.
In some DFSORT variants you can specify where in the output record a field goes using a leading output_position:. For example, 7:1,10 means "copy 10 bytes from input positions 1–10 and place them starting at output position 7." That lets you build a record with gaps or overlay specific positions. For simple sequential building (no gaps), listing items in order with FIELDS= or BUILD= is enough and is the most common style. If your shop uses overlay positioning, refer to your DFSORT documentation for the exact syntax (e.g. BUILD=(1,20,26:50,5) to put the 5-byte block at output position 26).
INREC supports IFTHEN clauses for conditional logic: when a condition is true, apply one set of building rules; otherwise, apply another. For example, you might build a different layout for header records (byte 1 = 'H') than for detail records. IFTHEN is covered in depth in the INREC Processing and conditional processing tutorials; for a first step, FIELDS= or BUILD= with a single layout is sufficient.
Imagine you have a stack of cards with lots of writing on them. Before you sort the cards, you want to make them smaller and only keep the parts you care about. INREC is like a helper who takes each card, copies only certain lines (or parts of lines) onto a new, shorter card, and maybe adds a label or a comma in between. You then sort that new stack of shorter cards. So the sorter never sees the long cards—only the short ones. That way sorting is faster and the order is based on exactly what you put on the short cards. If you needed to add a "sort key" that wasn't on the original card (like combining two numbers into one), the helper would write that on the new card too. OUTREC is different: it happens after the sort, when you are writing the final list. So INREC = fix the card before sorting; OUTREC = fix how the final list looks when you write it down.
1. When does INREC run in DFSORT?
2. INREC FIELDS=(1,20,50,10) produces an output record of what length?
3. Why would you use INREC instead of OUTREC to shorten records?
4. You need to sort by a field that does not exist in the input—you must build it from two columns. Where do you build it?
5. What does a character constant C'ABC' in INREC BUILD do?