Historically, APIs have been a bit of an enigma to most of the AS/400 programming community. To use them, you had to be familiar with mostly foreign objects like receiver variables, user spaces, and variable-length fields. And, in that respect, nothing much has changed. What has changed is the AS/400 programmer’s point of view. The cause may be global warming or a rise in UFO sightings. Or maybe it is because most AS/400 programmers realized that the ostrich approach (living with their heads in the sand) is not going to work in a world in which the equipment and software they work on changes on a daily basis.
Think about this: The computer you buy today may be outdated by next year, but the software you write today could very well be running decades from now. If Y2K taught us anything, it taught us that software often outlives its author. We were performing Y2K fixes to RPG code written back in the ’60s, for crying out loud!
The point is that, if your only goal is to remain gainfully employed in some oneman shop, working on some broken down CISC-based AS/400, just keep doing what you are doing. But the fact is, the previous depiction does not describe you, or you would never have read past the first few lines of an article with the acronym API in the title. No, you are more interested in learning about new tools and techniques and making yourself more valuable to your company or future potential employers. So, now that we have established that you are a hard-charging, up-and-coming dude (or dudette), let’s get down to the nitty-gritty and learn all about the Retrieve Data Area API (QWCRDTAA).
Who Wants to be an API Programmer?
An AS/400 data area is a single record file used to store information. Its beauty is in its simplicity. You can write data to it, and you can read data from it, but you have no record management to deal with. Consequently, you don’t have to deal with other complicated associations like logical views, multiple record formats, and a long list of other baggage generally associated with a physical file. Unfortunately for you, the programmer, IBM carried this simplicity thing a little too far with the tools that work with data areas.
You can create a data area using the Create Data Area (CRTDTAARA) command, display a data area using the Display Data Area (DSPDTAARA) command, retrieve a data area using the Retrieve Data Area (RTVDTAARA) command, change a data area using the Change Data Area (CHGDTAARA) command, or delete a data area using the Delete Data
Area (DLTDTAARA) command. Hello! Do you see something missing here? What about the ability to edit a data area? Did you think that the CHGDTAARA command would actually show you the data you were changing? If that is what you thought, guess again. Nope. You can specify the new value of the data and the position and length of the data to be changed. This seems an awful lot like the children’s game of pin the tail on the donkey. Just think of the data area as the donkey, and your data as the tail with the pin. One wrong move and you will end up making an ass out of yourself (pun intended). To blindly go where no man has gone before.... Sorry about that—went into a time warp for a minute
there. Back to the subject at hand....
Since IBM saw no need to give you the ability to edit a data area, this article shows you how to use APIs to do this very thing. It’s cool, and it’s fast!
What IBM did give us was an API to retrieve a data area, and it is named the Retrieve Data Area API (QWCRDTAA). We determined that we could use the API, combined with running the Change Data Area (CHGDTAARA) command (run via the QCMDEXC API), to create our own Edit Data Area (EDTDTAARA) command.
Would You Like to Use One of Your Lifelines?
This Edit Data Area utility consists of three objects: the RPG IV program EDT101RG; the associated display file, EDT101DS; and the EDTDTAARA command. The source code is too long for publication, but you can download it from the Midrange Computing Web site, (www.midrangecomputing.com/mc).
Figure 1 provides a sample of output for the command. The RPG program accepts one parameter that contains the name of the data area you wish to edit and the library where it resides. It passes the input parameter on to the Retrieve Data Area API (QWCRDTAA). The table in Figure 2 (page 114) describes the parameters for the Retrieve Data Area API. This is a relatively easy API to use because it only needs five parameters plus the obligatory, standard error data structure.
Parameter 1 is the name of the receiver variable, to hold the output from the API. Parameter 2 is the length of the receiver variable, named in Parameter 1. Parameter 3 is the qualified name of the data area. The qualified name of an object is simply the name of an object, directly followed by the library name where the object resides. Parameter 4 is the starting position within the data area to begin retrieving data. A -1 is used for this parameter, which tells the API to retrieve all the data in the data area from the beginning. And last, but not least, parameter 5 is the length of the data to retrieve.
Parameter 5 can be used in conjunction with parameter 4 to substring out part of the data from the data area. In this example, 32 KB is specified, which is roughly the maximum size of a variable field. This is used because, initially, you do not know the size of the data area you are going to edit. Therefore, you call the API twice; the first time to find the size of the receiver variable, and the second time to actually retrieve the data. This technique is pretty common when using the retrieve APIs.
The bottom line is that we are using the technique of double calling the API to determine the true size of the variable. So we call the API the first time, specifying 32 KB as the number-of-bytes-to-return parameter and specifying 8 bytes as the length of the receiver. After the first call of the API, the first field in the receiver variable (BYTESPOSS) contains the number of bytes that could have been returned by the API. This is also the length that the receiver variable should be. Once the length is established, we use the ALLOC command to allocate storage for that amount and call the API again, this time specifying the BYTESPOSS field as the size of the receiver variable.
The rest of the program parses through the returned receiver variable in 50-byte increments. There’s nothing magical about the number 50, we just decided that the size just fits pretty well on the screen in a subfile record. So each 50-byte chunk of data area equals one subfile record. This is pretty easy code if you are dealing with character-type data areas.
Most of the retrieve APIs have a parameter that describes the data to be returned. But, in the case of the Retrieve Data Area API (QWCRDTAA), the parameter was omitted because there is only one possible format.
The receiver variable definition, in Figure 2, shows the format of the returned data. The first two fields are the bytes-returned and total-bytes-possible fields, common to most retrieve type APIs. The third field is the type of data area that we are dealing with. The fourth field is the library name field, which contains the name of the library where the system finds the data area. The fifth field is the length of the data area. The sixth field is the number of decimal positions used when dealing with a decimal data area. If you total the lengths of all of these fields, you get the number 36. Consequently, the actual data that resides in the data area begins in position 37. Therefore, we defined the beginning of the data in 37 and run for a length of 2,000 more bytes, which happens to be the maximum length of a data area. We will only substring out the actual length of the data area as given in the field RtnLength in the receiver variable.
We found that we had a slight problem though. Why is nothing ever as simple as it seems? We found that the data returned in the receiver variable is packed data in a character variable. We found that we had to unpack the data to make it useable. Since the actual size of the data varies from data area to data area, we can’t code a simple move to a properly sized packed field. But that is what we need to do to unpack the data. So we needed to get a little creative when unpacking decimal data. We defined a data structure with 15 subfields. Each subfield is defined as packed and increases in size by one byte over the previous definition. So all we have to do is move the packed data into the inclusive data structure, determine the actual size of the data, and then move the correctly sized packed field definition to the character output field.
In looking through the code, you might see something else that looks a little unusual. We defined our subfile so that each subfile record is 50-bytes long and underlined.
But we did not want the underlined field to extend past the actual end of the data, and the length of every data area is not always going to be divisible by 50. So we needed to concatenate the protect and nondisplay control characters to the end of the last subfile record. The reason for doing this was purely cosmetic, but we liked the end result better this way.
As you can see, this program is both simple and functional. In the interest of brevity, we did not perform any edits on the data entered to ensure validity of data types. In other words, you can key alpha characters on the screen into a numeric data area. The program would blow up if you tried to do this. If you are going to use this utility, you should probably add your own edit routines.
Is That Your Final Answer?
APIs are a great way to retrieve data that is not otherwise readily available. Take a few minutes and browse through the API manuals. You may be surprised at how much information you can retrieve on your AS/400. If the information is there, there is probably a way to get it. All you need is to know is how.
Figure 1: EDTDTAARA looks similar to DSPDTAARA and is as easy to use.
Parameter Description Type Attribute Size
1 Receiver variable takes Output Char Varies the following format:
From To Description
Possible bytes to return Binary
Actual number of bytes returned Binary 4
Type of data area Char 10
Library name Char
Length of data area Binary 4
2 Receiver length Input Binary 4
Length of receiver variable specified in parameter 1.
3 Data area name Input Char 20
Qualified data area name. First 10 bytes is data area name, second 10 bytes is library name.
Special Name Values
*LDA Local data area
*GDA Group data area
*PDA Program initialization parameter data area
Special Library Values
*LIBL Library list
*CURLIB Jobs current library
4 Starting position Input Binary 4
Starting position with the data area to begin retrieving data. -1 indicates retrieve all data from the data area. 2000 bytes maximum.
5 Length of data to retrieve Input Binary 4
Cannot be zero. This length plus starting position -1 cannot exceed actual length of data area.
6 Error data structure I/O Char Varies
Standard error data structure.
Number of decimal positions Binary
Information stored in data area Char
Figure 2: The Retrieve Data Area API parameters are few and easy to understand.