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.

SET LOCK, Set(“Lock”), SET REPROCESS, Set(“Reprocess”)

SET LOCK determines whether a number of read-only commands automatically lock records in the table they’re reporting on. SET REPROCESS determines the behavior that should occur when a lock cannot be placed.

Usage

SET LOCK ON | OFF
cLockOnOrOff = SET( "LOCK ")

If a record is locked, other stations may not see changes to a record until they themselves lock the record. Data is cached at each local workstation and is not refreshed if another workstation locks, changes and unlocks one of those records on a shared table. SET LOCK ON forces a brief LOCK/UNLOCK pair on each record for many commands that otherwise would just report from cached data. These commands are listed in the documentation and include the mathematical AVERAGE, CALCULATE, SUM and TOTAL, as well as the output commands DISPLAY, LABEL, LIST and REPORT. If exactly up-to-the-minute data is critical, you may want to consider this command.

On the other hand, this command can really foul up a locking scheme. Setting LOCK ON means that these commands also release any pre-existing locks when they are run, as if UNLOCK ALL had been issued. See the first example below. If you really need this setting, we recommend that you wrap the individual needy commands in a SET/reSET pair to avoid problems with locking, as we show in the second example.

Example

SET MULTILOCKS ON
SET LOCK ON
? RLOCK("2,4,6,8",ALIAS()) && Lock four records.
LIST FOR SYS(2011) = "Record Locked"  && Nothing!
SET LOCK OFF
? RLOCK("2,4,6,8",ALIAS()) && Lock four records.
LIST FOR SYS(2011) = "Record Locked"  && Lists the four records.

cSetLock = SET("LOCK")
SET LOCK ON
CALCULATE AVG(nAge), MAX(nAge) to nAvg, nEldest
SET LOCK &cSetLock

* Also see the combined example with SET REPROCESS below.

Usage

SET REPROCESS TO nAttempts | nTime SECONDS | AUTOMATIC
     [ SYSTEM ]
nSetting = SET( "REPROCESS" )

Parameter

Value

Meaning

nAttempts

–2

This is the same as SET REPROCESS TO AUTOMATIC. When a command requiring a lock is issued, and the lock cannot be placed, the lock is retried forever (with the status bar prompt "Attempting to lock... Press ESC to cancel.") unless the user presses Escape to end the retries. If the user terminates the lock attempt and it came from a command that automatically places a lock, the ON ERROR handler receives the failed lock error. On the other hand, if a function such as LOCK() is placing the lock, the values .T. and .F. are returned to indicate the success of the operation, and the error handler is not called.

–1

One of the easiest ways to get your user to turn the computer off. If a lock cannot be made, the message "Waiting for lock..." is displayed and there is nothing—nothing—the user can do. If the user with the lock on the file or record of interest is off on vacation this week, you might as well take this week off. The main FoxPro window cannot be minimized or closed. There has to be a better way—we can't think of a worse one.

0

This one's a doozy, folks:

If an ON ERROR command is in effect, no attempts at retrying are performed. If a lock cannot be made, .F. is returned if a function tried to place the lock. If a command attempted the lock, an error is generated.

But, if there is no ON ERROR command in effect, both commands and functions behave just like AUTOMATIC locking.

Positive integer

The number of times to attempt to place the lock before giving up.

nTime

Positive integer

The number of seconds during which to continuously retry the lock.

nSetting

Integer

Returns the values set above, returning –2 for AUTOMATIC, and not distinguishing between settings of nAttempts and nTime.

This can be a very confusing command. The results often surprise the developer, because several conditions determine the outcome of an unsuccessful lock attempt. Mostly, we feel this is a documentation issue. The help file entry is so bad that we no longer understood the function after reading the topic. But we’ve gotten over it, and we hope we can help you to get over it, too.

First, if you are attempting to get a lock explicitly with functions such as FLOCK() or LOCK(), the functions return a logical value to tell you if you were successful. Your function gets control back after the time or number of retries expire, if this is specified. If automatic locking is chosen, your function gets the return after the lock is made, or if the user chooses not to wait for the lock and presses Escape.

If a command rather than a locking function is placing the lock, there’s no way for FoxPro to signal the command that a lock has failed, except by generating an error. Your ON ERROR handler should be written to handle these errors, offering the user the options of trying again or canceling the operation. If the user has the option of canceling, you need to consider how best to gracefully recover from this unstable condition, reset the environment, and restart the application. In a procedure where this error wouldn’t be unusual, we often install a local ON ERROR handler that can properly reset the environment if records are unavailable. In a global ON ERROR handler, it can be far more difficult. We might consider resorting to RETURN TO MASTER in this case, effectively shutting down and restarting the application.

In general, we try to avoid the second situation altogether by using explicit record locking and pessimistic buffering to reduce the potential loss of data. If we need to SET LOCK ON for some particular purpose, we often reset REPROCESS to AUTOMATIC for the length of that procedure, with a custom ON ERROR handler to handle unavailable data, but generally we leave REPROCESS at 0, and LOCK OFF.

SET REPROCESS is scoped to the current data session. You may also use the SYSTEM keyword, which applies to the system’s data session, which contains files like FoxUser, SCX files, databases and other files. The SYSTEM keyword was added in VFP 7. One of the reasons for adding the SYSTEM keyword is to prevent error 1709 from occurring when two people open the same view at the same time (VFP locks the view records in the DBC while it opens the view, so the second user gets this error).

Example

USE AGES
lcOnError = ON("ERROR")
lcSetLock = SET("LOCK")
lnSetRepr = SET("REPROCESS")
SET LOCK ON
SET REPROCESS TO -2
ON ERROR DO lErrHand with ERROR(), MESSAGE()
AVERAGE AGES TO nAges
ON ERROR &lcOnError
SET REPROCESS TO (lnSetRepr)
SET LOCK &lcSetLock

Procedure lErrHand(nErr, cMessage)
IF nErr = 108 or nErr = 109
  WAIT WINDOW "Some records were not available." + chr(13) + ;
              "Try again later. Press any key to continue..."
  RETURN
ENDIF
ENDPROC

See Also

Average, Calculate, Display, Error(), FLock(), IsFLocked(), IsRLocked(), Label, List, Lock(), On Error, Report, Return, Rlock(), Sum, SYS(2011), SYS(3051), SYS(3052), Total