Open data path (ODP)

27 Views


An Open Data Path (ODP) in IBM i is a system-managed structure that represents the path between a program and a database file once the file is opened. It controls how records are read, updated, and positioned — including:

  • File pointer position

  • Record format

  • Access path (keyed/sequential)

  • Locking and sharing info


๐Ÿง  Simple Definition:

The ODP is the "live connection" between your program and the file — it's what IBM i uses to track where you are in the file, how you opened it, and who else is using it.


โœ… Key Responsibilities of ODP

Function Description
Track file position Keeps current location for READ, SETLL, CHAIN, etc.
Maintain access path Manages index used for keyed access (K fields in DDS)
File sharing Shared across programs within the same activation group
Manage open mode Tracks if file is open for input, output, update

๐Ÿงพ Example: ODP Behavior with READ

setll 'C100' CUSTOMERF;
read CUSTOMERF;   // ODP now positioned at next record
read CUSTOMERF;   // Continues from last position

Each READ advances the ODP's cursor.


๐Ÿ” Types of ODP

Type Description
Shared ODP Used by multiple programs in the same activation group
Private ODP Used by one program only (e.g., in *NEW actgrp or DFTACTGRP)
Reused ODP Reused across program calls if file and actgrp are the same

๐Ÿงจ When ODP Causes Issues

Symptom Root Cause
READ returns wrong record ODP already positioned by another program
CHAIN fails after recompilation Format mismatch or shared stale ODP
File already open error File open in shared ODP with different params
Level check errors ODP referencing outdated format

โœ… Best Practices

Recommendation Reason
Always SETLL before READ Resets ODP position
Use *NEW activation group when needed Forces new ODP
Use CLOSE to reset ODP cleanly Especially in reusable jobs/APIs
Avoid sharing files in long-running groups Prevents ODP confusion across program calls

๐Ÿ” Inspecting ODPs (Indirectly)

While IBM i doesn't let you directly "see" ODPs, you can observe their behavior using:

  • Debug (STRDBG) → see file pointer changes

  • Job log and DSPJOB → monitor open file references

  • DSPPGMREF / DSPDBR → trace usage relationships


Let’s walk through a clear example where two programs — using different activation groups — each get their own Open Data Path (ODP) to the same file, leading to different read behavior even though the file and logic are the same.


๐ŸŽฏ Scenario: Two Programs, Same File, Different Activation Groups

Files:

  • File: SALESF

    • Has 4 records: S001, S002, S003, S004


๐Ÿงพ Program A (PGMA) — Uses *NEW Activation Group

ctl-opt actgrp(*new) dftactgrp(*no);

dcl-f SALESF usage(*input) keyed;

read SALESF;
if not %eof(SALESF);
   dsply ('PGMA: ' + SALEID);
endif;

๐Ÿงพ Program B (PGMB) — Also Uses *NEW

ctl-opt actgrp(*new) dftactgrp(*no);

dcl-f SALESF usage(*input) keyed;

read SALESF;
if not %eof(SALESF);
   dsply ('PGMB: ' + SALEID);
endif;

โœ… What Happens:

Each program has:

  • Its own activation group

  • Its own ODP

  • So even though both programs read SALESF, they each start at the top

If you run:

CALL PGMA
CALL PGMB

Output:

PGMA: S001
PGMB: S001

โžก Even though PGMA read record S001, PGMB also starts at S001 because it got a separate ODP when it opened the file.


๐Ÿ” Now, Modify PGMB to Use Same Activation Group:

In PGMB:

ctl-opt actgrp('SALEGROUP');

And also recompile PGMA with the same activation group:

ctl-opt actgrp('SALEGROUP');

Now, run:

CALL PGMA
CALL PGMB

Output:

PGMA: S001
PGMB: S002

โžก PGMB inherits the ODP from PGMA and continues from where PGMA left off!


๐Ÿ” Takeaway: Activation Group Controls ODP Sharing

Activation Group ODP Behavior
Same group Shared ODP
*NEW or *DFTACTGRP Separate ODP
Mixed Can cause conflicts or confusion

๐Ÿ›  Debugging ODP Issues in Service Programs

If your service program is:

  • Using files without CLOSE

  • Called from programs with different actgrps

Then:

  • ODPs can stay open

  • Reads may act unpredictably

  • Files may show already open or level check errors

๐Ÿ”ง Solution:

  • Use *CALLER in service program:

    ctl-opt actgrp(*caller);
    
  • Or explicitly CLOSE files at end of procedure


Let’s build a full working example that shows:

  • A main program (MAINPGM) calls a service program (SRVPGM)

  • Both use a shared file (SALESF)

  • Improper activation group handling causes ODP confusion or even file already open errors

  • Then we'll fix it using *CALLER and CLOSE


๐Ÿงพ Step 1: Physical File — SALESF

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

Populate with:

INSERT INTO SALESF VALUES ('S001', 100.00);
INSERT INTO SALESF VALUES ('S002', 200.00);

๐Ÿงพ Step 2: Service Program Source — SRVREAD

ctl-opt actgrp('SALEGROUP') dftactgrp(*no);  // โ›” bad for shared services

dcl-f SALESF usage(*input) keyed;

dcl-proc ReadNextSale export;
   dcl-s sale char(5);

   read SALESF;
   if not %eof(SALESF);
      sale = SALEID;
      dsply ('SRVPGM: ' + sale);
   else;
      dsply 'SRVPGM: EOF';
   endif;

   // Optional fix: close file to reset ODP
   // close SALESF;
end-proc;

๐Ÿงพ Step 3: Main Program — MAINPGM

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

dcl-pr ReadNextSale extproc(*dclcase);
end-pr;

dcl-f SALESF usage(*input) keyed;

read SALESF;
if not %eof(SALESF);
   dsply ('MAINPGM: ' + SALEID);
endif;

// Now call service program
ReadNextSale();

๐Ÿงจ Problem: ODP Conflict

When you run MAINPGM, it opens SALESF and reads S001.
Then it calls ReadNextSale() from SRVPGM, which tries to open SALESF again — but:

  • ODP is already in use

  • File may be locked or skip to S002

  • You may get:

    RNX1216 โ€” File already open
    RNX1217 โ€” File not found or not loaded
    
  • Or unexpected read behavior (record skipping)


โœ… Fix 1: Use *CALLER in Service Program

Change SRVREAD:

ctl-opt actgrp(*caller);  // โœ… Inherits activation group from MAINPGM

This allows the ODP to be shared safelySALESF is opened once by MAINPGM and reused by SRVPGM.


โœ… Fix 2: Use CLOSE inside service proc

If you want to force a clean read each time ReadNextSale() is called, add:

close SALESF;

But this is less preferred than managing activation groups properly.


๐Ÿ” Lesson Summary

Mistake Result
Service PG in own actgrp File re-opened, ODP conflict
Same file in both programs READ may skip or error
Using *CALLER Shares file, avoids conflicts
Using *NEW in caller Resets everything clean

 

Post Comments