Blog › ICP guides
Natural developer on retainer: Adabas hold queue lock, Software AG Natural, Natural for Mainframe developer on monthly retainer
October 8, 2026 · ~15 min read
A Natural developer was maintaining an insurance claims processing application running in Software AG Natural 6.3 on IBM z/OS with an Adabas database backend for a regional insurance carrier. The application included a batch program named CLMPROC that ran nightly to process a set of “Pending” insurance claims: reading each pending claim, applying eligibility and coverage calculations, and updating the claim status from “Pending” to either “Approved” or “Review Required”. The program used a FIND statement to retrieve all claims with status “PENDING” from the CLAIMS Adabas file, then used an UPDATE (ISN) statement within the FIND loop to update each claim’s status field. In the Adabas database model, a FIND statement that retrieves records for subsequent update places each retrieved record’s ISN (Internal Sequence Number — Adabas’s record identifier) into the Adabas hold queue: a nucleus-level lock table that grants exclusive use of those ISNs to the session that placed them there. The developer tested the batch program by running it in a test Natural environment against a subset of pending claims; the test ran successfully, updated all test claims, and the batch job completed normally. The developer did not notice that no END TRANSACTION statement was present at the end of the FIND loop. In production, the nightly batch completed all updates and the program reached END-FIND and END-PROGRAM without issuing END TRANSACTION. The Adabas hold queue entries for the three claims that were processed last (the three claims that happened to be fetched and updated immediately before the program ended) remained active in the Adabas hold queue for the remainder of the Natural batch session. When claim entry operators on interactive Natural terminals attempted to access those three claims the following morning, Adabas returned response code 145 — “The ISN is in the Adabas hold queue” — blocking all interactive access to those claim records. Concurrent claim-entry operators blocked with ADABAS response code 145: 3 → 0 after adding END TRANSACTION at the end of the FIND loop processing body.
The root cause was a missing END TRANSACTION statement at the end of the FIND loop. In Adabas’s data model, an UPDATE operation in Natural does not immediately write the modified record to the Adabas data storage area and release the hold queue entry. Instead, Adabas buffers the updated record in its Work area and retains the hold queue entry for that ISN until the Natural program issues END TRANSACTION (which instructs the Adabas nucleus to write all buffered updates to data storage, update the Adabas protection log, and release all hold queue entries for the current transaction) or BACKOUT TRANSACTION (which discards all buffered updates and releases all hold queue entries). This design — where updates are buffered until explicit transaction termination — is fundamental to Adabas’s consistency and recovery model. Every UPDATE (ISN) statement in a Natural FIND loop is a deferred write that places the ISN in the hold queue and buffers the field changes; END TRANSACTION is the “commit” that writes and releases. A FIND loop that issues UPDATE (ISN) on each record without ever issuing END TRANSACTION accumulates hold queue entries for every processed ISN throughout the entire batch run. When the batch program terminates at END-PROGRAM without an explicit END TRANSACTION, the Natural runtime may or may not issue an implicit transaction rollback depending on the Natural session configuration — and in any case, the hold queue entries persist for the lifetime of the Natural session (the batch JCL step), not merely for the lifetime of the program execution, in older Natural/Adabas configurations.
The Adabas hold queue is distinct from conventional row locking as implemented in SQL databases like Oracle or SQL Server. In SQL databases, a row lock is typically released either when the transaction is committed or rolled back (in transaction-level locking) or when the cursor advances past the row (in cursor-level locking with READ COMMITTED isolation). In Adabas, the hold queue is explicitly controlled by the program: UPDATE (ISN) places the ISN in the hold queue; END TRANSACTION or BACKOUT TRANSACTION releases it. There is no automatic hold queue release when a FIND loop reaches its natural end (END-FIND). There is no automatic release when a Natural subprogram (CALLNAT) called from within the FIND loop returns. There is no automatic release when the Natural program returns to its caller via RETURN. Only END TRANSACTION, BACKOUT TRANSACTION, or Natural session termination releases hold queue entries. This means a developer who writes a FIND-UPDATE loop and tests it in a single-user environment will never observe the hold queue contention issue — in single-user testing, there are no concurrent sessions trying to access the same ISNs. The Adabas Online System (AOS) — the Adabas nucleus monitoring and administration interface — is required to diagnose hold queue contention: the AOS session display shows all active Natural sessions, their current hold queue entry count, and the ISNs they hold.
The interaction between Natural subprograms (CALLNAT) and Adabas hold queue scope is a particularly subtle aspect of Natural/Adabas retainer work. Natural programs are organized into a hierarchy of programs and subprograms: a main program calls subroutines via CALLNAT ‘SUBPGM’, passing parameters. Adabas hold queue entries accumulated by a subprogram within a CALLNAT are owned by the Natural session’s transaction scope, not by the subprogram’s call frame. If subprogram SUBCALC issues UPDATE (ISN) on a CLAIMS record, the hold queue entry for that ISN is in the session’s hold queue — it is not released when SUBCALC returns to the calling program. If the calling program does not issue END TRANSACTION after the CALLNAT returns, the hold queue entry persists. Similarly, an ON ERROR handler in the calling program that catches an Adabas error and returns to the calling menu without issuing BACKOUT TRANSACTION leaves all hold queue entries from the current transaction — including those placed by any CALLNAT subroutines that ran before the error — active in the session’s hold queue. A retainer developer auditing Natural/Adabas applications for hold queue bugs must trace the full CALLNAT call chain from every UPDATE (ISN) statement to the nearest enclosing END TRANSACTION or BACKOUT TRANSACTION, confirming that every code path — normal completion, error handler exit, and early RETURN — reaches an END TRANSACTION or BACKOUT TRANSACTION before the session returns to the calling menu or terminates.
Software AG Natural 4GL, the Adabas database, and the hold queue model
Software AG (formerly Softwarehaus Darmstadt AG) developed the Natural programming language in the early 1970s as a high-level 4GL designed to work natively with Adabas (Adaptable DAta BAse System), Software AG’s proprietary inverted-list database for mainframe and midrange systems. Natural is a structured, procedural language organized around programs, subprograms (called via CALLNAT), subroutines (inline or external, called via PERFORM), and maps (screen layout definitions used in interactive online programs). Natural programs are stored in a Natural library (a named collection of Natural programs, subprograms, and maps in the Natural system file FNAT or FUSER) and are cataloged into a compiled object format (the Natural module catalog) using the Natural STOW or CATALOG command. The cataloged object is what actually executes at runtime; the Natural source is stored separately and used for maintenance and recompilation.
Adabas is an inverted-list database that stores data in a format fundamentally different from relational SQL databases. An Adabas file is analogous to a relational table, but Adabas stores only the “compressed” field values for each record in the data storage area, while maintaining separately an inverted list for each searchable field (called a “descriptor”) that maps field values to the ISNs (Internal Sequence Numbers) of all records containing that value. A Natural FIND CLAIMS WITH CLAIM-STATUS = 'PENDING' statement causes Adabas to perform an inverted-list lookup on the CLAIM-STATUS descriptor, retrieving the list of ISNs for all CLAIMS records with CLAIM-STATUS equal to “PENDING”, and then sequentially reading those records into the Natural FIND buffer. Each record that is fetched and marked for update via UPDATE (ISN) has its ISN added to the Adabas hold queue for the current Natural session. The hold queue is maintained in the Adabas nucleus Work (Protection) area in memory. The Adabas ADARUN configuration parameter LQ controls the maximum number of ISNs that can be in the hold queue at any one time across all sessions; if LQ is exceeded, Adabas returns response code 9 (“The hold queue is full”). The ADARUN parameter NH (introduced in Adabas 8) controls the maximum number of ISNs a single user session can hold simultaneously in the hold queue.
Natural supports two operational environments with different transaction models. In Natural for Mainframe (running on z/OS, z/VSE, or BS2000), the transaction model is governed by the Natural ADARUN parameters set in the Natural JCL (for batch) or the Natural logon profile (for CICS or IMS online). In Natural for Linux-Unix-Windows (Natural LUW), the transaction model works similarly but uses the Natural LUW runtime rather than the mainframe Natural nucleus. In both environments, END TRANSACTION commits the current Adabas transaction — it writes all buffered UPDATE changes to the Adabas data storage area, writes a commit record to the Adabas protection log (PLOG) for recovery purposes, and releases all ISNs in the session’s hold queue. BACKOUT TRANSACTION discards all buffered UPDATE changes since the last END TRANSACTION and releases all ISNs in the session’s hold queue. Natural also supports a connection to SQL databases (Oracle, DB2, SQL Server) via the Natural SQL gateway; in that mode, END TRANSACTION issues a SQL COMMIT to the connected SQL database rather than an Adabas end-of-transaction call. A retainer developer working on a Natural application that uses both Adabas (via Natural’s native Adabas interface) and an external SQL database (via the Natural SQL gateway) must confirm that END TRANSACTION correctly commits and releases both the Adabas hold queue entries and the SQL database transaction locks.
Natural version history affects the specifics of hold queue behavior and transaction scope. In Natural 4.x and 5.x, the Natural session’s transaction scope was less strictly enforced: abnormal program termination might leave hold queue entries active until the entire Natural session (CICS task or batch JCL step) ended. In Natural 6.x and later, the Natural ON ERROR handler provides a structured mechanism for catching Adabas errors (including response code 145 from hold queue contention) at the program level and issuing BACKOUT TRANSACTION before returning to the calling menu. Natural 9.x introduced additional Natural Security enhancements and improved Natural for LUW Adabas connectivity. A retainer developer migrating a Natural 4.x or 5.x batch application to Natural 6.x or 9.x should audit all batch programs that use FIND-UPDATE loops to confirm that END TRANSACTION is present at the end of each processing unit — not just at the end of the outermost program, but within the loop body if the loop processes many records (to avoid accumulating thousands of hold queue entries in a single transaction and risking an ADARUN LQ exhaustion).
Typical Natural developer retainer work and what it looks like in a work log
FIND-UPDATE loop without END TRANSACTION at end of processing is the canonical Natural/Adabas invisible production hold queue lock. The pattern is consistent: a Natural batch program uses FIND file WITH condition to retrieve a set of records, issues UPDATE (ISN) within the FIND loop for each record, and reaches END-FIND and END-PROGRAM without ever calling END TRANSACTION. The developer tests the batch program in a test environment by running it as the only user of the CLAIMS file; no concurrent access contention occurs during testing; the program runs correctly and updates all test records. In production, the batch program runs overnight; by morning, the hold queue entries for the last-processed ISNs remain active (the session is still alive until the batch JCL job step terminates). Claim-entry operators starting their day encounter ADABAS response code 145 on three claim records. Fix: END TRANSACTION added after the last UPDATE (ISN) within the FIND loop body (or at the end of each logical batch unit within the loop for large record sets). Concurrent blocked operators: 3 → 0. Work log: “CLMPROC FIND CLAIMS WITH CLAIM-STATUS = ‘PENDING’; UPDATE (ISN) for each claim in loop; END-FIND + END-PROGRAM without END TRANSACTION; 3 CLAIMS ISNs in Adabas hold queue for duration of Natural batch session; 3 claim-entry operators blocked with ADABAS response code 145; fix: END TRANSACTION added after UPDATE (ISN) in FIND loop body; ADABAS hold queue entries released; blocked operators: 3 → 0; 1.5h.”
CALLNAT subroutine ON ERROR handler without BACKOUT TRANSACTION is the second most common Natural/Adabas retainer pattern. A Natural program calls a subprogram via CALLNAT ‘SUBCALC’ to perform part of the claims processing work; SUBCALC issues UPDATE (ISN) on one or more CLAIMS records within the session’s transaction scope. The calling program has an ON ERROR handler that catches Adabas errors (including response code 145, response code 3 for invalid ISN, and others) and returns control to the menu program without issuing BACKOUT TRANSACTION. The hold queue entries accumulated by SUBCALC’s UPDATE (ISN) calls remain active in the session’s hold queue after the ON ERROR handler returns. The next time the operator attempts to process one of those claims (or any time another operator session accesses the same ISN), Adabas returns response code 145. Work log: “CLMMAIN ON ERROR: ADABAS response code 3 (ISN not found) during CALLNAT ‘SUBCALC’ UPDATE (ISN) for claim ISN 00012847; ON ERROR handler logged error code and returned to menu without BACKOUT TRANSACTION; 2 CLAIMS ISNs from prior UPDATE (ISN) calls in SUBCALC held in Adabas hold queue; operators blocked with response code 145 on those 2 claims; fix: BACKOUT TRANSACTION added in ON ERROR handler before RETURN; 2 claims released; 2 concurrent blocks → 0; 2h.”
Adabas ADARUN LQ hold queue exhaustion from large FIND loop without mid-loop END TRANSACTION is the third common Natural/Adabas retainer pattern in applications that process large record sets. A Natural batch program uses a FIND loop to process thousands of records without issuing END TRANSACTION within the loop. As the loop progresses, each UPDATE (ISN) adds an ISN to the Adabas hold queue. When the total number of ISNs in the hold queue across all sessions reaches the ADARUN LQ (length of hold queue) parameter value, Adabas returns response code 9 (“The hold queue is full”) to the next UPDATE (ISN) attempt — not only from the batch program that is accumulating the entries, but from any session that attempts any UPDATE (ISN) once LQ is exhausted. The entire Adabas nucleus is effectively unable to process any update until existing hold queue entries are released. The fix has two parts: add END TRANSACTION within the FIND loop at a regular interval (e.g., every 100 or 500 records) to commit and release hold queue entries as the loop progresses; and increase the ADARUN LQ parameter to accommodate the maximum expected hold queue size for the batch workload. Work log: “INVPROC FIND INVENTORY loop processing 15,000 records; UPDATE (ISN) for each record without mid-loop END TRANSACTION; ADARUN LQ = 5,000; at record 5,001: ADABAS response code 9 (LQ full); all Adabas UPDATE operations system-wide blocked; ADARUN LQ increased to 20,000 (nucleus reload required); END TRANSACTION added every 500 records within FIND loop; maximum concurrent hold queue entries: 500; response code 9 recurrence: 0; 3h.”
Track Natural developer retainer hours without the status emails
When a 1.5-hour investigation traces 3 claim-entry operators blocked with ADABAS response code 145 to a missing END TRANSACTION at the end of a FIND-UPDATE loop — Adabas holds each updated ISN in the nucleus hold queue until END TRANSACTION releases it; reaching END-FIND and END-PROGRAM without END TRANSACTION leaves all hold queue entries active for the Natural session lifetime — the work log must name the program, the FIND statement, the UPDATE pattern, the missing END TRANSACTION, the Adabas hold queue entry count, and the blocked-operator count before and after. HourTab gives your Natural retainer client a public dashboard URL they can bookmark: hours used, hours remaining, and a work log naming the END TRANSACTION fix. No client login. No status emails. CSV in, URL out.
See HourTab pricing →How HourTab tracks Natural developer retainer hours
Natural/Adabas FIND-UPDATE without END TRANSACTION hold queue bugs are invisible by the same mechanism that makes them hard to reproduce in development: the Natural program runs correctly; all UPDATE (ISN) statements succeed; END-FIND and END-PROGRAM execute without error; the batch job step completes with return code 0; the Natural batch JCL sysout shows no Adabas error messages. The updates are buffered in the Adabas Work area and are committed to data storage when the batch job step terminates (Adabas issues an implicit END TRANSACTION on session end). The only evidence of the problem is in the following morning’s interactive claims-entry session: three operators open three specific claim records and receive “ADABAS response code 145 — ISN in hold queue” with no indication of which session holds the hold queue entries or why. Diagnosing the problem requires accessing the Adabas Online System (AOS) or running the ADAREP utility to display the Adabas hold queue table: the AOS session monitor shows all active Natural sessions, their jobnames, and the count of ISNs each session holds in the hold queue. Correlating the session holding the three CLAIMS ISNs to the overnight CLMPROC batch job step (which may still be alive in a long-running JCL job) requires cross-referencing the AOS session identifiers with the z/OS job log.
The work log must name the mechanism to be auditable: which Natural program (CLMPROC), the FIND statement (FIND CLAIMS WITH CLAIM-STATUS = ‘PENDING’), the UPDATE pattern (UPDATE (ISN) within FIND loop), the missing END TRANSACTION (not present at end of FIND loop or at end of program), the Adabas hold queue entries held (3 CLAIMS ISNs), the concurrent blocked-operator count before and after fix (3 → 0), the fix (END TRANSACTION added after each UPDATE (ISN) within the FIND loop body, or at the end of the loop for small record sets), and the verification (batch program re-run in test environment; AOS hold queue display shows 0 entries after loop completion; production run confirmed 0 ADABAS response code 145 errors the following morning). A log entry that says “fixed lock issue in claims batch, 1.5h” is not auditable. A log entry that names CLMPROC, the FIND-UPDATE loop, the missing END TRANSACTION, the 3 CLAIMS hold queue entries, and the END-TRANSACTION-after-UPDATE fix is auditable and defensible to the regional insurance carrier client. HourTab gives Natural developers a public retainer-hours URL they send to clients — regional insurers, banks, government agencies, utilities, and healthcare organizations that built Natural/Adabas applications on IBM mainframes in the 1980s, 1990s, and 2000s for claims processing, policy management, account ledger maintenance, and citizen record management, maintained today by the original Natural developer or a successor retainer consultant.
Comparative context: Natural/Adabas FIND-UPDATE without END TRANSACTION hold queue bugs are structurally similar to cooperative locking patterns in other legacy environments where the platform gives the program explicit control over when locks are released. RPGLE retainers cover the free-format RPG EVAL-CORR field mismatch pattern on IBM i — a different class of invisible production bug where schema rename causes silent data loss rather than lock hold, but both environments share the IBM i/mainframe maintenance context where a single retainer developer maintains applications across a long-lived enterprise platform. Pick/MultiValue retainers cover the READU lock hold past CONTINUE pattern in Pick BASIC where an exclusive item-level lock acquired by READU is held when CONTINUE bypasses the RELEASE statement, producing a hold pattern structurally analogous to Adabas hold queue entries held past the logical processing boundary. DataFlex retainers cover the FIND implicit record lock not released in a conditional skip branch — the same class of “lock acquired on record open, not released on the non-update exit path” pattern that appears in Natural as “hold queue entry acquired on UPDATE, not released when END TRANSACTION is omitted.”
FAQ: Natural developer retainers
What does a Natural developer on retainer typically do?
A Natural developer on monthly retainer covers Adabas hold queue lock-hold audits (reviewing every FIND-UPDATE loop to confirm that END TRANSACTION is called on every completion path); ADABAS response code 145 diagnosis via the Adabas Online System (AOS) hold queue display; Natural subprogram (CALLNAT) ON ERROR handler audits to confirm BACKOUT TRANSACTION is present on all error exit paths; Natural application migration from Natural 4.x/5.x to Natural 6.x/9.x; Natural for Mainframe batch job tuning on z/OS (ADARUN parameter optimization for LQ and NH, Natural batch JCL parameter settings); Natural for Linux-Unix-Windows (LUW) application support; Natural Security library and program profile management; and Natural connection to SQL backends (Oracle, DB2 LUW, SQL Server) via Natural SQL gateway configuration.
What Adabas hold queue lock work is most commonly underlogged?
FIND loops that include UPDATE statements on the retrieved records, where the Natural program reaches END-FIND and END-PROGRAM without issuing END TRANSACTION, are the most systematically underlogged Natural retainer work. Every UPDATE (ISN) adds the ISN to the Adabas hold queue; the hold queue entry is released only by END TRANSACTION or BACKOUT TRANSACTION — not by END-FIND, not by CALLNAT return, not by END-PROGRAM. The developer who tests the batch in a single-user environment never observes hold queue contention; in production, the batch session remains alive until job step termination, and concurrent interactive operators receive ADABAS response code 145 on the held ISNs with no explanation of cause.
What are typical Natural developer retainer rates?
Entry-level Natural developers with experience in Natural program structure, FIND/READ/UPDATE statements, Adabas DDM navigation, and Natural report generation typically bill at $70 to $120 per hour. Mid-level Natural programmers with experience in Adabas hold queue locking (ADABAS response code 145 diagnosis, END TRANSACTION / BACKOUT TRANSACTION scope analysis), Natural CALLNAT subprogram design, Natural Security, and Natural batch JCL for z/OS typically bill at $100 to $180 per hour. Senior Natural developers with deep knowledge of Adabas nucleus configuration (ADARUN LQ, NH parameters), Natural for Mainframe migration, Natural SQL gateway configuration, and production incident forensics on mission-critical Natural/Adabas mainframe applications typically bill at $150 to $280 per hour. Monthly retainer ranges: $2,000 to $3,500 per month for advisory engagements covering hold queue audits and batch tuning (12 to 20 hours per month); $3,000 to $6,500 per month for active maintenance of mission-critical Natural/Adabas mainframe applications.
What should a Natural developer retainer agreement include?
A Natural developer retainer agreement should specify: Natural version (Natural 4.x, 5.x, 6.3, 8.x, 9.x); Adabas version (Adabas 7.x, 8.x — Adabas 8 introduced per-user NH hold queue limit and the ACF security module); platform (Natural for Mainframe on z/OS, Natural for LUW, or both); whether the retainer developer has access to the Natural SYSPROG utility and the Natural module catalog for recompiling changed programs; whether the retainer covers Adabas nucleus parameter optimization (ADARUN LQ, NH, TLSCMD for transaction timeout); whether the retainer includes Natural Security library and program profile management; whether the retainer covers Natural connection to SQL backends (Oracle, DB2, SQL Server via Natural SQL gateway); and whether the retainer includes Adabas Online System (AOS) access for hold queue monitoring and Adabas ADAREP utility access for hold queue forensics.
How should Natural developer retainer hours be logged?
Log each Natural retainer session with the program name, the FIND/UPDATE statement pattern, and the hold queue outcome. For FIND-UPDATE without END TRANSACTION: program name (CLMPROC), the FIND statement (FIND CLAIMS WITH CLAIM-STATUS = ‘PENDING’), the UPDATE pattern (UPDATE (ISN) within FIND loop), the path that omitted END TRANSACTION (END-FIND + END-PROGRAM without END TRANSACTION), hold queue entries held (3 CLAIMS ISNs), concurrent blocked operators with ADABAS response code 145 before and after fix (3 → 0), fix (END TRANSACTION added after UPDATE within FIND loop), hours (1.5h). For CALLNAT ON ERROR without BACKOUT TRANSACTION: calling program, CALLNAT target, error condition, hold queue entries from subroutine UPDATE calls, fix (BACKOUT TRANSACTION in ON ERROR handler), hours. For ADARUN LQ exhaustion: ADABAS response code 9, LQ parameter value, increased LQ, END TRANSACTION added at mid-loop interval, hours.