Search This Blog

Wednesday, June 9, 2010

Declarative Sorting Of Dynamically Allocated In-Memory Tables With COBOL

Visual COBOL = Visual Studio COBOL
One of the things COBOL is really good at is data processing.

Its declarative data model makes it second only to SQL for this purpose. Both in Managed COBOL and native COBOL, Micro Focus COBOL can sort an in-memory table just by saying 'sort'. Not only that, a little trick with pointers and the linkage section means that we can sort any sized table and allocate the memory for that table on the fly. Here I am using Visual COBOL (Visual Studio COBOL) to work through these ideas. To do this, I am using an imaginary example of a retail data control system where we have product variants and stock keeping units (skus). Our little program shows how we can sort variant name/sku pairs by the sku number.

What does declarative mean?

Here we simply declare the structure of our table and how it is indexed and can be sorted:

linkage section.
       01 variants occurs 1 to 1000 depending on variant-count
                   ascending key is sku
                   indexed   by jump-start-index.
           03 sku  binary-long.
           03 decr pic x(20).

Because we have put this in the linkage section, we have declared all this but we have not allocated any storage to it yet - that comes later. Now we sort:

sort variants

Now that is the bit I love! Having declared the data and key structure of the table, COBOL knows everything it needs to know about how to sort it. We do not have to call some sort function passing in some functional thing like a lambda or a call back. All that complexity is taken away. We want the table sorted - so we tell COBOL to sort it! If only my kids were so easy to instruct...

How About Pointers And Allocation?

As mentioned, the declaration of the table is in the linkage section. I have also created a working storage item 'mem-ptr' which is usage pointer. This approach means we can use CBL_ALLOC_MEM to assign a block of memory to use for storing our table. The size of the block to allocate is worked out from the size of each record via the "length of" keyword pair and multiplying the result by variant-count. The location of that memory is pointed to by mem-ptr and we can tell COBOL to use it for our table by the statement "set address of variants(1) to mem-ptr". However, COBOL does need to know how big the table is. This is done by using variant-count in the "depending on" clause of the table declaration.

Putting It Together In Visual COBOL

First open Visual Studio:

Then start a new project:

Then pick a native COBOL template:

Take the created source and replace it with the source below:

$set sourceformat(variable)
       program-id. "sorter".

       working-storage section.
       01 mem-ln        binary-long.
       01 mem-flags     pic x(4) comp-5 value 0.
       01 int-bl        binary-long.
       01 mem-ptr       usage pointer.
       01 status-code   pic x(2) comp-5.
       01 variant-count binary-long.
       linkage section.
       01 variants occurs 1 to 1000 depending on variant-count
                   ascending key is sku
                   indexed   by jump-start-index.
           03 sku  binary-long.
           03 decr pic x(20).
       procedure division.
           move 10 to variant-count
           set mem-ln to length of variants
           multiply mem-ln by variant-count giving mem-ln
           call "CBL_ALLOC_MEM" 
                using     mem-ptr
                by value  mem-ln mem-flags
                returning status-code
           if not status-code = 0
               display    "Failed to get memory"
               stop run
           set address of variants(1) to mem-ptr
           move 1234       to  sku(1)
           move "beans"    to decr(1)
           move 12         to  sku(2)
           move "fish"     to decr(2)
           move 4532       to  sku(3)
           move "cat food" to decr(3)
           move 2342       to  sku(4)
           move "dog food" to decr(4)
           move 1231       to  sku(5)
           move "sauce"    to decr(5)
           move 1254       to  sku(6)
           move "bread"    to decr(6)
           move  999       to  sku(7)
           move "chicken"  to decr(7)
           move    1       to  sku(8)
           move "beer"     to decr(8)
           move    2       to  sku(9)
           move "wine"     to decr(9)
           move  9999      to  sku(10)
           move "tnt"      to decr(10)
           sort variants
           perform varying int-bl from 1 by 1 until int-bl greater variant-count
               display sku(int-bl) " =- " decr(int-bl)
       end program "sorter".

Giving this:

Now click in the left margin to put a break point on the "goback":

Now step into the program using the debugger and it will stop on the break point:

We can now see the sorted output!

For more stuff like this - check out the Visual COBOL Knol and The Managed COBOL Knol community sites