Friday, November 18, 2011

ISPF Tables

Most of our uses of ISPF tables are very simple.  Every once in a while, however, we might bump into a relatively-more-complex situation where the uses are not so simple.  Without fail, such times are opportunities for us to learn some very difficult and painful lessons.  It's much better to learn them on a blog than while sitting before a terminal pumping code in a vain attempt to make a deadline.  The most difficult lesson is this: reading a table row populates any REXX variables that have matching names (and creates them otherwise).  This is most dangerous when you have to work with more than one table simultaneously.  Let me illustrate:

   address ISPEXEC 
   "TBSKIP ORDERS" /* sets vendor, product, date, qty, invoice */
   "TBGET  INVENT" /* keyed by 'product', sets qty, descrip */ 

The value for 'qty' from 'ORDERS' has been overlaid by 'qty' from 'INVENT'.  To preserve the original 'qty', it has to be copied to a different variable name.  Code-writing time is the wrong place to have to suddenly rename variables wholesale.  That is why I recommend that every table variable name should have a two-character prefix unique to the particular table:

   address ISPEXEC 
   "TBSKIP ORDERS" /* sets orvendr, orprod, ordate, orqty, orinvc */
   "TBVCLEAR INVENT"
   inprod = orprod
   "TBGET  INVENT" /* keyed by 'inprod', sets inqty, indesc */ 

There is now 'orqty' and 'inqty' and they can be compared, perhaps to see whether it's time to reorder.

Problem solved?  Hardly.  ISPF tables have more tricks up their sleeve(s).  Behold... extension variables.

Extension variables are unique to each row, and only the programmer exercising care in their naming can prevent clashes such as above.  As with ordinary table variables, extension variables also populate REXX variables when the row is read, and there is no warning that a simple TBSKIP may have clobbered other variables... unless the programmer is smart enough to ask if any extension variables were transferred with the rest of the row:

   "TBSKIP ORDERS SAVENAME(xvars)"
   parse var xvars  "("  xvars  ")"

which lets us know that 'ornotes', 'ormgrnam' and 'ormgrtel' were set without warning.  If we were to update that row without also commanding that those three extension variables be included in the update, they would simply disappear, also without warning.  It's a quick way to shoot holes in table data.  That's not us, thankfully.  We're smart enough to:

   "TBMOD   ORDERS  SAVE(" xvars ")"

thus preserving the data in those extension variables.

As with everything else, a few small proof-of-concept routines can be an invaluable learning aid, and (of course) you need to test the logic to death.

No comments:

Post a Comment