Midrange News for the IBM i Community


Posted by: Bob Cozzi
Rogue Programmer
Cozzi Productions, Inc.
Chicagoland
Bob's Blog
has no ratings.
Published: 09 May 2011
Revised: 23 Jan 2013 - 4111 days ago
Last viewed on: 25 Apr 2024 (7380 views) 

Using IBM i? Need to create Excel, CSV, HTML, JSON, PDF, SPOOL reports? Learn more about the fastest and least expensive tool for the job: SQL iQuery.

Data Area APIs for IBM i and RPG IV Published by: Bob Cozzi on 09 May 2011 view comments

No Fanboy of Data Areas am I, but...

It's no secret that I'm no fan boy of data areas. But the truth is, every shop I go into to educate, consult or help optimize their RPG code uses data areas. Data areas are not a bad thing, but I have never liked the RPG→Data Area interface; it has always felt "forced".

Just before 1990, IBM introduced the first of what was to be thousands of APIs. Among the initial set of APIs were interfaces to access User Space objects. A "user space" was just an exposed or "legal" interface to the SPACE object that had been on the machine since it was conceived in the 1970s. I immediately abandoned Data Areas in favor of User Space objects and their much more flexible (albeit at the time more complex) set of APIs.

Add to that, the fact that Data Areas are really just another exposed interface to the SPACE object, and are much more restrictive (2000 character max length) and their declaration on D specs, primitive IN/OUT opcodes, ah, it just bugged me. So I never looked back and as a consequence never had a data area issue in any of my applications.

IBM i v5r2 Data Area Enhancements to RPG IV

Along with several refinements in v5r2, IBM enhanced RPG IV so that the DTAARA keyword on the D spec could accept a variable name. This enhancement allows you to specify a field name instead of a literal data area name. Then at runtime, you can insert the data area and library name just prior to the IN/OUT opcodes. This is similar to what they added to the File Specification's EXTFILE and EXTMBR keywords back on V5R1.

The new syntax for the DTAARA keyword on the D specs allows you to specify DTAARA(*VAR : myDataArea) where the MYDATAAREA field contains the name (or will contain the name) of the data area to be processed by the program. Previously you had to specify the data area name (unquoted). The syntax is, as I mentioned the same as the EXTFILE and EXTMBR keywords. So you may specify a variable name or a quoted literal. When a literal is specified, the data area name should be in all UPPER CASE and may be qualified using CL-qualified name syntax, just as DTAARA(*VAR : 'QGPL/APPSTORE')  This would specify the data area named APPSTORE in the QGPL library. Or you could specify the following:

     D runtimeDA       S             21A   Inz('QGPL/APPSTORE')
     D myDataArea      S             10A   Dtaara(*VAR : runtimeDA)

The RUNTIMEDA (runtime data area) field contains the qualified data area name, and MYDATAAREA is the variable that will receive the data area info. Using this technique with the UDS style data area data structure is also allowed, however the "UDS" is read when the program starts, so if a variable name is specified, it would need to be filled with the data area name before the detail Calcs begin--perhaps using an input parameter value, a literal, or a named constant to populate the variable

Data Area APIs

All the rules that make up the enhanced data area support in RPG just add to my indifference for data areas. Just give me a good old user space, and let me use RPG xTools to get to it (RPG xTools contains easy-to-use wrappers for User Space APIs) and I'm happy.

But in the "real world" (which usually means, in your fish bowl vs my fish bowl) people tend to run across data area use in legacy code and continue to integrate them into new code. So I thought I would share with you some ways to make that integration easier. Perhaps it isn't technically "easier" but it is more consistent with using functions and APIs rather than a retro-fit interface that requires you to stand on your left foot, point at the Moon and when the Sun is at Zenith, spin counter clockwise.

There are actually 3 APIs for Data Area access. Two of them were built for the C language, but may be accessed using RPG, and the third was introduced in IBM i v3r1 along with RPG IV.


Change Data Area Data (QXXCHGDA)

This API allows you to change the content of a data area. It accepts a data area name, and starting position, length and the new data. Its actually pretty straight-forward to use it, once you've properly prototyped it.

QXXCHGDA Parameters

Data Area Name: The data area name is, ironically, a 20-byte field where the first 10 positions are the data area name and the second 10 positions are the library name. The same restrictions for the data area name apply to this API as those for the CHGDTAARA CL command. The library name may be (A) any valid library name, (B) blank, (C) *CURLIB, or (D) *LIBL. The data area name may be any data area name, or the special values *GDA or *LDA (with no library name specified).

Start Position: The starting location in the data area where the data shall be changed. This is a 1's based position, not an offset.

Data Length: The number of bytes in the data area beginning with the Start Position, to be changed. 

New Data: The data to be written to the data area. This data should be as long as the Data Length parameter, or longer. Extra bytes are ignored.


Retrieve Data Area Data (QXXRTVDA)

This API allows you to retrieve the content of a data area. It accepts a data area name, and starting position, length and a variable to receive the returned data. Its actually pretty straight-forward to use it, and has fewer parameters than the QWCRDTAA API that many developers use. 

QXXRTVDA Parameters

