OpenEdge developer on retainer: updAppt.p FIND FIRST Appointment EXCLUSIVE-LOCK not released on Cancelled/NoShow RETURN — OpenEdge ABL record lock held in SmartWindow transaction scope blocks concurrent sessions with ERROR 26 — Progress OpenEdge developer, ABL developer on monthly retainer
OpenEdge 11.7.9 • Windows Server 2016 • ABL updAppt.p • FIND FIRST EXCLUSIVE-LOCK • Cancelled/NoShow RETURN without RELEASE • ADM2 SmartWindow DO TRANSACTION scope • PROMON R&D Record Locking Summary • retainer billing
At Prairie Health Network, clinic coordinators began reporting that appointment records were intermittently unavailable for rescheduling or status review. The error message was consistent: ERROR 26: Record currently being used by another user (EXCLUSIVE-LOCK). The affected records were appointments with statuses of "Cancelled" or "NoShow" — exactly the records that coordinators most often needed to reschedule or reassign. A coordinator at scheduling station 4 would open an appointment to update it, navigate away or switch to another task, and meanwhile two or three other staff members at different stations would find themselves locked out of the same appointment record with no indication of when the lock would clear.
The OpenEdge retainer developer was engaged. The diagnosis confirmed that the locks were caused by the ABL procedure updAppt.p, which acquired an EXCLUSIVE-LOCK on the Appointment record at FIND FIRST time, then returned early on Cancelled and NoShow status checks without releasing the lock. Because updAppt.p was called from within a DO TRANSACTION block in the clinic scheduling SmartWindow, the exclusive lock remained tied to the SmartWindow's transaction scope — meaning it stayed held for as long as the coordinator's SmartWindow was open and their session was active.
OpenEdge ABL record locking model: EXCLUSIVE-LOCK at FIND time
OpenEdge ABL does not acquire record locks lazily. When a FIND FIRST, FIND LAST, or FIND NEXT statement executes with EXCLUSIVE-LOCK, OpenEdge acquires the exclusive lock on that record at the moment the FIND executes — not when the record is modified, not when the transaction commits, but immediately at read time. This is a fundamental characteristic of the OpenEdge 4GL record locking model that differs from SQL-based databases where SELECT ... FOR UPDATE acquires a lock but subsequent validation can still precede any lock escalation.
Once acquired, an EXCLUSIVE-LOCK in OpenEdge is held until one of the following:
- RELEASE table-name — explicitly releases all record locks held on that table's buffer in the current scope. The record buffer is cleared and the lock is freed immediately, regardless of whether a transaction is active.
- END TRANSACTION / end of a DO TRANSACTION block — all record locks acquired within the transaction scope are released when the transaction ends, whether by commit or rollback.
- Transaction rollback — an error or explicit UNDO that rolls back a transaction releases all locks acquired within that transaction.
- Session disconnect — when an OpenEdge session terminates or disconnects from the database, the OpenEdge session lock table for that session is cleared and all held locks are released. Each OpenEdge session maintains its own independent lock table in the database's lock manager.
- Record going out of scope in a FOR EACH block — within a
FOR EACHloop, the lock on each record is released as the loop advances to the next record (unless the record is inside aDO TRANSACTIONblock, in which case the lock is held until the transaction ends).
The critical implication: if an ABL procedure acquires an EXCLUSIVE-LOCK with FIND FIRST and then exits via a RETURN statement without first executing RELEASE, the lock is not released by the RETURN itself. The lock remains held in the calling scope — specifically, in whatever transaction scope the calling program is managing.
The updAppt.p procedure and the early-exit locking pattern
updAppt.p was a standalone ABL procedure responsible for updating appointment status records in the apptmgmt.db database. It accepted an integer appointment ID (iApptID) and a new status string (cNewStatus) as input parameters, located the corresponding Appointment record, validated that the update was appropriate, and applied the new status. The procedure as originally written:
/* updAppt.p — appointment status update procedure */
/* OpenEdge 11.7.9 — apptmgmt.db */
DEFINE INPUT PARAMETER iApptID AS INTEGER NO-UNDO.
DEFINE INPUT PARAMETER cNewStatus AS CHARACTER NO-UNDO.
FIND FIRST Appointment
WHERE Appointment.ApptID = iApptID
EXCLUSIVE-LOCK NO-ERROR. /* lock acquired HERE */
IF NOT AVAIL Appointment THEN RETURN. /* exits — lock still held? */
IF Appointment.Status = "Cancelled" THEN RETURN. /* BUG: lock held */
IF Appointment.Status = "NoShow" THEN RETURN. /* BUG: lock held */
ASSIGN
Appointment.Status = cNewStatus
Appointment.LastModified = TODAY.
The structure appears logical at first glance: find the record exclusively, validate it, update it. The problem is that the EXCLUSIVE-LOCK is acquired before any of the validation checks. When IF Appointment.Status = "Cancelled" THEN RETURN fires, the procedure exits immediately. OpenEdge has already locked the Appointment record exclusively. The RETURN exits updAppt.p and returns to the caller — the ADM2 SmartWindow's DO TRANSACTION block. The SmartWindow's transaction is still open. The Appointment record's EXCLUSIVE-LOCK is still held in that transaction scope.
The IF NOT AVAIL Appointment THEN RETURN check at first appears safe: if the FIND found nothing, there is no record buffer, so there is no lock. In OpenEdge, a FIND ... NO-ERROR that finds no matching record sets the availability to false and acquires no lock. So the first RETURN is technically harmless. But the two status checks that follow it are not: by the time those checks execute, the FIND has already succeeded and the EXCLUSIVE-LOCK is held.
ADM2 SmartWindow DO TRANSACTION scope: why the lock outlasted the procedure
updAppt.p was not called in isolation. It was called from within the clinic scheduling SmartWindow using the standard ADM2 invocation pattern:
/* SmartWindow trigger — Save button */
DO TRANSACTION:
RUN updAppt.p (INPUT iSelectedApptID, INPUT cNewStatus).
END.
In OpenEdge ABL, a DO TRANSACTION block defines a transaction boundary. Any record locks acquired by procedures called within that DO TRANSACTION block are owned by that transaction. The transaction does not end until the END statement of the DO TRANSACTION block is reached. If the block is inside a SmartWindow's save-trigger procedure, and the save-trigger procedure returns normally (as it does here, since RUN updAppt.p returns without error even when updAppt.p exits via the Cancelled/NoShow RETURN), the DO TRANSACTION block ends normally — committing any changes and releasing any locks.
But here is the subtlety that caused the incident at Prairie Health Network: the SmartWindow was built with an ADM2 pattern where the save trigger was not the only context in which DO TRANSACTION blocks executed. The coordinator's SmartWindow maintained its own broader transaction context through the ADM2 framework's SmartDataObject save mechanism. When the coordinator opened an appointment for editing, the ADM2 framework placed that record's buffer into a pending-changes state within an implicit transaction scope that spanned the entire editing session — from the moment the coordinator opened the appointment detail view to the moment they explicitly saved or cancelled.
The RUN updAppt.p call happened within this broader ADM2 transaction context. When updAppt.p exited via the Cancelled RETURN, the EXCLUSIVE-LOCK on the Appointment record was held in the ADM2 framework's transaction — which remained open as long as the SmartWindow was open and the coordinator was still working in it. On a busy clinic scheduling day, a coordinator might have a SmartWindow open for 30, 45, or even 90 minutes between interactions. During that entire window, any Appointment record that triggered a Cancelled or NoShow early exit in updAppt.p was locked out to every other session on the network.
PROMON R&D Record Locking Summary: identifying the locked records
The retainer developer accessed the OpenEdge PROMON (Progress Monitor) utility on the apptmgmt.db database server and navigated to the R&D (Research and Development) diagnostic menu, then to the Record Locking Summary. This is the definitive tool for identifying which sessions hold which record locks in an OpenEdge database. The output showed:
PROMON R&D → Record Locking Summary
Database: apptmgmt.db
Table RecID Lock Type Session User Duration
----------- ------- ---------- ------- ---------- --------
Appointment 18294 EXCL 14 PHNET\coord4 47:12
Appointment 21883 EXCL 14 PHNET\coord4 23:04
Appointment 19047 EXCL 14 PHNET\coord4 11:38
Three Appointment records were exclusively locked by SESSION-ID 14, which corresponded to the workstation at scheduling station 4 (PHNET\coord4). The durations — 47 minutes, 23 minutes, and 11 minutes — showed that these locks had accumulated over the course of the coordinator's morning shift. The developer queried the Appointment table directly to confirm the status of each locked record:
FOR EACH Appointment NO-LOCK
WHERE Appointment.ApptID = 18294
OR Appointment.ApptID = 21883
OR Appointment.ApptID = 19047:
DISPLAY Appointment.ApptID Appointment.Status.
END.
ApptID Status
------ ----------
18294 Cancelled
21883 NoShow
19047 Cancelled
All three locked records had the exact statuses (Cancelled or NoShow) that triggered updAppt.p's early RETURN paths. The correlation was definitive: every time the coordinator at station 4 attempted to update a Cancelled or NoShow appointment through the SmartWindow, updAppt.p acquired an EXCLUSIVE-LOCK on the Appointment record and then returned early without releasing it. The SmartWindow's open transaction held the lock. Three such incidents had occurred that morning before the PROMON session, producing three simultaneously locked appointment records.
The staff members at other stations who received ERROR 26 were attempting to view or reschedule those exact three appointments — ApptIDs 18294, 21883, and 19047. From their sessions, any FIND FIRST Appointment WHERE Appointment.ApptID = 18294 with EXCLUSIVE-LOCK or SHARE-LOCK immediately received ERROR 26 because SESSION-ID 14 held an exclusive lock. Even a SHARE-LOCK request is blocked by an existing EXCLUSIVE-LOCK in OpenEdge — the exclusive lock prevents any other session from accessing the record in any lock mode other than NO-LOCK.
The fix: NO-LOCK for validation, FIND CURRENT EXCLUSIVE-LOCK for the update path
The correct OpenEdge ABL pattern for this situation is to separate the read-for-validation phase from the read-for-update phase. Validate with NO-LOCK first — which acquires no lock and allows all the early-exit RETURN statements to execute without leaving any lock behind. Only after validation passes and the procedure has confirmed it will definitely proceed with the update should it upgrade to EXCLUSIVE-LOCK using FIND CURRENT:
/* updAppt.p — fixed version */
/* OpenEdge 11.7.9 — apptmgmt.db */
DEFINE INPUT PARAMETER iApptID AS INTEGER NO-UNDO.
DEFINE INPUT PARAMETER cNewStatus AS CHARACTER NO-UNDO.
FIND FIRST Appointment
WHERE Appointment.ApptID = iApptID
NO-LOCK NO-ERROR. /* no lock acquired */
IF NOT AVAIL Appointment THEN RETURN. /* safe — no lock held */
IF Appointment.Status = "Cancelled" THEN RETURN. /* safe — no lock held */
IF Appointment.Status = "NoShow" THEN RETURN. /* safe — no lock held */
FIND CURRENT Appointment EXCLUSIVE-LOCK. /* acquire only when certain to update */
ASSIGN
Appointment.Status = cNewStatus
Appointment.LastModified = TODAY.
FIND CURRENT in OpenEdge upgrades the lock on the record that is already in the current buffer — the same record that was found with NO-LOCK — to EXCLUSIVE-LOCK. It does not re-execute the WHERE clause or re-navigate the index. It simply promotes the lock level on the record already held in the buffer. This pattern is idiomatic OpenEdge ABL and is the standard approach for read-validate-then-update logic.
The alternative fix — keeping the original FIND FIRST ... EXCLUSIVE-LOCK and adding RELEASE Appointment before each early RETURN — also works and is sometimes preferable when the validation logic is more complex or when a future developer might add additional RETURN paths that could inadvertently skip the RELEASE:
/* updAppt.p — alternative fix: RELEASE on each non-update RETURN */
FIND FIRST Appointment
WHERE Appointment.ApptID = iApptID
EXCLUSIVE-LOCK NO-ERROR.
IF NOT AVAIL Appointment THEN RETURN.
IF Appointment.Status = "Cancelled" THEN DO:
RELEASE Appointment.
RETURN.
END.
IF Appointment.Status = "NoShow" THEN DO:
RELEASE Appointment.
RETURN.
END.
ASSIGN
Appointment.Status = cNewStatus
Appointment.LastModified = TODAY.
The retainer developer recommended and implemented the NO-LOCK + FIND CURRENT EXCLUSIVE-LOCK approach (the first fix) rather than the RELEASE-before-each-RETURN approach. The reasoning: the NO-LOCK first pattern is structurally self-correcting. Any future developer adding a new validation check with a RETURN statement will naturally add it in the NO-LOCK validation section, before the FIND CURRENT EXCLUSIVE-LOCK line — and it will automatically be correct. The RELEASE-before-RETURN approach requires future developers to remember to add RELEASE Appointment before every new RETURN, which is the same class of mistake that caused the original bug.
OpenEdge 4GL session model and lock persistence
Understanding why the locks at Prairie Health Network persisted for 47 minutes requires understanding the OpenEdge session model. Each connection to an OpenEdge database is a session. Each session has its own entry in the database's lock manager, and that entry accumulates all record locks acquired by programs running in that session. The lock table entry for a session is maintained by the database server as long as the session is connected — it is not cleared by individual procedure returns, window closes, or navigation events within the session.
This is fundamentally different from, say, a web application where each HTTP request is typically a separate transaction and locks are released at the end of each request handler. An OpenEdge ADM2 SmartWindow is a persistent GUI session. The session connects to the database when the application starts, maintains that connection through the entire user workday, and disconnects only when the application exits. Any record lock acquired during that session — and not released by a RELEASE statement, END TRANSACTION, or ROLLBACK — remains held in the session's lock table until the session terminates.
The 47-minute duration for ApptID 18294 meant that the coordinator at station 4 had attempted to update that appointment 47 minutes before the PROMON session, the attempt had triggered the Cancelled RETURN in updAppt.p, and for the next 47 minutes every other session that tried to access appointment 18294 was blocked. The coordinator had no indication that anything was wrong — from their perspective, the update attempt had simply returned without error (updAppt.p RETURN is a clean exit, not an error). The problem was invisible to the session that caused it and highly visible to every other session that needed the same record.
The session model also explains why disconnecting the coordinator's session was the immediate remediation: forcing a session disconnect caused OpenEdge to clean up the session's lock table, releasing all three EXCLUSIVE-LOCK records simultaneously. The developer confirmed this via PROMON after the session was cleared: the Record Locking Summary showed 0 EXCLUSIVE-LOCK records on the Appointment table from any session. The three appointment records became immediately accessible to other sessions.
Why EXCLUSIVE-LOCK-first is a common ABL mistake
The FIND FIRST ... EXCLUSIVE-LOCK pattern before validation is not a careless error — it is a natural consequence of how OpenEdge ABL programs are typically taught and written. In introductory ABL examples, the pattern is: FIND the record, check AVAIL, update it. The EXCLUSIVE-LOCK is placed on the FIND because "that's what you use when you're going to update." The validation checks that follow are usually assumed to be rare edge cases, not primary code paths.
In production systems, however, status checks like "IF Appointment.Status = 'Cancelled'" often turn out to be common paths — not edge cases. At Prairie Health Network, a significant fraction of appointment update requests came through the scheduling SmartWindow for appointments that were already Cancelled or NoShow, because coordinators frequently opened appointment records to review history before deciding on a new action. updAppt.p was designed under the assumption that it would only be called when a genuine status change was needed, but the SmartWindow's UI flow allowed the save trigger to fire even when no meaningful update was intended.
The OpenEdge documentation on record locking is explicit that EXCLUSIVE-LOCK is acquired at FIND time, but this detail is easy to overlook when the primary mental model is "find, validate, update" — the lock acquisition feels like a preparation for the update that might follow, rather than an immediate database operation. The NO-LOCK + FIND CURRENT EXCLUSIVE-LOCK pattern avoids this conceptual mismatch entirely by making the lock acquisition a deliberate step that only occurs when the update is certain to proceed.
After the fix: PROMON confirms clean locking
After deploying the fixed updAppt.p and restarting the clinic scheduling SmartWindow (to clear the three existing locked records by terminating SESSION-ID 14's connection), the retainer developer ran a series of test cases through the SmartWindow targeting appointments with Cancelled and NoShow statuses. For each test, PROMON R&D Record Locking Summary was checked immediately after the SmartWindow's save trigger fired:
PROMON R&D → Record Locking Summary
Database: apptmgmt.db
Table RecID Lock Type Session User Duration
----------- ------- ---------- ------- ---------- --------
(no records)
Zero EXCLUSIVE-LOCK records held on the Appointment table by updAppt.p after Cancelled and NoShow exits. A test case with an appointment that had a valid updatable status (e.g., Status = "Scheduled") confirmed that the FIND CURRENT EXCLUSIVE-LOCK step correctly acquired the exclusive lock for the duration of the update and released it cleanly at the end of the DO TRANSACTION block. The lock appeared in PROMON during the update transaction and disappeared after the transaction committed.
The scheduling team reported that ERROR 26 conflicts on Appointment records dropped to zero after the fix was deployed and the SmartWindow was restarted across all scheduling stations. The three specific appointments that had been locked (ApptIDs 18294, 21883, 19047) were immediately accessible to other sessions once the SmartWindow restart cleared SESSION-ID 14's lock table.
How HourTab helps Progress OpenEdge retainer developers
The diagnosis and fix took 3 hours: 30 minutes reviewing the incident reports from the scheduling staff and identifying the specific ERROR 26 pattern; 30 minutes accessing PROMON R&D Record Locking Summary and correlating the three locked ApptIDs to SESSION-ID 14 at station 4; 45 minutes reviewing the updAppt.p source code, tracing the FIND FIRST EXCLUSIVE-LOCK call, and mapping all RETURN paths to determine which exited without RELEASE; 30 minutes writing the fix, applying the NO-LOCK + FIND CURRENT EXCLUSIVE-LOCK restructure, and reviewing for any other ABL procedures in the apptmgmt application that used the same problematic EXCLUSIVE-LOCK-first validation pattern; 15 minutes testing the fix against Cancelled and NoShow appointments in the development environment and confirming PROMON showed 0 residual locks; 30 minutes coordinating the SmartWindow restart across the four scheduling stations and verifying the production PROMON Record Locking Summary cleared. A brief 30-minute session was also spent with the scheduling supervisor explaining the root cause, demonstrating the PROMON R&D Record Locking Summary navigation, and setting up a simple monitoring checklist for the IT support staff to run PROMON at the start of each morning shift if coordinators report ERROR 26 conflicts.
Each segment of that work is distinct, billable retainer activity. In a HourTab log, the session reads: “updAppt.p FIND FIRST Appointment EXCLUSIVE-LOCK not released on Cancelled/NoShow RETURN — PROMON R&D Record Locking Summary confirmed ApptIDs 18294/21883/19047 EXCL locked by SESSION-ID 14 for 47/23/11 min; restructured to NO-LOCK first, validate, FIND CURRENT EXCLUSIVE-LOCK on update path only; all 4 station SmartWindows restarted; PROMON post-fix: 0 orphaned EXCL locks; ERROR 26 scheduling conflicts: eliminated; PROMON monitoring checklist for IT support, 3.0h.” Prairie Health Network's IT manager reads that entry and sees exactly which records were locked, which session held them, how long they had been held, and what structural change was made to prevent recurrence — not a vague “fixed locking issue” entry that raises more questions than it answers.
HourTab turns a time-tracker CSV into a public retainer-hours URL your client can bookmark — no login, no portal, no “how many hours do I have left?” emails. Free for one retainer. $9/mo for up to ten.
FAQ: Progress OpenEdge developer retainers
What does a Progress OpenEdge developer on retainer typically do?
A Progress OpenEdge developer on monthly retainer covers ABL program maintenance (FIND FIRST/LAST/NEXT with NO-LOCK, SHARE-LOCK, and EXCLUSIVE-LOCK; RELEASE for explicit lock management; DO TRANSACTION block scope; IF AVAIL / IF NOT AVAIL availability checks; CREATE, ASSIGN, DELETE record statements; BUFFER-COPY and BUFFER-COMPARE); OpenEdge database administration (Data Dictionary schema changes, proutil integrity checks, proutil -C idxbuild index rebuilds, extent additions, dump/load migrations); ADM2 SmartObject and SmartWindow maintenance (SmartDataObject queries, SmartBrowser configuration, SmartWindow transaction scope); Progress Application Server (PAS for OpenEdge) and AppServer maintenance (NameServer configuration, broker and worker tuning, stateless vs. stateful session design); PROMON diagnostics (Record Locking Summary, buffer cache hit rates, I/O statistics, active user sessions); and OpenEdge replication and After-Image journaling configuration for disaster recovery.
What OpenEdge ABL record locking work is most commonly underlogged?
FIND FIRST / FIND NEXT with EXCLUSIVE-LOCK followed by early RETURN without RELEASE is the most systematically underlogged OpenEdge retainer work. Pattern: updAppt.p issues FIND FIRST Appointment EXCLUSIVE-LOCK NO-ERROR — lock acquired immediately at FIND time; IF Appointment.Status = "Cancelled" THEN RETURN and IF Appointment.Status = "NoShow" THEN RETURN exit without RELEASE Appointment; lock held in calling SmartWindow's DO TRANSACTION scope for the entire SmartWindow session; other sessions receive ERROR 26 Record currently being used by another user; PROMON R&D Record Locking Summary confirms the ApptIDs, SESSION-ID, and duration; fix: restructure to FIND FIRST ... NO-LOCK NO-ERROR, validate (no lock held on any RETURN), then FIND CURRENT Appointment EXCLUSIVE-LOCK only when update will proceed. Log must specify the table, record identifiers, STATUS values that triggered early RETURN, and PROMON Record Locking Summary output.
What are typical Progress OpenEdge developer retainer rates?
Entry-level OpenEdge ABL developers with basic ABL syntax (FIND, FOR EACH, IF AVAIL, ASSIGN, CREATE, DELETE, basic lock mode usage, simple DO TRANSACTION blocks, Data Dictionary navigation) typically bill at $75 to $130 per hour. Mid-level OpenEdge developers with record lock lifecycle debugging (EXCLUSIVE-LOCK vs NO-LOCK patterns, FIND CURRENT EXCLUSIVE-LOCK upgrades, RELEASE statement placement, PROMON R&D Record Locking Summary diagnostics, SmartWindow transaction scope analysis, ADM2 SmartObject maintenance, AppServer broker configuration, proutil database utilities) typically bill at $110 to $190 per hour. Senior OpenEdge developers with full architecture expertise (DO TRANSACTION scope design for multi-table ACID updates, OpenEdge database extent planning and schema migration strategy, PAS for OpenEdge stateless/stateful design, After-Image journaling and point-in-time recovery, OpenEdge Replication configuration, version upgrade planning from 10.x or 11.x to 12.x, multi-tenant database architecture) typically bill at $165 to $285 per hour. Monthly retainer ranges: $3,000 to $6,500 per month for ABL program maintenance, lock debugging, and database operations; $5,500 to $12,000 per month for OpenEdge architecture and system engineering.
What should a Progress OpenEdge developer retainer agreement include?
A Progress OpenEdge retainer agreement should specify: OpenEdge version (10.2B, 11.7, 12.2, 12.8 LTS) and operating system (Windows Server, Linux, AIX) since ABL behavior, PROMON availability, and database utility options vary by platform; whether ABL application maintenance is in scope and which libraries (standalone .p procedures, class-based .cls objects, procedure libraries .pl); whether ADM2 SmartObject maintenance is in scope — SmartWindow, SmartDataObject, SmartBrowser, and SmartViewer each have distinct transaction and lock-scope patterns requiring ADM2 framework knowledge beyond plain ABL; whether database administration is in scope — schema changes via Data Dictionary, proutil integrity checks, index rebuilds, extent additions, and dump/load migrations require DBA-level skills distinct from application development; whether AppServer or PAS for OpenEdge configuration is in scope (NameServer, broker/worker tuning, stateful vs. stateless session design); whether OpenEdge replication or After-Image journaling is in scope; and whether on-call emergency response for ERROR 26 record lock incidents is covered with a defined response-time SLA.
How should Progress OpenEdge developer retainer hours be logged?
Log each OpenEdge retainer session with the OpenEdge version, database name, program name, table name, record identifiers (ApptIDs), lock type, calling transaction scope, and the specific RETURN paths where RELEASE or lock restructuring was applied. For an EXCLUSIVE-LOCK-not-released diagnosis: OpenEdge 11.7.9 on Windows Server 2016; database apptmgmt.db; ABL procedure updAppt.p; table Appointment; FIND FIRST Appointment WHERE Appointment.ApptID = iApptID EXCLUSIVE-LOCK NO-ERROR at line 12 — lock acquired at FIND time; IF Appointment.Status = "Cancelled" THEN RETURN at line 16 — EXCLUSIVE-LOCK held on return; IF Appointment.Status = "NoShow" THEN RETURN at line 18 — EXCLUSIVE-LOCK held on return; called via RUN updAppt.p inside DO TRANSACTION block in clinic scheduling SmartWindow — lock tied to SmartWindow's ADM2 transaction scope; PROMON R&D Record Locking Summary: ApptID 18294 EXCL SESSION-ID 14 (PHNET\coord4) 47 min; ApptID 21883 EXCL SESSION-ID 14 23 min; ApptID 19047 EXCL SESSION-ID 14 11 min — all Cancelled or NoShow; other sessions: ERROR 26 on all three ApptIDs; fix: restructured to FIND FIRST ... NO-LOCK NO-ERROR at line 12; IF NOT AVAIL RETURN (no lock); IF Status = "Cancelled" RETURN (no lock); IF Status = "NoShow" RETURN (no lock); FIND CURRENT Appointment EXCLUSIVE-LOCK at new line 20 — lock acquired only when update proceeds; all 4 station SmartWindows restarted to clear SESSION-ID 14's lock table; PROMON post-fix: 0 EXCL locks on Appointment from any session; ERROR 26 incidents: 0; PROMON monitoring checklist created for IT support; hours: 0.5h incident review + 0.5h PROMON session + 0.75h source review + 0.5h fix + 0.25h dev test + 0.5h production restart/verify = 3.0h.
See also: Progress 4GL developer retainer · Informix developer retainer · CA Datacom/DB developer retainer