MODULE 6 · TABLES · 4/8

Serial SEARCH

14 min30 XPExercise

Looking something up in a table is one of the most common jobs in batch COBOL: turn a branch code into a name, a product code into a price, a postcode into a sales region. You could write the loop yourself with PERFORM VARYING, but COBOL has a statement for it: SEARCH.

       IDENTIFICATION DIVISION.
       PROGRAM-ID. SRCHDEMO.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  WS-BRANCH-VALUES.
           05  FILLER         PIC X(9) VALUE "D01DUBLIN".
           05  FILLER         PIC X(9) VALUE "C02CORK  ".
           05  FILLER         PIC X(9) VALUE "G03GALWAY".
       01  WS-BRANCH-TABLE REDEFINES WS-BRANCH-VALUES.
           05  WS-BRANCH      OCCURS 3 TIMES INDEXED BY BR-IX.
               10  WS-BR-CODE     PIC X(3).
               10  WS-BR-NAME     PIC X(6).
       01  WS-WANTED          PIC X(3).
       PROCEDURE DIVISION.
           MOVE "C02" TO WS-WANTED
           PERFORM 1000-FIND-BRANCH
           MOVE "X99" TO WS-WANTED
           PERFORM 1000-FIND-BRANCH
           STOP RUN.

       1000-FIND-BRANCH.
           SET BR-IX TO 1
           SEARCH WS-BRANCH
               AT END
                   DISPLAY WS-WANTED " NOT FOUND"
               WHEN WS-BR-CODE(BR-IX) = WS-WANTED
                   DISPLAY WS-WANTED " IS " WS-BR-NAME(BR-IX)
           END-SEARCH.

Output:

C02 IS CORK
X99 NOT FOUND

How SEARCH works

  • You search the table item that has the OCCURS (WS-BRANCH), not a field inside it.
  • The table must have an INDEXED BY index. SEARCH uses the first one.
  • It tests each WHEN condition against the current element. On the first match it runs that WHEN's statements and stops. The index is left pointing at the match, so you can use it afterwards.
  • If no element matches, it runs the AT END statements. AT END is optional, but leave it out and a failed lookup does nothing at all. That is almost never what you want.
  • You can have several WHENs. Whichever condition is true first wins.

Always SET the index first

SEARCH starts from wherever the index currently points. It does not reset it. Take out the SET BR-IX TO 1 above and look up C02 then D01: the first search leaves the index at element 2, so the second one starts there, never looks at element 1, and reports D01 NOT FOUND, even though D01 is in the table.

This bug is easy to miss in testing, because a single lookup works fine. It only shows up when lookups run in a certain order.

Starting part-way through

Because SEARCH starts at the current index, you can deliberately begin part-way through, for example SET BR-IX TO 5 to skip header entries. That is rare. SET ... TO 1 before every serial SEARCH is the rule.

Cost

A serial search checks elements one by one. For a table of 6 or 60 that is nothing. For 50,000 entries searched once per input record over millions of records, it adds up to hours of CPU time. The next lesson shows the fix.

On the job

Put the most frequently used codes first in a serial table. If 80% of transactions are for one branch, putting it at element 1 makes most searches end after one comparison. Old programs are sometimes ordered this way on purpose, so ask before you "tidy" a table into alphabetical order.

Your task

The hardware counter needs a price checker. The starter has a hard-coded product table with an index PROD-IX:

Code Description Price
A100 BOLT PACK 4.99
A200 NUT PACK 3.49
B150 HINGE 7.25
C300 PADLOCK 12.00
D410 CHAIN 1M 8.75
E500 TOOLBOX 29.99

Read product codes, one per line, until END. For each code display the code, description and price, or NOT FOUND. At the end display how many codes were not found:

C300 PADLOCK     12.00
A100 BOLT PACK    4.99
Z999 NOT FOUND
NOT FOUND: 001

Complete 1000-LOOK-UP with a serial SEARCH. Format the price with WS-PRICE-OUT.

fixed format
Run your program to see its output here. The first visible test's input and datasets are used.
Submit to grade your program against every test.