Newsletters Subscriptions Media Kit About Us Contact Search Home

Stuff
OS/400 Edition
Volume 2, Number 9 -- April 24, 2003

Using Pointer-Based Variables in RPG IV


by Raymond Everhart

[The code for this article is available for download.]

Using pointers in RPG IV doesn't have to be complicated. In this article we will explore the use of pointer-based variables in the context of a database trigger program. The program will demonstrate two techniques for using pointer-based variables. Before proceeding with this article, you may want a review of the basics of pointers. If so, check out article "Back to Basics: Pointers in RPG," by Kevin Vandever.

A Trigger Example

When a trigger program is called, two parameters are passed to the trigger program. The first parameter is a buffer that contains all of the information collected when the trigger was fired. The second parameter indicates the length of the data stored in the trigger buffer (the first parameter). Before OS/400 V5R1, the trigger buffer was commonly described using a data structure. The first 96 bytes of the trigger buffer were always subdivided the same way. The layout of the data following the 96th byte was determined by the length of the file's record format and by the number of fields contained in the record. If your file was 100 bytes long, the "before" image of the data would start in position 97 and end at position 196. If your file had 10 fields, the null map for the "before" image would begin at position 197 and end at 206. The "after" image of the data would start in position 207 and end at position 306. The null map for the "after" image would begin at position 307 and end at 316. Calculating and coding these starting and ending positions takes me back to coding in RPG II. It always took a few passes to get the data defined just right. When IBM released OS/400 V5R1, there were significant changes to DB2 and to the parameters passed when a trigger is fired. Numeric values in the fixed portion of the data were changed from the binary data type to the integer data type. More important, IBM warned that hard-coding the starting positions of the before and after images of the data was not recommended, because these positions could vary because of the additional support in DB2 for binary large objects, or BLOBs. The change from binary to integer data types effectively "breaks" trigger programs compiled under OS/400 V4R5 when the operating system is upgraded to V5R1.

Buffer Description

Figure 1 shows the fixed portion of the trigger buffer. These fields are crucial in determining the relative position of the "before" and "after" images of the data.

Figure 1

Figure 1: Fields in the fixed portion of trigger buffer determine positions of "before" and "after" images of data

Here is a brief description of each field:

FileName File Name The name of the file that generated the call to the trigger program.
LibName Library Name The name of the library that generated the call to the trigger program.
MbrName Member Name The name of the file member that generated the call to the trigger program.
TrgEvent Trigger Event This code indicates what event fired the trigger. If TrgEvent = 1, then the record was inserted (added) into the file. If TrgEvent = 2, then the record was deleted. If TrgEvent = 3, then the record was updated.
TrgTime Trigger Time This code indicates whether the trigger was fired before or after the I/O actually occurred. If TrgTime = 1, then the trigger was fired after the file I/O. If TrgTime = 2, then the trigger was fired before the file I/O.
CmtLevel Commit Lock Level This code indicates the level of commit lock level: '0'=*None, '1'=*Chg, '2'=*CS, '3'=*All
Reserved1 Reserved This field is reserved for future use.
CCSID CCSID This is the CCSID code of the data.
Reserved2 Reserved This field is reserved for future use.
OrgRecOffset Original Record Offset This field is used to calculate the starting position of the original record.
OrgRecLength Original Record Length This field contains the length of the original record.
OrgRecNulOff Original Record Null Offset This field is used to calculate the starting position of the original records null map.
OrgRecNulLen Original Record Null Length This field contains the length of the original records null map.
NewRecOffset New Record Offset This field is used to calculate the starting position of the new record.
NewRecLength New Record Length This field contains the length of the new record.
NewRecNulOff New Record Null Offset This field is used to calculate the starting position of the new records null map.
NewRecNulLen New Record Null Length This field contains the length of the new records null map.
Reserved3 Reserved This field is reserved for future use.

