Logo

Hacker’s Guide to Visual FoxPro
An irreverent look at how Visual FoxPro really works. Tells you the inside scoop on every command, function, property, event and method of Visual FoxPro.

LOCK(), RLOCK(), SET MULTILOCKS, Set(“MultiLocks”), Unlock

These functions and commands allow locking and unlocking of one or more records. It is only by locking a record that the application can be sure that it is viewing the actual data on disk. MULTILOCKS allow more than one record in a table to be locked at one time; this is essential for table buffering. With the introduction of buffering in Visual FoxPro, explicit record locking is needed far less frequently.

Usage

lSuccess = RLOCK | LOCK ( [ [ cRecordList, ]
                          nWorkArea | cAlias ] )

Parameter

Value

Meaning

cRecordList

Character

A comma-separated list of the record numbers to be locked.

nWorkArea

Numeric

Specifies the work area in which the lock should be placed.

Omitted

If cAlias is also omitted, place the lock in the current work area.

cAlias

Character

Specifies the alias of the table receiving the lock.

Omitted

If cAlias is also omitted, the lock takes place on the current table.

lSuccess

.T.

Lock(s) were successfully placed.

.F.

The lock(s) failed because another user has the record or table locked, or the work area has no table open, or the record numbers do not exist. If the alias is not valid, the error "Alias not found" is generated.

LOCK() and RLOCK() are exactly the same. RLOCK() stands for Record Lock, to differentiate it from FLOCK(), the File Lock function. The LOCK() function was inherited from another Xbase dialect, but functions exactly the same as RLOCK().

RLOCK() locks a record, flagging it as available for update only by this workstation. Other workstations can view the record or display the record’s values in reports, but they cannot change the record. A record lock will fail if another workstation has already locked that record, or locked the file.

This is termed an “explicit” record lock, where you actually issue a lock command in code. Implicit record locks are created by the system and released automatically when a command that must change a record is issued against an unlocked record. These commands include APPEND, DELETE, GATHER, INSERT and REPLACE, as well as table-locking commands such as REPLACE ALL, UPDATE and ALTER TABLE. We prefer to issue explicit locks as much as possible, so we can handle locking problems locally. An alternative to consider in your system’s design is to handle these locking issues globally, with a combination of the ON ERROR command and SET REPROCESS settings. Transactions and both optimistic and pessimistic locking work as implicit lock commands, and can be handled using the ON ERROR and SET REPROCESS methods as well.

RLOCK() can lock multiple records with a single command. Strangely, this option requires that you specify the alias or work area where the locks should be placed. This is another of those unusual commands where the optional arguments come before the others, so it takes a little study to get it right. Unlike an individual RLOCK(), throwing multiple locks with this command does not assume you mean the current work area. We usually just tack on ALIAS() as the second parameter when we want the locks applied to the current work area.

Issuing RLOCK() with a list of multiple records to lock returns .T. if the locks can be placed—even if MULTILOCKS is set OFF! But only the last record ends up locked—each is locked in sequence, as if you had issued separate RLOCK()s for each record, and then each is unlocked automatically as the next record is locked. This is dumb! RLOCK() should always return .F. if a list of records is supplied, and MULTILOCKS is not ON.

Specifying the record number 0 (zero) locks the table header without locking any individual records. We’ve never done this, and aren’t sure why this would be preferable to an FLOCK(). Locking the table header prevents other users from adding records, because the number of records is stored in the header, but it does allow individual record locks on existing records. So why might you want to do this? One of the few scenarios we can imagine is if you want to run a report off the table, and don’t want records added in the middle of the report to throw off your count or totals. By SETting LOCK ON, you can read the current values of individually locked records, and get the most accurate report on the state of the table with the least inconvenience to other users on the network. However, if you choose this method, be aware that your technique for adding records must be able to gracefully handle the possibility that records cannot always be added to a table. SYS(2011) reports condition as “Header Locked.”

Example

? RLOCK("82,93,75",ALIAS()) && locks 3 records

Usage

SET MULTILOCKS ON | OFF
cOnOrOff = SET( "MULTILOCKS" )

MULTILOCKS is required in order to be able to lock more than one record at a time. MULTILOCKS actually uses a different technology than the older single-lock-per-table technique. Because it doesn’t seem to make an extraordinary demand on resources, we recommend you leave MULTILOCKS ON all the time. MULTILOCKS is required for row and table buffering, and is scoped to each data session.

Contrary to the Help file, setting MULTILOCKS OFF unlocks all records in the table, if more than one record is locked, but leaves an individual lock if only one is in place. It also leaves individual locks in place in other work areas, although it does clear multiple locks on those tables.

Usage

UNLOCK [ RECORD nRecord ] [ IN nWorkArea | cAlias ] | [ ALL ]

Parameter

Value

Meaning

nRecord

0

Unlocks the table header.

Integer

Unlocks the specified record number.

nWorkArea

Integer

Specifies the work area in which lock(s) are to be released.

Omitted

In cAlias is also omitted, unlocks records in the current work area.

cAlias

Character

The alias of the table whose locks are to be released.

Omitted

If nWorkArea is also omitted, unlocks records in the current work area.

UNLOCK releases previously set locks on one record, all records, or a table header. UNLOCK with no further arguments releases all file and record locks in the current work area. UNLOCK RECORD 0 releases a table header lock. UNLOCK ALL releases all record and file locks in all work areas in the current data session.

UNLOCK and its relative RLOCK() show some distinctive inconsistencies—you lock records with a function, but unlock them with a command. You can specify multiple records to lock with a character string, comma-separated list, but you can unlock only an individual record or all of them—not a specified subset. While we're not campaigning for the ability to specify lists of records to unlock—we've never needed the function much—we do find the inconsistencies worth noting.

Example

UNLOCK ALL

See Also

CursorSetProp(), CurVal(), FLock(), GetFldState(), IsFLocked(), IsRLocked(), OldVal(), On Error, Set DataSession, Set Lock, Set Refresh, Set Reprocess, SetFldState(), Sys(2011), TableUpdate()