How Pick Dictionary Items Work
Even after years many Pick people aren’t quite sure how atb7 or 8 work, they just put something one place, then the other, and if it works they leave it until they find out it doesn’t work for some new purpose. Here is how they work.
This article was inspired by a request for how the LPV processing code works. An explanation of that has been worked into this too. A number of assumptions are made of the reader including knowledge of the following topics. I apologize if I’ve made too many assumptions but I’m trying to keep this article focused:
- You know what a dict item is.
- You know how a stack works, pushing data on and popping it off.
- You know what processor codes are like A, F, D, MR, MT, etc.
- You understand a little something about the reverse polish notation (RPN) used in an F correlative.
- You’re using A an S type correlatives, and not I-types.
Now that we’re on a common base, consider this statement:
LIST ORDERS WITH DATE
The DATE def must have a Conversion with a D type. That converts the external representation to internal for comparisons. The conversion is again used immediately prior to output for final masking of the data.
Conversions in atb7 should be limited to processing codes that go both ways: D, MR, and MT are the primary ones.
The Correlative is executed on data prior to searching and sorting. The result of a correlative should be unformatted, searchable and sortable data. This is where we do G and T extractions, T-substrings, and calls to BASIC.
The correlative is also where codes like MCT, MCU, and MCL "should" go, but these codes have their place in conversions as well.
As an example of how atb 7 and 8 are used together, consider the statement on ORDERS above. We can assume that there is a D2/ in the atb 7 conversion which will take "12/1" and convert it into the internal representation, but now we need atb 8 correlatives to extract data from the file. If the order date*time is in the same attribute 14 we may need a correlative like F;14;(G0*1) to get the date. After atb8 gets the date, it’s checked against the data provided at input, and items that match are stored in a list. When searches are complete, the list is sorted in memory (they don’t bubble sort as they go for reasons you’ll see below). When the sorted list of raw data is available, the output is generated using atb7 conversions for final output masking.
That’s the basic way that it works. What if we want to do something like this?:
LIST ORDERS WITH CUST.CODE "A]" CUST.CODE
But we want the output to look like this:
Code is ABC
Code is ABD
etc
Here the output is different from the input. Some people might resort to something like this:
LIST ORDERS WITH CUST.CODE.IN "A]" CUST.CODE.OUT
Where the Code.In is just a basic extraction done with a correlative and the Code.Out formatting is done by another dict item with another correlative. To do this in one dict item we’d do something like this:
[01] S
[02] 0
[07] F;CCode is ;LPV;:
[08] F;CZ;23;:;(TCUSTS;X;;19)
In that contrived example we’re concatenating a Z to atb 23, then using that as a key to the custs file where we retrieve atb 19, supposedly the raw cust code.
Now that we have that code we can check it against the original request, "A]". If it matches it’s put on a stack. Note that atb7 isn’t processed yet. At output time we have a list of sorted items and their output from atb8. Now we apply the conversions.
For each item in the list the same process is executed to generate output. Normally the result from the correlative is available on the top of the stack. In the example above the text "Code is " is placed on the top of the stack, completely wiping it out. The result of the correlative is then brought back with the LPV (Load Previous Value) code. The two strings are concatenated, and that’s the output.
While I have seen this, using LPV at the beginning of the correlative is redundant. For example:
[07] F;LPV;CCode is ;_;:
Here we already have the result from atb8 on the stack, we clear the stack, and load the previously calculated value, which is again the results from atb8. Then we push the "Code is " text on the stack, reverse the entries, and concatenate.
Someone might wonder if you can’t just push “Code is ” onto the stack and then use the underscore code to swap that text with the correlative which was already at the top. Unless some platform has a bug the answer is no. Conversions and correlatives should operate on whatever is already on the stack, but if the first entry does not then the stack is initialized. That can be a good thing, as we saw in the example with the order data when you want to select raw data but the output doesn’t look anything like the data that was processed.
Since we’re here, you’ll notice in the example I used "0" for the attribute. Some people use 99 or 9999, etc when they’re computing some data in the conversion or correlative. That used to be a waste of processing power, though these days I think all MV variants check for this. What’s happening internally is that the attribute specified in atb2 is fetched before anything else. Let’s say we have 999 in there. For every item in the file, a scan is done to count every atb in and try to find atb 999. When it doesn’t find anything, the top of the stack is null, which is what the developer wanted in the first place, just a nice clean "nothing" on the stack. Then we get down to atb8 which completely replaces the top entry on the stack with some value anyway – so that initial fetch process was a complete waste. As we see in my example above, the first thing I put onto the stack is the letter Z, so rather than wasting time looking for atb 999 I just started with the first atb 0 and jumped right to the correlative processing. Again, I believe, but I’m not certain, that all modern MV DBMS platforms check right from the start to see when the correlative is going to initialize the stack, so they should bypass the initial fetch process. (I wonder how many engineers are scratching their heads now and going to look at their C or assembler source code…)
So to summarize, here is how dict items work:
- atb 7 conversion converts the use input into internal format from external.
- atb 8 extracts data from the database, compares to the internally formatted input data, and sorts the results.
- At output time, atb7 is applied to the raw data coming from atb 8.
- If atb 7 initializes the stack, use LPV to get the atb 8 value back.
You’ll find that values with the attributes work in similar ways. When there are multiple values in the correlative, each one is processed in succession, passing its result as the top stack entry for the processor code in the next value. If a value starts off by initializing the stack then it needs LPV to get the prior value. The final value of the correlative is passed to the first value of the conversion, and the final value of the conversion is used for the report output.
If your environment doesn’t work like this, please let me know. This is the way “Pick” based environments have always worked. If Prime flavors or some other variant works differently then we should all be aware of the difference because the order of operations here is critical to the way many applications report their data. If you have an in-depth commentary on this, please email it rather than posting a comment, and I’ll add it as another page to this article.