One thing that you should notice is that the data structure in Figure 1 does not define any fields past the fixed portion of the data. The entire parameter is stored in memory; the TriggerDS data structure defines only a portion of the data. The rest of the data will be accessed using pointer-based variables.

Calculating the Position of the "Before" and "After" Images

The starting position of the original record data is stored in the OrgRecOffset field. In order to set a pointer to the proper "address" in memory, we need to first determine the starting position of the data structure and then add the value off the offset. The code looks like this:

     * Define Pointer fields

0001 D AfterPtr        S               * 
0002 D BeforePtr       S               *
0003 D StartBuff       S               *

     * Set pointers for before and after record image

0004 C           Eval      StartBuff = %Addr(TriggerDS)
0005 C           Eval      AfterPtr = StartBuff + NewRecOffset
0006 C           Eval      BeforePtr = StartBuff + OrgRecOffset

Line 4 sets the StartBuff pointer variable to the address occupied by the TriggerDS data structure. Line 5 sets the AfterPtr pointer variable to the address occupied by the first byte of the new record. Line 6 sets the BeforePtr pointer variable to the address occupied by the first byte of the original record.

Externally Described Data Structures

Now that we have established where the records start in memory, we can begin to access the data. Using an external data structure is the easiest way to ensure that the data definition matches the data. Just be sure that when you compile the program, your program uses the same file that you intend to install the trigger program onto. The code below defines an external data structure (line 1), adds a prefix (line 2) to each field, and then "overlays" the data structure at the memory address specified by the pointer variable, specified by the Based keyword (line 3).

0001 D AfterDS       E DS                  ExtName(MyFile)
0002 D                                     Prefix(A_)
0003 D                                     Based(AfterPtr)

0004 D BeforeDS      E DS                  ExtName(MyFile)
0005 D                                     Prefix(B_)
0006 D                                     Based(BeforePtr)

Take a Moment to Let It Sink In

In just six lines of code we have mapped a "before" image and an "after" image of the record as it is passed from the database trigger. It doesn't matter if the relative position of the data in the buffer changes; the data structures will be correctly positioned. If the file layout changes, simply recompile the trigger program and it will work. The source code for a functioning example can be downloaded here. What you do with the data is up to you. You can create a log file of changes, an export file for interfacing to other applications, or add referential integrity checking. The possibilities are endless.


Raymond Everhart is an independent programmer/consultant in the Dallas/Fort Worth area and has 17 years of experience with IBM midrange servers. E-mail: reverhart@raecodesign.com.


This article has been corrected since its was first published. The number of bytes referred to in the sentences that read "The first 95 bytes of the trigger buffer were always subdivided the same way. The layout of the data following the 95th byte was determined by the length of the file's record format and by the number of fields contained in the record" has been changed to 96 bytes. [Correction made 4/24/03.]


Sponsored By
WORKSRIGHT SOFTWARE

600 Billion

That's how much a recent independent study estimated U.S. businesses spend on dirty data. How much of that 600 billion is spent by your company? Cleanse you dirty ZIP Codes and mailing addresses with our software and save big bucks.

WorksRight Software, Inc.
Phone: 601-856-8337
E-mail: software@worksright.com
Web site: www.worksright.com


THIS ISSUE
SPONSORED BY:

T.L. Ashford
East Coast Computer
WorksRight Software
Profound Logic Software


BACK ISSUES

TABLE OF
CONTENTS
JAXB takes XML to Java

Scribble on SQL's Scratchpad

Using Pointer-Based Variables in RPG IV

Calling Java from RPG: A Refresher


Editors
Shannon O'Donnell
Kevin Vandever

Managing Editor
Shannon Pastore

Contributing Editors:
Howard Arner
Raymond Everhart
Joe Hertvik
Ted Holt
David Morris

Publisher and
Advertising Director:

Jenny Thomas

Advertising Sales Representative
Kim Reed

Contact the Editors
Do you have a gripe, inside dope or an opinion?
Email the editors:
editors@itjungle.com


Copyright © 1996-2008 Guild Companies, Inc. All Rights Reserved.