Locking Scope with External Procedures


I have two programs:


FIND item WHERE item.part-num = "4M5"
    AND item.cto-code = ""
RUN test2.



FIND sysmstr WHERE coname = "NEXTWO"

When test.p pauses, both ITEM and SYSMSTR tables are locked.
  1. Why is SYSMSTR still locked after leaving test2.p? Isn't an external procedure a separate transaction? Is the ITEM exclusive lock in test.p changing the locking scope?
  2. How can I unlock SYSMSTR in test2.p?

Rob Fitzpatrick

ProgressTalk.com Sponsor
When test.p pauses, both ITEM and SYSMSTR tables are locked.
ABL code doesn't lock tables. I think what you mean is that the records that you are accessing in those tables are locked.

Isn't an external procedure a separate transaction?
A client session can only have one transaction at a time; either you are in one or you aren't. You need to know the code patterns (there is more than one) that cause transactions. A find... exclusive-lock will start a transaction. How that transaction is scoped will depend on the surrounding or calling code. If you start a transaction in test.p and then run test2.p, the entirety of test2.p is within that transaction. Exclusive record locks are not released within the enclosing transaction.

Is the ITEM exclusive lock in test.p changing the locking scope?
There is transaction scope and record scope; separate concepts. I suggest you review the docs on them.

If the code you have shown is real, your transaction scope is the procedure test.p. You can see transaction and buffer scope with a compile... listing of the procedure(s) in question, though it only does one procedure per listing.



Thanks, Rob. That helps a lot.

I was looking through the locking documentation and found one of the articles confusing:
If you have any doubt at all about when a record goes out of scope or when a lock is released, release the record explicitly when you are done updating it with the RELEASE statement. If you release the record, you know that it is no longer locked, and that you cannot unwittingly have a reference to it after the transaction block that would extend the scope of the lock, or even the transaction.

Is that really true? I've heard time and time again that RELEASE doesn't unlock records; it just clears the record from the buffer and joins it to the database.

Rob Fitzpatrick

ProgressTalk.com Sponsor
I've heard time and time again that RELEASE doesn't unlock records
That is correct, though that is not how I would word it.

I'm not an expert on such things but here is my understanding:
  • What is being released directly by a RELEASE statement is the contents of a record buffer, not a record lock.
  • Note the wording of the documentation that you quoted, specifically "after the transaction block". A lock acquired in or before a transaction won't be released within that transaction, whether or not you use a RELEASE statement.
  • A record share-lock, unlike an exclusive-lock, can be held outside a transaction. If the record buffer is released with a RELEASE statement, that share-lock will end as a side-effect. But don't think of it as being "released" directly.
Consider the following code:
/* do transaction: */
find first state share-lock.
pause message 'we have a share lock; check promon R&D 1, 6, 1'.
release state.
pause message 'we are after the release; check promon R&D 1, 6, 1'.
/* end. */

Run it against a multi-user sports database in one shell and run promon against that database in another. At the first PAUSE, there will be a share-lock in the lock table for that state record. At the second PAUSE, after the RELEASE, the share-lock is gone.

Now uncomment the first and last statements and run it again. This time, the share-lock still exists at the second PAUSE. You can try moving the DO TRANSACTION: after the FIND and you will still have the same result. I hope this helps.