Partner400 Logo
    Source for Open Access Part 3 Example Code
   

This is a simple Open Access handler program that allows a CSV file to be read using a conventional READ op-code with no need to use IFS APIs or to use utilities to copy the data from the CSV form to a temporary database file. A more sophisticated version able to utilize column headings can be found here but if you are just starting your OA journey we suggest starting with this one.

The article that describes this program can be found here.

On this page you can find the source files for the CSV data file (IFSDATA1) that is used in the example. The main source file for the handler (IFSINPHND1), and the test program from the article (IFSINPTST1).

The /COPY file QRNOPENACC is shipped by IBM as part of the Open Access support. The other files used are part of the CSVR4 routines referenced in the article.

[an error occurred while processing this directive]


DDS for CSV "File" IFSDATA1's layout

	
A R IFSDATAR1
A ZONED5_0 5S 0
A ZONED5_2 5S 2
A PACKED7_2 7P 2
A CHAR80 80A
A DATEUSA L DATFMT(*USA)

Handler Program IFSINPHND1

       // An RPG Open Access handler that supports READing from a CSV file in
// the IFS.

// This handler takes as input a CSV file and parses out the
// individual fields which it then returns to RPG
// This version assumes that the field sequence in the IFS
// file matches that in the file used in the program.
// The handler uses Scott Klement's CSVR4 Service Program to
// perform the parsing of the IFS input records. As part of the process,
// Scott's code strips any quotes from around character strings.

H DftActGrp(*No) Option(*NoDebugIO: *SrcStmt) BndDir('CSV')

// Standard IBM supplied Open Access definitions
/copy qrnopenacc
// Definition of additional handler parameter and constants
/copy ifs_cpy
// RPG Status code values
/copy monstatcds
// Protos for the CSVR4 Service Program procedures
/copy CSV_H

// On V7 and later systems this PR can be removed and so can those for
D IFSINPHND1 Pr ExtPgm('IFSINPHND1')
D info likeds(QrnOpenAccess_T)

// Definition for local subprocedure
D readFile pr like(info.rpgStatus)
D handle like(fileHandle) value

D IFSINPHND1 PI
D info likeds(QrnOpenAccess_T)

// Error status (i.e. RPG error status)
D errStatus s Like(info.rpgStatus)

// Field Names/Values structures
D namesValues ds likeds(QrnNamesValues_T)
D based(pnamesValues)

// Structure to map the "additional information" parameter passed
// by the RPG program. In this case it contains the IFS file name.
// Its pointer is contained within the userArea field in the info struct
D ifs_info ds likeds(ifs_hdlr_info_t)
D based(pIfs_info)


// Used by the IFS routines to determine which IFS file is to be used
// Maps to storage dynamically allocated when opening the file.
// Pointer is stored in the rpgStatus field in the info structure
D fileHandle s * based(pfileHandle)

/free
// Use the pointers in the info area to set up access to the
// the handle for the IFS file (stateInfo)
// and the IFS file name (userArea)
pfileHandle = info.stateInfo;

pIfs_info = info.userArea;

If info.rpgOperation = QrnOperation_READ;
// Set up access to Name/Value information
pnamesValues = info.namesValues;

errStatus = readFile(fileHandle);
If errStatus <> stsNoError;
info.rpgStatus = errStatus;
EndIf;

elseIf info.rpgOperation = QrnOperation_OPEN;
// Specify that we want to use Name/Value information
info.useNamesValues = *On;

// Allocate the storage for the file handle and store the pointer
// in the info area. That way RPG can associate the pointer with
// the specific file and give it back to us on each operation.
pfileHandle = %Alloc(%Size(fileHandle));
info.stateInfo = pfileHandle;

// Ensure that file handle is zero before attempting open()
clear fileHandle;

fileHandle = CSV_open(ifs_info.path); // Open file
if fileHandle = *Null;
info.rpgStatus = errImpOpenClose; // Open failed
EndIf;

elseif info.rpgOperation = QrnOperation_CLOSE;
csv_close(fileHandle);

// free the state information and null out the info pointer
dealloc(n) pfileHandle;
info.stateInfo = *null;

else;
// Any other operation is unsupported so notify RPG
info.rpgStatus = 1299; // general error status
endif;

Return;

/end-free

// Subprocedure ReadFile()
// Reads record from CSV file and sets up the field values in
// the RPG name/value area

P readFile b
D pi Like(errStatus)
D handle Like(fileHandle) value

D tempField s 32740a Varying Inz
D value s 32470a Based(pvalue)
D fieldLen s 10u 0
D i s 5i 0
D reply s Like(info.rpgStatus)
D csvEOF s n
D gotField s n

/free
// Load the next record - returns true if record found
If ( CSV_loadrec (handle) );

info.eof = *Off; // Clear eof flag

// Process all of the requested input fields
For i = 1 to namesValues.num;

// Set up pointer to field buffer area
pvalue = namesValues.field(i).value;
// Attempt to get the field data from the CSV
gotField = CSV_getfld( handle: tempField: %size(tempField));
If ( gotField );
// If we have field data determine the length to use and load
// the data into the buffer.
If ( %Len( tempField ) > namesValues.field(i).valueMaxLenBytes );
namesValues.field(i).valueLenBytes
= namesValues.field(i).valueMaxLenBytes;
Else;
namesValues.field(i).valueLenBytes = %Len(tempField);
EndIf;

%Subst( value: 1: namesValues.field(i).valueLenBytes ) = tempField;
Else;
namesValues.field(i).valueLenBytes = 0;
dsply ('No value found for field '
+ namesValues.field(i).externalName);
EndIf;

// Make sure that numeric fields are not returned to RPG as zero length
If ( ( namesValues.field(i).valueLenBytes = 0 ) And (
( namesValues.field(i).dataType = QrnDatatype_Decimal )
Or ( namesValues.field(i).dataType = QrnDatatype_Integer )
Or ( namesValues.field(i).dataType = QrnDatatype_Unsigned )
Or ( namesValues.field(i).dataType = QrnDatatype_Float ) ) );

// Numeric field with no data - Set value to zero and length to 1
%Subst( value: 1: 1 ) = *Zero;
namesValues.field(i).valueLenBytes = 1;
EndIf;
EndFor;

Else;
info.eof = *On; // Set eof flag - no more records to process
EndIf;

Return reply;

/end-free
P readFile e

Program IFSINPTST1 - Test Program from the Extra Article.

     H dftactgrp(*no) option(*NoDebugIO : *SrcStmt)

FIFSDATA1 IF E Disk Handler('IFSINPHND1' : ifs_info1)
F UsrOpn
FQSYSPRT O F 132 PRINTER

// Copy in definition of the additional IFS data (path)
/copy simplify,ifs_cpy

// Define IFS file name etc. based on the template
D ifs_info1 ds likeds(ifs_hdlr_info_t)

/free
// Set up IFS path name and then open file
ifs_info1.path = '/Partner400/IFS_INP1.csv';
Open IFSDATA1;

Read IFSDATA1;

DoW not %eof(IFSDATA1);
Except showData;
Read IFSDATA1;
EndDo;

*inlr = *On;

/End-Free

OQSYSPRT E ShowData 1
O zoned5_0 10
O zoned5_2 20
O packed7_2 30
O dateUSA 45
O char80 132
     
Return to Home Page  

Want more information?
Got a question or comment about the site?
Please feel free to Contact Us at any time.}