file reads behaviour

25 Views


A very real behavior in IBM i ILE RPG where activation groups and Open Data Paths (ODPs) affect how file reads behave across programs.


๐ŸŽฏ Scenario Summary

  • Two programs: PGM1 and PGM2

  • Both are compiled with the same activation group (e.g., 'SALEGROUP')

  • Both use the same file, say SALESF

  • PGM1 does SETLL + READ on SALESF

  • Then PGM2 is called and also does READ on SALESF, without SETLL


๐Ÿง  What Happens

1. File sharing occurs via the same activation group

Because PGM1 and PGM2 share the same activation group, IBM i reuses the Open Data Path (ODP) for SALESF. That means:

  • The file cursor/position is shared

  • The file stays open across program calls


2. PGM2 continues reading where PGM1 left off

So in your case:

  • PGM1 does:

    setll key SALESF;
    read SALESF;    // reads record #1
    read SALESF;    // reads record #2
    
  • Then PGM2 does:

    read SALESF;    // continues from record #3
    

Because PGM2 never did SETLL, it just continues reading from wherever PGM1 left off.


โœ… Behavior: This is normal and expected in shared activation groups

Shared Component Behavior
File ODP Shared
File cursor Shared (position retained)
File state Shared (open, locked, etc.)
Buffer, vars Not shared unless explicitly passed

๐Ÿ›‘ Potential Pitfalls

Issue Risk
Forgetting to SETLL in PGM2 Unexpected record or skipped data
Assuming files are "fresh" per program Leads to bugs in batch or API jobs
Files left open Can block others or cause locking issues

โœ… Best Practices

Practice Why
Always SETLL or CHAIN before READ Ensures correct positioning
Use CLOSE if you want a clean state Frees ODP and file cursor
Use ACTGRP(*NEW) if you want isolation Avoids shared file behavior
Document shared file behavior Helps in modular/multi-program flows

๐Ÿ’ก Bonus Tip: Detecting ODP Reuse

You can trace ODP usage with a debug tool or use debug logging to monitor how many times a file is opened and where it starts reading.


Below is a working demo of two RPGLE programs (PGM1 and PGM2) using the same activation group and sharing a physical file (SALESF). The goal is to demonstrate how PGM2 reads from where PGM1 left off.


๐Ÿงพ Step 1: Physical File — SALESF

Create this DDS source:

A          R SALESREC
A            SALEID     5A
A            AMOUNT     9P 2
A          K SALEID

Compile it with:

CRTPF FILE(MYLIB/SALESF) SRCFILE(MYLIB/QDDSSRC)

And insert some sample data (via SQL or DFU):

INSERT INTO SALESF VALUES ('S0001', 100.00);
INSERT INTO SALESF VALUES ('S0002', 200.00);
INSERT INTO SALESF VALUES ('S0003', 300.00);
INSERT INTO SALESF VALUES ('S0004', 400.00);

๐Ÿงพ Step 2: Program PGM1 — READ with SETLL

ctl-opt actgrp('SALEGROUP') dftactgrp(*no);

dcl-f SALESF keyed usage(*input);

dcl-s saleid char(5);
dcl-s amount packed(9:2);

setll 'S0001' SALESF;
read SALESF;
if not %eof(SALESF);
   saleid = SALEID;
   amount = AMOUNT;
   dsply ('PGM1: ' + saleid + ' - ' + %char(amount));
endif;

read SALESF;
if not %eof(SALESF);
   saleid = SALEID;
   amount = AMOUNT;
   dsply ('PGM1: ' + saleid + ' - ' + %char(amount));
endif;

// Now call PGM2 (reads same file without SETLL)
call 'PGM2';

๐Ÿงพ Step 3: Program PGM2 — READ Without SETLL

ctl-opt actgrp('SALEGROUP') dftactgrp(*no);

dcl-f SALESF keyed usage(*input);

dcl-s saleid char(5);
dcl-s amount packed(9:2);

// No SETLL โ€” continues from where PGM1 left off
read SALESF;
if not %eof(SALESF);
   saleid = SALEID;
   amount = AMOUNT;
   dsply ('PGM2: ' + saleid + ' - ' + %char(amount));
endif;

read SALESF;
if not %eof(SALESF);
   saleid = SALEID;
   amount = AMOUNT;
   dsply ('PGM2: ' + saleid + ' - ' + %char(amount));
endif;

๐Ÿงช Expected Output

PGM1: S0001 - 100.00
PGM1: S0002 - 200.00
PGM2: S0003 - 300.00
PGM2: S0004 - 400.00

Notice how PGM2 picks up exactly where PGM1 left off, because the file ODP and cursor are shared via the same activation group.


โœ… Optional: Isolate Behavior with *NEW

If you change actgrp('SALEGROUP') to actgrp(*NEW) in either program, the file will be reopened, and the cursor will reset — so PGM2 would start from the top again.


 

Post Comments