|SAS/SHARE User's Guide|
You can use SAS Component Language (SCL) with SAS/SHARE software to access data through a SAS/SHARE server. SCL has the ability to read and update SAS tables that are used concurrently by other clients or SCL applications. For complete information about SCL, see SAS Component Language: Reference.
A concurrent SCL application opens one SAS data table for update while other SAS operations (possibly in different SAS sessions) have the same data table open for update. These other opens for update can be done by other invocations of the first SCL application, by a different SAS application or SCL application, or even by a user who uses the FSEDIT or FSVIEW procedure on the table.
This section describes the following issues that you should consider when writing an SCL application that updates data concurrently:
Finally, see Appendix 4, "SAS Component Language Application," for an application that uses SAS tables that contain inventory and ordering information for each product in a store. The purpose of the application is to automate a system that develops orders and maintains the inventory list while sales representatives simultaneously write orders for products.
|Locking Rows in SAS Tables|
A row in a SAS table is locked implicitly when it is read by a SAS procedure, a DATA step, or an SCL application. A lock on a row is held until a different row is read or until the SCL application calls the UNLOCK function.
When a SAS table is opened for update, only one row can be locked at a time. When a SAS table is opened for update more than one time in the same SAS session or in different SAS sessions (through a server), a different row can be locked by each of the opens. For example, if two users are running an SCL application that calls the OPEN function to open a SAS table for update, row 7 can be locked under one of the opens while row 10 is locked under the other.
|Implications of Row Locking in SCL|
Row locking is a key consideration in concurrent SCL programming. After a lock on a row is released, your application can no longer be sure of the values that are contained in that row; another user might have already modified the values. Any data modifications that you make that are based on the old values may damage the data integrity of the system.
Therefore, you must never assume that the data values in a given row will not change in a shared table, even though only a very brief amount of time has elapsed between consecutive reads and locks of the row.
Row locking can give a programmer an important advantage. While an SCL application has a row locked, no other SAS operation (especially in another SAS session) can alter or delete that row. When each row in a SAS table can represent a specific instance of a resource that the application must govern, row locking provides a resource-specific, protected period of time in which the application can safely test and modify the state of the resource.
An example of a specific-resource instance is information about one of your customers or the number of items of a specific type that is currently in inventory. The sample SCL application in the appendix in this book applies locks to its inventory table to maintain the proper inventory count for each item, even if several sales representatives are simultaneously writing orders for those items.
|Programming with the FSEDIT and the FSBROWSE Procedures|
Unlike other SCL environments (such as SAS/AF software and the FSVIEW procedure), the FSEDIT and FSBROWSE procedures give the SCL programmer a number of labeled sections for structuring an SCL application. The sequence in which the FSEDIT and FSBROWSE procedures run some of these sections has several implications for concurrent SCL programming.
The INIT section is especially useful to applications that read and update shared data. The initial values of the columns in a row (as presently stored in the SAS table) can be preserved in SCL columns. Preservation of initial values in SCL columns is important for applications that update auxiliary tables that are based on the PROC FSEDIT user's modification or on the creation of a row in the primary table (that is, the table that is specified in the DATA= option in the PROC FSEDIT statement.) (footnote 1) These SCL applications typically need to perform the following tasks:
While the MAIN or TERM sections must validate the user's modifications to the primary table's row as well as update auxiliary tables, it is usually desirable that no row of an auxiliary table remain locked between executions of these sections. Such locks prevent other users or applications from modifying the row as long as the user is on the primary table's current row.
|Programming with the Data Table and Data Form Classes|
The Data Table and Data Form classes in SAS/AF FRAME entries allow you to specify an SCL entry to use for the model SCL. This SCL entry is separate from the frame's SCL entry. Model SCL is typically used to initialize computed columns and to perform error checking and data validation.
Like the FSEDIT procedure, the Data Table and the Data Form objects give the SCL programmer a number of labeled sections for structuring the order in which events will take place for each row in the table. These sections, which include INIT, MAIN, and TERM, operate in the same way as explained in Programming with the FSEDIT and the FSBROWSE Procedures.
If multiple instances of the Data Table or the Data Form objects are displayed within a single SAS/AF FRAME entry, the objects share data, then the model SCL for each data table or data form runs separately and the application developer must keep in mind whether a previous object has a lock on a row that the current object attempts to read or update. In addition, the frame SCL may also be operating on the shared data and timing within the frame could be critical. For more information about when SCL labels are run, see "Controlling Execution in the SCL" and "Summary of SCL Label Running" in the Data Set Data Model class under SAS/AF Component Reference in online help.
|Locating and Fetching Control Rows|
SCL provides a set of functions that are useful for locating and fetching the required auxiliary table observations in a data-concurrent SCL application. However, you should use caution with these functions in applications that access shared data. The return code, which is obtained directly from the called function or from the SYSRC function, must be checked to ensure that a lock was obtained on the observation or that an update was successful. The return value, which is generated by the macro invocation %SYSRC(_SWNOUPD), is generated when a fetch or update function fails to lock or update the observation because it is locked by another application.
The FETCHOBS table function is useful when the observation number can serve as the observation identifier. Remember that this function accepts a relative observation number by default that may or may not equate to the physical observation number. If you can delete observations in the auxiliary table, you probably want to use the ABS option of the FETCHOBS function for absolute observation numbering.
The LOCATEC and LOCATEN table functions may be useful for finding observations in small tables when the data can remain sorted by a unique identifier (column) and a binary search is specified. Beyond these limits, due to the overhead of searching with these SCL functions, you should use the WHERE and FETCH functions to find these observations. In a shared-data environment, each observation must be requested from the server and transmitted to the client's SAS session for the LOCATEC and LOCATEN functions to check.
The SYSRC function must be queried for warnings when the LOCATEC and LOCATEN functions find an observation because these functions return only a zero-positive return code for either condition: observation found or observation not found. The following SCL program example illustrates checking whether the located observation is locked by another task:
gotrec=locatec(data-set-id,var-num,search-string, sort-order); if (gotrec<=0) then do; /* Handle observation not found */ end; else if (sysrc()=%sysrc(_swnoupd)) then do; /* Handle observation locked */ end;
Note: The LOCATEC and LOCATEN functions cannot perform
binary searches on compressed tables, SAS data views, or SAS data files with
The more general and usually more efficient way to locate an observation is to use the WHERE function followed by a FETCH function call. The WHERE clause is evaluated in the server's SAS session, and only the observation that satisfies the WHERE clause is transmitted to the client's SAS session.
If the WHERE clause does not find the requested observation, the FETCH function returns a -1 return code indicating that the end of the table has been reached. If the WHERE clause is cleared by issuing a null WHERE function call, the next FETCH call that the application issues fetches the first observation in the table. The FETCH call, not the WHERE clause, locks the observation (if possible). Note that the WHERE function returns a harmless warning, %SYSRC(_SWWREP), when the WHERE clause is replaced.
The DATALISTC and DATALISTN selection-list functions help a client to select a valid observation. These functions actually fetch the entire selected observation into the Table Data Vector (DDV) and lock the observation (if possible). Because these functions do not return a system return code, the SYSRC function must be queried for warnings. The DATALISTC and DATALISTN functions may cause the entire SAS table to be read, where each observation read is transferred individually from the server to the client SAS session.
|Unlocking an Observation|
Besides releasing a lock on the current observation by reading another observation, an SCL application can also use the SCL function UNLOCK. UNLOCK leaves the read-pointer at its current position in the table and does not update the DDV.
Furthermore, the SCL OBSINFO function returns information about the primary table's current observation in an FSEDIT application. You can query whether the observation has been deleted, locked, or newly created. An observation does not attain deleted status until the client's DELETE command has run. Therefore, if you specified the CONTROL ENTER statement to force your MAIN section to run, the OBSINFO function will not return the deleted status when issued from the MAIN section (because the user's DELETE command has caused MAIN to be run.) However, it will return a deleted status when the MAIN statement or TERM section is run again.
Top of Page
Copyright 1999 by SAS Institute Inc., Cary, NC, USA. All rights reserved.