Data Area Name: The data area name is a 20-byte field where the first 10 positions are the data area name and the second 10 positions are the library name. The same restrictions for the data area name apply to this API as those for the CRTDTAARA CL command. The library name may be (A) any valid library name, (B) blank, (C) *CURLIB, or (D) *LIBL. The data area name may be any data area name, or the special values *GDA, *LDA, or *PDA (with no library name specified).

Start Position: The starting location in the data area where the data shall be changed. This is a 1's based position, not an offset.

Data Length: The number of bytes in the data area beginning with the Start Position, to be changed. 

Retrieved Data: The data to be written to the data area. This data should be as long as the Data Length parameter, or longer. Extra bytes are ignored.


Retrieve Data Area Data (QWCRDTAA)

This API is different from the QXXRTVDA API in that it works with data areas on remote systems. It also uses the classic API parameter set, including that often times burdensome API Exception/Error Data Structure.

QWCRDTAA Parameters

Returned Data Area Data: The data structure QWCRDRTN_T (defined below) defines this return parameter. It is the classic, confusing API data structure style, including the infamous "bytes provided" and "bytes available" subfields. The final subfield in this data structure, QWCVALUE, receives the data retrieved from the data area. The other fields reflect information about the the returned data.

Returned Data (Receiver) Length: The length of the data structure specified on the first parameter.

Data Area Name: The data area name is a 20-byte field where the first 10 positions are the data area name and the second 10 positions are the library name. The same restrictions for the data area name apply to this API as those for the CRTDTAARA CL command. The library name may be (A) any valid library name, (B) blank, (C) *CURLIB, or (D) *LIBL. The data area name may be any data area name, or the special values *GDA, *LDA, or *PDA (with no library name specified).

Start Position: The starting location in the data area where the data shall be changed. This is a 1's based position, not an offset.

Data Length: The number of bytes in the data area beginning with the Start Position, to be changed. 

API Error Data Structure: The standard QUSEC API exception/error data structure. Declare your own implementation of this data structure using the LIKEDS keyword, initialize it, and then pass it on this parameter. Upon returning from the API call, the data structure will either be empty (the bytes available subfield will be zero) or if the bytes available is greater than zero, the CPF Message ID subfield will contain a value.


The Bottom Line

If you're going to continue to use Data Areas either by design, by habit, or because you like them, consider migrating the RPG code that interfaces with data areas to one of these APIs. At least then the Rub Goldberg interface for data areas in RPG IV can be avoided.

To help, I've created a source member that can be /COPY'd or /INCLUDE'd into RPG IV that exposes the Data Area APIs to your own programs. Note that since these APIs are actually *PGM objects (not subprocedures or functions) they do not require the QC2LE binding directory entry on the Header spec or BNDDIR compiler parameter.

Source Member: DTAARA in file QCPYSRC in library RPGREPORT
..... /if NOT DEFINED(QXXCHGDA)
      /define QXXCHGDA

      /INCLUDE QSYSINC/QRPGLESRC,QUSEC

     D DTAA_NAME_T     DS                  TEMPLATE Qualified
     D  dtaa_name                    10A
     D  dtaa_lib                     10A

        // Change Data Area
     D QXXCHGDA        PR                  EXTPGM('QXXCHGDA')
     D  dtaaraName                         LikeDS(DTAA_NAME_T) Const
     D   startPos                     5I 0 Value
     D   length                       5I 0 Value
     D  newData                    2000A   OPTIONS(*VARSIZE)

        // Retrieve Data Area Data
     D QXXRTVDA        PR                  EXTPGM('QXXRTVDA')
     D  dtaaraName                         LikeDS(DTAA_NAME_T) Const
     D   startPos                     5I 0 Value
     D   length                       5I 0 Value
     D  rtnData                    2000A   OPTIONS(*VARSIZE)

        // Returned Data Area Data/Data Structure for QWCRDTAA API
     DQWCRDRTN_T       DS                           TEMPLATE QUALIFIED
     D QWCBAVL                       10I 0
     D bytesAvail                    10I 0 Overlay(QWCBAVL)
     D QWCBRTN                       10I 0
     D bytesReturned                 10I 0 Overlay(QWCBRTN)
     D QWCTVRTN                      10A
        //  QWCTVRTN = *CHAR, *DEC, *LGL
     D rtnDataAreaType...
     D                               10A   Overlay(QWCTVRTN)
     D QWCLIBN                       10A
     D rtnLibName                    10A   Overlay(QWCLIBN)
     D QWCLVRTN                      10I 0
     D rtnLength                     10I 0 Overlay(QWCLVRTN)
     D QWCNBRDP                      10I 0
     D rtnDecPos                     10I 0 Overlay(QWCNBRDP)
     D QWCVALUE                    2000A
     D  rtnValue                   2000A   Overlay(QWCVALUE)

        //  Conventional RtvDtaAra API
     D QWCRDTAA        PR                  extPgm('QWCRDTAA')
     D  rtnDataDS                          LikeDS(QWCRDRTN_T) OPTIONS(*VARSIZE)
     D  nRtnDataLen                  10I 0 Const
     D  dtaaraName                         LikeDS(DTAA_NAME_T) Const
     D  nStartPos                    10I 0 Const
     D  nLength                      10I 0 Const
     D  apiErrorDS                         LikeDS(QUSEC) OPTIONS(*VARSIZE)
      /endif 

Return to midrangenews.com home page.
Sort Ascend | Descend

COMMENTS