See how a great utility can be made even better using APIs
In the April 1991 issue, Ernie Malaga provided a useful utility program that printed a library-size report. I created the utility, ran it, and was able to spot some objects that were taking up too much space. As Ernie pointed out, the utility takes a good while to run -- elapsed times of more than an hour were common on my system. At the end of the article, Ernie alluded to the possibilities of improving the performance of the utility with the new Release 3.0 system APIs.
That set me to work with the dual purpose of investigating the APIs and improving the utility. The results of my experiments were somewhat surprising. Although we will have much more to say about system APIs in the future, you can begin now with this article. This is a good example of how to learn a lot by taking an existing function and modifying it. The concepts that are described in this article cover the basics of what you will need to know to use other APIs.
What are APIs?
An API (Application Programming Interface) is IBM's way of giving us more direct access to some of the components of OS/400 and other products such as Office/400. To be useful, an API consists of two components: the machine component that actually performs the function, and the documentation component that describes precisely how to use the function. The machine components are provided as part of OS/400. The documentation consists of the System Programmer's Interface Reference (SC21-8223) and PTF SF06260.
Unfortunately, the documentation component is not that useful for a "first look" at APIs. There are several errors in the sample programs in the book, resulting in programs that fail to compile, and mistakes in the data structures provided in the QUSRTOOL library that make learning about APIs through experimentation a trying experience.
The Function of an API
For the example program shown here, the function of the API is to replace the DSPOBJD (Display Object Description) command, with OUTFILE processing, as described in the April 1991 article. The program first had to generate a list of library objects, then generate a list of all objects in each library. Finally, a program was called to process the OUTFILE, summing the size of objects in the library and determining the largest object in each library. As Ernie correctly surmised, there's a performance penalty to generating the OUTFILE, then reading it in the RPG program. The equivalent function can be programmed with APIs.
In order to program this function, you need to use three APIs in RPG, and four if you choose to process using pointers in a pointer-capable language (C, PL/I, PASCAL). The APIs you use are the Create User Space API, the List Objects API, and the Retrieve User Space API. For pointer-capable languages, you also use the Pointer to User Space API.
Using APIs in the Program
The API that does "the work" in the program is the List Objects API. This generates a list of data about objects that we specify, and takes the place of the DSPOBJD command with the OUTFILE. The question is, where is this list generated, and how do we access it?
The List Object API puts the list data in a User Space object. A User Space is, more or less, a named collection of bytes. It differs from a file, in that there are no record formats associated with the space, and no concept of processing it as a file (sequential read or random retrieval). Although the system does not specify a processing method for a user space, your program does. As you will see in this example, the program practically uses the user space as a file, since we apply a program-defined record format to the space and move sequentially through the space.
Prior to using the List Object API, you use the Create User Space API. This tells the system to create the user space object with the name you supply in the library that you specify. You also provide an initial size for the space, and some other object-type information. To get at the list data, you use the Retrieve User Space API, which returns 1 or more bytes to your program from the user space.
API Support
When I began experimenting with APIs, I was in the book constantly. The book has several charts that show the format of data and parameters used by the APIs, in terms of the length of the parameter and the offset from the beginning of the parameter list. Supposedly, the source members provided in the QUSRTOOL library could be used as the formats; however, I found several errors in the RPG formats. Because I also wanted to try the APIs in PL/I and C, I decided to create definitions for API parameter lists as external files, then include the definitions in my programs. The definitions that you'll need for the example are shown in Figures 1 through 4. To create these, you simply enter them as externally described physical files. These are not data files, simply lists of fields used in API parameters.
The OBJL0700 format, used with the List Objects API, needs some explanation. The List Objects API lets you specify the level of detail you want to retrieve for each object in the list. Supposedly, performance of the API is best when you retrieve the least information, and worsens as you retrieve more. The List Objects API defines seven formats of information that you can retrieve, in an "additive" fashion. That means that you can start with format OBJL0100, object name information. That returns the object name, library and object type only. You can then supplement that with OBJL0200, and get the extended attribute (e.g., PF, LF for files) and text, and so on. Each additional format adds more information to the previous formats. You cannot retrieve the "higher format" information alone; in our example, using the OBJL0700 format gets all of the preceding formats.
I created the OBJL0700 format, and will probably always use that. If you think you will use the List Objects API and need less information, you can use the source member shown here as a basis for creating the less-extensive formats.
APIs in a Program
After you examine the API parameter formats, you can turn your attention to the sample program. This program replaces the LIB002RG and LIB002RGA programs in the April 1991 article. Keep in mind that the program needs to get a list of libraries, then a list of all objects in each library. With the list for each library, the total is accumulated, and the largest object name and size is recorded. All of this information is written to the work file record. The work file is then passed to a program to print the report. We have kept the printing program (LIB002RGB) rather than incorporate it into this program.
Looking at the RPG source, you see that we have included the parameter formats as externally described data structures. In the main routine, the first significant section of code retrieves the list of libraries. It does this by first creating a user space to contain the list, then calling the List Objects API to list libraries into the user space. We tell the List Objects API to generate the list with the OBJL0700 format, which puts the maximum amount of information for each library object into the list. We need to specify this because the object size is at the very end of the OBJL0700 format (the object size, for a library, is shown as the "directory size" on the report).
The next section of code retrieves the list of all objects in each library, in turn. This section starts with a call to the Retrieve User Space API, which retrieves data for a library from the user space. The DSPLIB subroutine is then called, which works like the just-executed routine to get the libraries.
And that's really all there is to it. As you can see, there are no references to files, other than the work file that is used in the print program. The list is created into the user space, and the program retrieves data with CALLs to system APIs.
Performance
One of the touted virtues of system APIs is that you can improve performance for these types of applications. You might intuitively think, as I did, that using a user space and program CALLs would be faster than using the DSPOBJD with an OUTFILE approach.
The results of several experiments on our B10 system are shown in the table in 5. There are two sections to this table. In the first test suite, I simply ran the program to accomplish the same results as the April 1991 program: get a summation of object size for all libraries on the system. As the table shows, using the APIs improved performance by 1.3 percent, as shown by CPU time used. When dealing with a program that runs for an elapsed time of over an hour, this improvement is unnoticeable.
The results of several experiments on our B10 system are shown in the table in Figure 5. There are two sections to this table. In the first test suite, I simply ran the program to accomplish the same results as the April 1991 program: get a summation of object size for all libraries on the system. As the table shows, using the APIs improved performance by 1.3 percent, as shown by CPU time used. When dealing with a program that runs for an elapsed time of over an hour, this improvement is unnoticeable.
Somewhat more significant was the PL/I test in which I used the pointer to the user space method to retrieve data from the user space, rather than calls to the Retrieve User Space API. This improved performance 22.1 percent, which is significant.
In terms of the usefulness of the program, though, a very simple change can be made to the original April 1991 source: don't get the object list for library QSYS. The reason for omitting this is that you probably won't be able to do much about anything in QSYS, other than spool file members. So if you run the report once, just to see the QSYS size, you can then change the program (or control it via a parameter) so that QSYS is no longer included.
This simple change cut in half the length of CPU time for the RPG program, and approximately halved the PL/I program. The elapsed time was also halved, to about half an hour.
One interesting experiment I conducted with the RPG version involved the "object size" and the "object size multiplier." These are the last two entries in the OBJL0700 format, and are used to calculate the size of the object. The documentation for the API states that the object size multiplier will be a value of 1, or 1024 or 1048576. This is apparently used for large objects, where the object size will not fit into the object size field. Since most object size multipliers will be 1, there's no need to perform the multiplication to arrive at the object size for most objects. This is shown in the RPG program, where the test is made for object size multipliers greater than 1. Only performing the multiply when needed, rather than performing it for every object, resulted in a 1.8 percent CPU time saving. Since this was not performed for 5752 objects, it appears that the B10 multiply takes .0013908 seconds. Obviously, this is not significant when the number of multiplies is small, but you can see how, in a "batch"-type situation, the penalty for unneeded operations mounts up.
So what is the conclusion? Given that the system APIs did not result in significant gains, what is the point of even considering using them? One reason might be to learn more about a very important topic of the AS/400 -- APIs. We will be exploring APIs more in future issues, and developing other applications that use APIs. Also, we will take an in- depth look at the user space, since this object is used by many of the system APIs.
Real Life APIs
Figure 1 Create User Space API parms (PF ##0015PF)
A***************************************************************** A* QUSCRTUS: CREATE USER SPACE LAYOUT A***************************************************************** A* A R CRTUS TEXT('Create User Space layout ') A CSQLSN 20 TEXT('Qualified Space name ') A CSEXTA 10 TEXT('Extended attribute ') A CSINSZ 9B 0 TEXT('Initial size ') A CSINVL 1 TEXT('Initial value ') A CSPAUT 10 TEXT('Public authority ') A CSTEXT 50 TEXT('Text description ')
Real Life APIs
Figure 10 Revised command PRTLIBSIZ (PRTLIBSIZA)
PRTLIBSIZ: CMD PROMPT('Print Library Sizes') PARM KWD(SORT) TYPE(*CHAR) LEN(5) RSTD(*YES) + DFT(*NAME) VALUES(*NAME *SIZE) + PROMPT('Sort option') PARM KWD(VERSION) TYPE(*CHAR) LEN(4) RSTD(*YES) + DFT(*RPG) VALUES(*PLI *RPG) PROMPT('Version')
Real Life APIs
Figure 2 Retrieve User Space API parms (PF ##0016PF)
A***************************************************************** A* QUSRTVUS: RETRIEVE USER SPACE GENERIC LAYOUT A***************************************************************** A* A R RTVUS TEXT('Retrieve User Space layout ') A RSRSCL 64 TEXT('Reserved for caller ') A RSHDSZ 9B 0 TEXT('Size of generic header ') A RSSTLV 4 TEXT('Structure level ') A RSFMTN 8 TEXT('Format name ') A RSPGM 10 TEXT('Pgm/API generating list ') A RSLSDT 13 TEXT('List written date/time ') A RSINST 1 TEXT('Information status ') A RSUSSZ 9B 0 TEXT('Total size of space used ') A RSOFIP 9B 0 TEXT('Offset - input parms ') A RSSZIP 9B 0 TEXT('Size - input parms ') A RSOFHD 9B 0 TEXT('Offset - header ') A RSSZHD 9B 0 TEXT('Size - header ') A RSOFLS 9B 0 TEXT('Offset - list data ') A RSSZLS 9B 0 TEXT('Size - list data ') A RSCTLS 9B 0 TEXT('Count - list data ') A RSSZEN 9B 0 TEXT('Size - each entry ')
Real Life APIs
Figure 3 List Objects API parms (PF ##0017PF)
A***************************************************************** A* QUSLOBJ: List Objects Parms A***************************************************************** A* A R LOBJ TEXT('List Objects parms ') A LOQLSN 20 TEXT('Qualified Space Name ') A LOFMTN 8 TEXT('Format name ') A LOOBLI 20 TEXT('Object/Library to list ') A LOOTYP 10 TEXT('Object type to list ')
Real Life APIs
Figure 4 List Objects API returned data (PF ##0018PF)
A***************************************************************** A* QUSLOBJ: FORMAT OBJL0700 A***************************************************************** A R OL0700 TEXT('QUSLOBJ, FORMAT OBJL0700 ') A***************************************************************** A* ..format OBJL0100: name information A***************************************************************** A O7ONAM 10 TEXT('Object name ') A O7LNAM 10 TEXT('Library name ') A O7OTYP 10 TEXT('Object type ') A***************************************************************** A* ..format OBJL0200: name, extended atr, text A***************************************************************** A O7OSTS 1 TEXT('Object status ') A O7EXAT 10 TEXT('Extended attribute ') A O7TEXT 50 TEXT('Text description ') A O7RS01 17 TEXT('Reserved ') A***************************************************************** A* ..format OBJL0300: basic object information A***************************************************************** A O7AUXP 9B 0 TEXT('Auxiliary storage pool ') A O7OWNR 10 TEXT('Owner ') A O7DOMN 2 TEXT('Domain - *S=System, *U=User') A O7DTCR 8 TEXT('Date, creation ') A O7DTCG 8 TEXT('Date, change ') A O7STOR 10 TEXT('Storage ') A O7RS02 22 TEXT('Reserved ') A***************************************************************** A* ..format OBJL0400: creation information A***************************************************************** A O7SRCF 10 TEXT('Source file name ') A O7SRCL 10 TEXT('Source file library ') A O7SRCM 10 TEXT('Source file member ') A O7SRCU 13 TEXT('Source file update date/time') A O7CRET 10 TEXT('Creator ') A O7SYSC 8 TEXT('System created on ') A O7SYSL 9 TEXT('System level ') A O7COMP 16 TEXT('Compiler ') A O7OBLV 8 TEXT('Object level ') A O7USCG 1 TEXT('User changed ') A O7LCPG 16 TEXT('Licensed program ') A O7PTF 10 TEXT('PTF ') A O7APAR 10 TEXT('APAR ') A O7RS03 21 TEXT('Reserved ') A***************************************************************** A* ..format OBJL0500: save/restore information A***************************************************************** A O7DTSV 8 TEXT('Date, save ') A O7DTRS 8 TEXT('Date, restore ') A O7SVSZ 9B 0 TEXT('Save size ') A O7SVMU 9B 0 TEXT('Save size multiplier ') A O7SVSQ 9B 0 TEXT('Save sequence number ') A O7SVCM 10 TEXT('Save command ') A O7SVVL 71 TEXT('Save volume IDs ') A O7SVDV 10 TEXT('Save device ') A O7SVFI 10 TEXT('Save file ') A O7SVFL 10 TEXT('Save file library ') A O7SVLB 17 TEXT('Save label ') A O7RS04 52 TEXT('Reserved ') A***************************************************************** A* ..format OBJL0600: usage information A***************************************************************** A O7DTLU 8 TEXT('Date, last used ') A O7DTRE 8 TEXT('Date, reset ') A O7USCT 9B 0 TEXT('Usage count ') A O7USUP 1 TEXT('Usage updated ') A O7RS05 23 TEXT('Reserved ') A***************************************************************** A* ..format OBJL0700: size information A***************************************************************** A O7OSIZ 9B 0 TEXT('Object size ') A O7OSMU 9B 0 TEXT('Object size multiplier ')
Real Life APIs
Figure 5 Program run times
Figure 5: Program Run Times Program Type CPU Time Percent RPG, Outfile, with QSYS 930 100.0 RPG, APIs, with QSYS 918 98.7 PL/I, APIs, with QSYS 725 77.9 RPG, APIs, without QSYS 458 PL/I, APIs, without QSYS 384 RPG, APIs, without QSYS 466 Multiply all sizes
Real Life APIs
Figure 6 RPG program ##006RG
***************************************************************** * LIST LIBRARY PROGRAM ***************************************************************** FLIB002WFO E DISK A I 'DLTUSRSPC QTEMP/LST1'C USPC1 I 'DLTUSRSPC QTEMP/LST2'C USPC2 IOL0700 E DS##0018PF IQRTVUS E DS##0016PF IQCRTUS E DS##0015PF IQLOBJ E DS##0017PF I DS I***************************************************************** I* PARMS TO QUSRTVUS PGM I* I* RSSTRP - START POSITION I* RSLEND - LENGTH OF DATA I***************************************************************** I B 1 40RSSTRP I B 5 80RSLEND C SETON LR C* C***************************************************************** C* GET LIST OF LIBRARIES C***************************************************************** C* C MOVEL'LST1' CSSPNM 10 *SPACE NAME C MOVEL'QTEMP' CSSPLB 10 *SPACE LIBRARY C MOVELUSPC1 DLTSPC 20 *DLTUSRSPC C* C EXSR CRTSPC C EXSR INTLST C* C MOVELCSQLSN LOQLSN *SPACE/LIB C MOVEL'OBJL0700'LOFMTN *LIST FORMAT C MOVEL'*ALL' LOOBLI *OBJ/LIB C MOVEL*BLANKS W10 C MOVEL'QSYS' W10 10 *OBJ LIB C MOVE W10 LOOBLI *OBJ/LIB C MOVEL'*LIB' LOOTYP *OBJ TYPE C* C EXSR GETLST C* C***************************************************************** C* RETRIEVE EACH LIBRARY ENTRY FROM LIST C***************************************************************** C* C 1 DO RSCTLS N 50 C CALL 'QUSRTVUS' C PARM LOQLSN C PARM RSSTRP C PARM RSLEND C PARM OL0700 C* C CLEARWFREC *INIT WORKFILE C* C MOVELO7ONAM WFLIB *LIBRARY C MOVELO7TEXT WFTEXT *LIB TEXT C O7OSIZ MULT O7OSMU WFLBSZ *LIB SIZE C Z-ADDWFLBSZ WFTSIZ *TOTAL LIB SIZE C* C WFLIB IFNE 'QSYS' C EXSR DSPLIB C END C* C ADD RSSZEN RSSTRP C END C***************************************************************** C* FOR EACH LIBRARY, GET OBJECTS IN THAT LIBRARY C***************************************************************** C* C DSPLIB BEGSR C* *************** C* C***************************************************************** C* SAVE LIST API VALUES C***************************************************************** C* C *LIKE DEFN RSCTLS SVCTLS C *LIKE DEFN RSSZEN SVSZEN C *LIKE DEFN RSSTRP SVSTRP C *LIKE DEFN RSLEND SVLEND C *LIKE DEFN LOQLSN SVQLSN C* C Z-ADDRSCTLS SVCTLS C Z-ADDRSSZEN SVSZEN C Z-ADDRSSTRP SVSTRP C Z-ADDRSLEND SVLEND C MOVELLOQLSN SVQLSN C* C***************************************************************** C* GET LIST OF OBJECTS IN A LIBRARY C***************************************************************** C* C MOVEL'LST2' CSSPNM *SPACE NAME C MOVEL'QTEMP' CSSPLB *SPACE LIBRARY C MOVELUSPC2 DLTSPC *DLTUSRSPC C* C EXSR CRTSPC C EXSR INTLST C* C MOVELCSQLSN LOQLSN *SPACE/LIB C MOVEL'OBJL0700'LOFMTN *LIST FORMAT C MOVEL'*ALL' LOOBLI *OBJ/LIB C MOVEL*BLANKS W10 C MOVELO7ONAM W10 *OBJ/LIB C MOVE W10 LOOBLI *OBJ/LIB C MOVEL'*ALL' LOOTYP *OBJ TYPE C* C EXSR GETLST C* C***************************************************************** C* RETRIEVE EACH OBJECT ENTRY FROM LIST C***************************************************************** C* C 1 DO RSCTLS K 50 C CALL 'QUSRTVUS' C PARM LOQLSN C PARM RSSTRP C PARM RSLEND C PARM OL0700 C* C ADD RSSZEN RSSTRP *NEXT START POS C* C***************************************************************** C* CACLULATE OBJECT SIZE, ACCUMULATE TOTALS, SAVE LARGEST OBJ C***************************************************************** C* C*** Z-ADDO7OSIZ OBJSIZ 110 *OBJECT SIZE C* C*** O7OSMU IFGT 1 C O7OSIZ MULT O7OSMU OBJSIZ 110 *OBJECT SIZE C*** END C* C ADD OBJSIZ WFOBSZ *TOT OBJS SIZE C* C OBJSIZ IFGT WFLRGS *LARGEST SIZE C Z-ADDOBJSIZ WFLRGS *LARGEST SIZE C MOVELO7ONAM WFLRGN *NAME C MOVELO7OTYP WFLRGT *OBJ TYPE C MOVELO7EXAT WFLRGA *OBJ ATTR C END C END C* C ADD WFOBSZ WFTSIZ *TOT LIB SIZE C Z-ADDRSCTLS WFOBJS *OBJ COUNT C* C WRITEWFREC C* C***************************************************************** C* RESTORE LIST API VALUES C***************************************************************** C* C Z-ADDSVCTLS RSCTLS C Z-ADDSVSZEN RSSZEN C Z-ADDSVSTRP RSSTRP C Z-ADDSVLEND RSLEND C MOVELSVQLSN LOQLSN C ENDSR C***************************************************************** C* CREATE A NEW USER SPACE C***************************************************************** C* C CRTSPC BEGSR C* *************** C* C***************************************************************** C* ..DELETE EXISTING USER SPACE C***************************************************************** C* C MOVELDLTSPC PMCMD 20 C Z-ADD20 PMLEN 155 C* C CALL 'QCMDEXC' 99 *99 - ERROR C PARM PMCMD C PARM PMLEN C* C***************************************************************** C* ..CREATE NEW USER SPACE C***************************************************************** C* C MOVEL*BLANKS CSQLSN C MOVELCSSPNM CSQLSN *SPACE NAME C MOVE CSSPLB CSQLSN *SPACE LIB C MOVEL'USPACE' CSEXTA *EXTENDED ATTR C Z-ADD100000 CSINSZ *INIT SIZE C MOVEL*BLANKS CSINVL *INIT VALUE C MOVEL'*ALL' CSPAUT *PUB AUTHORITY C MOVEL*BLANKS CSTEXT *TEXT DESC C* C CALL 'QUSCRTUS' C PARM CSQLSN C PARM CSEXTA C PARM CSINSZ C PARM CSINVL C PARM CSPAUT C PARM CSTEXT C ENDSR C***************************************************************** C* GET LIST, LIST HEADER C***************************************************************** C* C GETLST BEGSR C* *************** C* C CALL 'QUSLOBJ' C PARM LOQLSN C PARM LOFMTN C PARM LOOBLI C PARM LOOTYP C* C***************************************************************** C* GET OFFSET, SIZE OF EACH ENTRY, NUMBER OF ENTRIES C***************************************************************** C* C Z-ADD1 RSSTRP *START POSN C Z-ADD140 RSLEND *LENGTH OF DATA C* C CALL 'QUSRTVUS' C PARM LOQLSN C PARM RSSTRP C PARM RSLEND C PARM QRTVUS C* C RSOFLS ADD 1 RSSTRP *START POSN C Z-ADDRSSZEN RSLEND *LENGTH OF DATA C ENDSR C***************************************************************** C* INITIALIZE 'GET LIST' PARM VALUES C***************************************************************** C* C INTLST BEGSR C* *************** C* C MOVEL*BLANKS LOQLSN C MOVEL*BLANKS LOFMTN C MOVEL*BLANKS LOOBLI C MOVEL*BLANKS LOOTYP C ENDSR
Real Life APIs
Figure 7 CL program ##0004CL (revised LIB002CL)
##0004CL: + PGM PARM(&SORT) DCL VAR(&SORT) TYPE(*CHAR) LEN(5) CLRPFM FILE(LIB002WF) CALL PGM(##0006RG) OVRPRTF FILE(QPDSPSTS) HOLD(*YES) WRKSYSSTS OUTPUT(*PRINT) CRTPF FILE(QTEMP/SYSSTS) RCDLEN(132) CPYSPLF FILE(QPDSPSTS) TOFILE(QTEMP/SYSSTS) DLTOVR FILE(QPDSPSTS) DLTSPLF FILE(QPDSPSTS) IF COND(&SORT *EQ '*SIZE') THEN(DO) OVRDBF FILE(LIB002WF) SHARE(*YES) OPNQRYF FILE((LIB002WF)) QRYSLT(*ALL) KEYFLD((WFTSIZ + *DESCEND) (WFLIB *ASCEND)) ENDDO CALL PGM(LIB002RGB) IF COND(&SORT *EQ '*SIZE') THEN(DO) CLOF OPNID(LIB002WF) DLTOVR FILE(LIB002WF) ENDDO DLTF FILE(QTEMP/SYSSTS) CLRPFM FILE(LIB002WF) ENDPGM
Real Life APIs
Figure 8 Revised program LIB002RG (LIB002RGB)
FLIB002WFIF E K DISK FSYSSTS IF F 132 DISK FLIB002P1O E 99 PRINTER * ISYSSTS NS I 96 1020STGMB * C Z-ADD*ZERO AUXSTG C Z-ADD*ZERO STGUSE C Z-ADD*ZERO PCTUSE C WRITEHEADER * C READ LIB002WF 90 B001 C *IN90 DOWEQ'0' C MOVELWFTEXT TEXT40 B002 C *IN99 IFEQ '1' C WRITEHEADER C MOVE '0' *IN99 E002 C END C WRITEDETAIL C ADD WFTSIZ STGUSE C READ LIB002WF 90 E001 C END * C 3 CHAINSYSSTS 90 C STGMB MULT 1000000 AUXSTG C STGUSE MULT 100 TEMP 150 C TEMP DIV AUXSTG PCTUSE C WRITETOTAL * C MOVE '1' *INLR
Real Life APIs
Figure 9 Work file LIB002WF
A UNIQUE A R WFREC A WFLIB 10 ALIAS(LIBRARY_NAME) A WFTEXT 50 ALIAS(LIBRARY_TEXT) A WFLBSZ 10P 0 ALIAS(LIBRARY_SIZE) A EDTCDE(1) A WFOBSZ 12P 0 ALIAS(OBJECTS_TOTAL_SIZE) A EDTCDE(1) A WFTSIZ 12P 0 ALIAS(TOTAL_SIZE) A EDTCDE(1) A WFOBJS 9P 0 ALIAS(NUMBER_OF_OBJECTS) A EDTCDE(1) A WFLRGN 10 ALIAS(LARGEST_OBJECT_NAME) A WFLRGT 10 ALIAS(LARGEST_OBJECT_TYPE) A WFLRGA 10 ALIAS(LARGEST_OBJECT_ATTRIBUTE) A WFLRGS 10P 0 ALIAS(LARGEST_OBJECT_SIZE) A EDTCDE(1) A K WFLIB
LATEST COMMENTS
MC Press Online