Using Qshell and CL to work with Stream files in the IFS

It turns out that there is no simple way of generating a list of files currently residing in a folder on the IBM i IFS. Simple, in this case, would be a command like DSPLNK OUTPUT(*FILE). An API does exist, but it turns out that the same results can be achieved both quickly and simply if you are willing to spend a bit of time in Qshell.

This post is a simplified reworking of an issue I encountered some time ago, but it’s worth documenting.

The issue is that I have a number of files being sent, via FTP, to a folder in the IFS. I need to be able to copy these files into an import file for subsequent processing and then archive them. The problem, of course, is that I don’t know what the file names will be beforehand.

Here’s a solution:

First create an extract file in QTEMP. You will need this in order to compile the program. If you are going to submit the compile in batch, you will need to create the file in some other library:

crtpf file(QTEMP/EXTRACTP) rcdlen(20)

And then the CL program:

pgm                                                                             
dcl &fromfile *char 50                                                          
dcl &tombr *char 50 value('/qsys.lib/LSCLIB.lib/IMPORTP.file/IMPORTP.mbr')  
dcl &dltfile *char 100                                                          
dcl &cpyfile *char 100                                                          
dclf EXTRACTP                                                                   
                                                                                
/* First, I use QShell to list the files in the Extract folder                */
/* The output of this is redirected to ExtractedFiles.txt.                    */
qsh cmd('ls /home/PAUL/Extract/ > /home/PAUL/ExtractedFiles.txt')     
                                                                                
/* In order to use this information, create the extract file in qtemp and     */
/* copy the ExtractedFiles.txt stream file into it.                           */
/* If the file already exists, the MONMSG clears it.                          */
crtpf file(QTEMP/EXTRACTP) rcdlen(20)                                           
monmsg CPF7302 exec(clrpfm QTEMP/EXTRACTP)                                      
cpyfrmstmf fromstmf('/home/PAUL/ExtractedFiles.txt') +                     
           tombr('/qsys.lib/qtemp.lib/EXTRACTP.file/EXTRACTP.mbr') +            
           mbropt(*REPLACE)                                                     
                                                                              
/* And now I can use QTEMP/EXTRACTP to drive my way through the Extract       */
/* folder                                                                     */
dowhile '1'                                                                     
    rcvf                                                                        
    monmsg msgid(CPF0864) exec(LEAVE)                                           
                                                                                
    /* Copy the next stream file to the IMPORTP physical file                 */
    chgvar &fromfile value('/home/PAUL/Extract/' *tcat &EXTRACTP)          
    cpyfrmstmf fromstmf(&fromfile) tombr(&tombr) mbropt(*add) +                 
               STMFCCSID(819)                                                   
                                                                                
    /* Copy the stream file to the Archive                                    */
    chgvar &cpyfile value('cp /home/PAUL/Extract/' *tcat &EXTRACTP +       
                    *bcat '/home/PAUL/Archive')                            
    qsh cmd(&cpyfile)                                                           
                                                                                
    /* Then remove the stream file from the Extract folder                    */
    chgvar &dltfile value('rm /home/PAUL/Extract/' *tcat &EXTRACTP)        
    qsh cmd(&dltfile)         
                                                   
    enddo                                          
                                                   
/* Clean up and exit                               
qsh cmd('rm /home/PAUL/ExtractedFiles.txt')   
dltf qtemp/EXTRACTP                                
                                                   
endpgm

It should go without saying that some of the names have been changed and that the above program should be treated as a sample only.

Being able to move information between the QShell/IFS and traditional i on Power environments is both useful and (in my experience) increasingly important. Although it does take a bit of thinking about, it isn’t difficult which is why I find that the oft-seen solution of “buy this tool” is both disappointing and (often) overkill.

Adding variables to ad-hoc SQL queries with REXX

It’s incredible how easily I can be distracted. All I needed was a quick and dirty way of capturing the input into an interface and now I’m writing a blog post.

Everything starts with an issue and, in this case, the issue is with an interface not behaving as expected in production even though everything works as expected in the test environment. My suspicion is that the incoming data is not correctly formatted, causing transactions to not meet the selection criteria. But to confirm this, I need to see exactly what is waiting to be processed when the interface runs.

Since this interface runs after the end of business I want to be able to submit an SQL query to capture the input data into a separate table so that I can see what was processed when I come in tomorrow morning. And, because much of this data is not destined to pass through the interface in question (this is why we have selection criteria) I want to be able to select today’s transactions for whatever the current value of today happens to be.

In a sane world, this would be a simple case of using the current date but in the real world there are still people using eight digit numbers to represent the date. This leads to some unwieldy date calculations in SQL which led me to wondering whether I could capture this in a variable to make things a bit more readable. It turns out I can, but not on the version of the IBM i operating system that I am currently using.

What really caught my eye at the above link however, was this:

but if “ad hoc sql + variables” is the thing you need, you should really try Rexx.

And I thought: “Rexx. That’s something I haven’t used since last century.”

Any excuse to download a couple of manuals is reasonable as far as I’m concerned, so off I went.

And here’s the script (library and table names have been changed):

datenow = DATE('S')
statement = 'insert into MYLIB/INPUTDATA' ,
            'select * from PRODLIB/INPUTDATA where dhdate =' datenow
address 'EXECSQL'
EXECSQL 'SET OPTION COMMIT = *NONE, NAMING = *SYS'
EXECSQL 'delete from MYLIB/INPUTDATA'
EXECSQL statement

The DATE function returns the current date and the 'S' option handily reformats it into an eight digit number (yyyymmdd). The address 'EXECSQL' statement handily points the subsequent commands to the SQL command environment and then it’s just a case of executing the statements I need to execute.

It all works very nicely indeed.