Function Database_Services_Orig(@Service, @Params) /*********************************************************************************************************************** This program is proprietary and is not to be used by or disclosed to others, nor is it to be copied without written permission from SRP Computer Solutions, Inc. Name : Database_Services Description : Handler program for all Database services. Notes : Application errors should be logged using the Error Services module. There are a few methodological assumptions built into way errors are managed which are important to understand in order to properly work with Error Services: Parameters : Service [in] -- Name of the service being requested Param1-10 [in/out] -- Additional request parameter holders Response [out] -- Response to be sent back to the Controller (MCP) or requesting procedure Metadata : History : (Date, Initials, Notes) 03/27/17 dmb Original programmer. 05/02/17 dmb Add error if WriteDatabaseRow is unable to lock row. 10/31/17 dmb Add CalculateColumn and GetTableCommuter services. 05/25/18 dmb Add GetUserLocks service. 05/29/18 dmb Add IsKeyIDLocked, IsKeyIDSelfLocked, and UnlockKeyID services. 10/09/18 djs Added ActivateRecord service, which sets @ID, @Record, and @DICT to enable {} shorthand. ***********************************************************************************************************************/ #pragma precomp SRP_PreCompiler $insert LOGICAL $insert SERVICE_SETUP $insert VOL_TABLE_EQUATES $insert RTI_LH_INFO_EQUATES Declare function Memory_Services, Database_Services, SRP_Encode, RetStack, RTI_LH_Info, SRP_Path Declare subroutine Memory_Services, Database_Services, Verify_LH, SRP_Stopwatch, Btree.Extract, Update_Index, Set_Status Declare subroutine RTI_LH_Info GoToService else Error_Services('Add', Service : ' is not a valid service request within the ' : ServiceModule : ' module.') end Return Response OR '' //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Service Parameter Options //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Options BOOLEAN = True$, False$ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Services //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //---------------------------------------------------------------------------------------------------------------------- // VerifyLHAll // // Performs a health check againsts all attached tables and returns back any issues. Returns two lists which are // delimited by an @RM. The first list is an @FM list of attached tables. The second list is an @FM list of results // (groups that have GFEs or an empty string if there are none). Items in each list correspond which each other based on // their list position. //---------------------------------------------------------------------------------------------------------------------- Service VerifyLHAll() VerifyResults = '' TableNames = @TABLES(0) NumTables = DCount(TableNames, @FM) For TableCnt = 1 to NumTables TableName = TableNames VerifyResults := Database_Services('VerifyLH', TableName) : @FM Next TableCnt VerifyResults[-1, 1] = '' ; // Strip off the last @FM Response = TableNames : @RM : VerifyResults end service //---------------------------------------------------------------------------------------------------------------------- // VerifyLH // // TableNames. One or more linear hash database tables to verify. List should be @FM delimited. - [OPTIONAL] // SaveList. Name of a saved selection of linear hash database tables to verify. This argument will be ignored // if TableNames is populated. - [OPTIONAL] // // Performs a health check against the indicated tables and returns back any issues. Note: This uses the Verify_LH // subroutine to check for GFEs. All results are stored in the SYSLHVERIFY table with a KeyID of // VolumeLabel*DatabaseID*TableName. Returns the list of groups that have GFEs or returns an empty string if there are // none. The list of GFEs or empty strings will themselves be @FM delimited to correspond with the tables passed into // this service. //---------------------------------------------------------------------------------------------------------------------- Service VerifyLH(Tablenames, SaveList) VerifyResults = '' If TableNames EQ '' then TableNames = Xlate('SYSLISTS', SaveList, '', 'X') If Index(TableNames<1>, @TM, 1) then // This saved select has metadata in attribute 1. Remove it. TableNames = Delete(TableNames, 1, 0, 0) end end If TableNames NE '' then NumTables = DCount(TableNames, @FM) For TableCnt = 1 to NumTables TableName = TableNames TableProperties = Database_Services('GetTableProperties', TableName) If Error_Services('NoError') then rv = Set_Status(0) Verify_LH('', TableName, True$, False$, False$) Open 'SYSLHVERIFY' to hSysLHVerify then DatabaseID = TableProperties<1> VolumeLabel = TableProperties<3> LHVerifyKeyID = VolumeLabel : '*' : DatabaseID : '*' : TableName Read LHVerifyRec from hSysLHVerify, LHVerifyKeyID then VerifyResults = LHVerifyRec<2> end end else Error_Services('Add', 'Error opening the SYSLHVERIFY table in the ' : Service : ' service.') end Begin Case Case @File_Error NE '' Error_Services('Add', 'Error verifying table ' : TableName : ': FS Error = ' : @File_Error<1>) Case Get_Status() Error_Services('Add', 'Get_Status error: ' : Get_Status()) End Case end Next TableCnt end else Error_Services('Add', 'The TableName argument was missing in the ' : Service : ' service.') end Response = VerifyResults end service //---------------------------------------------------------------------------------------------------------------------- // GetTableProperties // // TableName. The linear hash database table name. - [REQUIRED] // // Returns an array of information related to the database table being passed in. //---------------------------------------------------------------------------------------------------------------------- Service GetTableProperties(TableName) TableProperties = '' If TableName NE '' then rv = Set_Status(0) Locate TableName in @TABLES(0) using @FM setting fPos then TableProperties<1> = @TABLES(3) ; // DatabaseID TableProperties<2> = @TABLES(4) ; // MFS/BFS List VolumeID = @TABLES(1) ; // Volume ID Locate VolumeID in @VOLUMES(0) using @FM setting fPos then TableProperties<3> = @VOLUMES(1) ; // Volume Label TableProperties<4> = @VOLUMES(2) ; // Volume Path TableProperties<5> = @VOLUMES(4) ; // BFS end end else Error_Services('Add', 'The ' : TableName : ' table is not attached and available to the ' : Service : ' service.') end end else Error_Services('Add', 'TableName argument was missing in the ' : Service : ' service.') end Response = TableProperties end service //---------------------------------------------------------------------------------------------------------------------- // GetTableHandle // // TableName. The linear hash database table name. - [REQUIRED] // // Returns an array of information related to the database table being passed in. //---------------------------------------------------------------------------------------------------------------------- Service GetTableHandle(TableName) ServiceKeyID := '*' : TableName TableHandle = Memory_Services('GetValue', ServiceKeyID, True$, 360) If TableHandle EQ '' then rv = Set_Status(0) Open TableName to TableHandle then Memory_Services('SetValue', ServiceKeyID, TableHandle) end else Error_Services('Add', 'Unable to open the ' : TableName : ' table in the ' : Service : ' service. Error = ' : @File_Error<1>) end end Response = TableHandle end service //---------------------------------------------------------------------------------------------------------------------- // ReadDataRow // // TableName. The linear hash database table name. - [REQUIRED] // KeyID. The KeyID to the database table. - [REQUIRED] // // Reads a data row for the indicated Key ID and database table. //---------------------------------------------------------------------------------------------------------------------- Service ReadDataRow(TableName, KeyID, NotExpired, ExpirationDuration, IgnoreMFSRoutines) If NotExpired NE False$ then NotExpired = True$ If (ExpirationDuration EQ '') OR (Not(Num(ExpirationDuration))) then ExpirationDuration = 0 If IgnoreMFSRoutines NE True$ then IgnoreMFSRoutines = False$ ServiceKeyID := '*' : TableName : '*' : KeyID DataRow = Memory_Services('GetValue', ServiceKeyID, NotExpired, ExpirationDuration) If TableName NE '' AND KeyID NE '' then If DataRow EQ '' then TableHandle = Database_Services('GetTableHandle', TableName) If Error_Services('NoError') then If IgnoreMFSRoutines then MFSList = TableHandle<1, 1> ; // MFS routines are @SVM delimited. NumMFS = DCount(MFSList, @SVM) For MFSCnt = NumMFS to 1 Step -1 MFSRoutine = MFSList<0, 0, MFSCnt> If MFSRoutine NE 'RTP57' then MFSList = Delete(MFSList, 0, 0, MFSCnt) end Next MFSCnt TableHandle<1, 1> = MFSList end Read DataRow from TableHandle, KeyID then Memory_Services('SetValue', ServiceKeyID, DataRow) end else Error_Services('Add', 'Error reading ' : KeyID : ' from the ' : TableName : ' table in the ' : Service : ' service.') end end end end else Error_Services('Add', 'TableName or KeyID argument was missing in the ' : Service : ' service.') end Response = DataRow end service //---------------------------------------------------------------------------------------------------------------------- // ReadDataColumn // // TableName. The linear hash database table name. - [REQUIRED] // KeyID. The KeyID to the database table. - [REQUIRED] // ColumnNo. The index of the column that is to be read. - [REQUIRED] // // Reads a data column for the indicated Key ID and database table. //---------------------------------------------------------------------------------------------------------------------- Service ReadDataColumn(TableName, KeyID, ColumnNo, NotExpired, ExpirationDuration, IgnoreMFSRoutines) If NotExpired NE False$ then NotExpired = True$ If (ExpirationDuration EQ '') OR (Not(Num(ExpirationDuration))) then ExpirationDuration = 0 If IgnoreMFSRoutines NE True$ then IgnoreMFSRoutines = False$ ServiceKeyID := '*' : TableName : '*' : KeyID : '*' : ColumnNo DataColumn = Memory_Services('GetValue', ServiceKeyID, NotExpired, ExpirationDuration) If Num(ColumnNo) AND (ColumnNo GT 0) then If TableName NE '' AND KeyID NE '' then If DataColumn EQ '' then TableHandle = Database_Services('GetTableHandle', TableName) If Error_Services('NoError') then If IgnoreMFSRoutines then MFSList = TableHandle<1, 1> ; // MFS routines are @SVM delimited. NumMFS = DCount(MFSList, @SVM) For MFSCnt = NumMFS to 1 Step -1 MFSRoutine = MFSList<0, 0, MFSCnt> If MFSRoutine NE 'RTP57' then MFSList = Delete(MFSList, 0, 0, MFSCnt) end Next MFSCnt TableHandle<1, 1> = MFSList end ReadV DataColumn from TableHandle, KeyID, ColumnNo then Memory_Services('SetValue', ServiceKeyID, DataColumn) end else ErrorMsg = 'Error reading ' : KeyID : ' column number ' : ColumnNo : ' from the ' | : TableName : ' table in the ' : Service : ' service.' Error_Services('Add', ErrorMsg) end end end end else Error_Services('Add', 'TableName or KeyID argument was missing in the ' : Service : ' service.') end end else Error_Services('Add', 'ColumnNo was not a number or was not greater than zero in the ' : Service : ' service.') end Response = DataColumn end service //---------------------------------------------------------------------------------------------------------------------- // ActivateRecord // // TableName. The linear hash database table name. - [REQUIRED] // KeyID. The KeyID to the database table. - [REQUIRED] // // Reads a data row for the indicated Key ID and database table. Sets @ID, @Record, and @DICT to enable {} shorthand. //---------------------------------------------------------------------------------------------------------------------- Service ActivateRecord(TableName, KeyID, NotExpired, ExpirationDuration, IgnoreMFSRoutines) If TableName NE '' AND KeyID NE '' then @ID = KeyID DictTable = '' If TableName[1,5] _EQC 'DICT.' then DictTable = TableName TableName = TableName[-1, 'B.'] end else DictTable = 'DICT.':TableName end @DICT = Database_Services('GetTableHandle', DictTable) If Error_Services('NoError') then @Record = Database_Services('ReadDataRow',TableName,KeyID,NotExpired,ExpirationDuration,IgnoreMFSRoutines) If Not(Error_Services('NoError')) then Error_Services('Add','Error reading ':KeyID:' from the ':TableName:' table in the ':Service:' service.') end end else Error_Services('Add', 'Error retrieving handle for the ':TableName:' table in the ':Service:' service.') end end Response = @Record end service //---------------------------------------------------------------------------------------------------------------------- // WriteDataRow // // TableName. The linear hash database table name. - [REQUIRED] // KeyID. The KeyID to the database table. - [REQUIRED] // // Writes a data row for the indicated Key ID and database table. //---------------------------------------------------------------------------------------------------------------------- Service WriteDataRow(TableName, KeyID, DataRow, IgnoreSelfLock, IgnoreMFSRoutines, IgnoreAllLocks) If TableName NE '' AND KeyID NE '' then If IgnoreSelfLock NE True$ then IgnoreSelfLock = False$ If IgnoreMFSRoutines NE True$ then IgnoreMFSRoutines = False$ If IgnoreAllLocks NE True$ then IgnoreAllLocks = False$ If IgnoreAllLocks then HaveLock = True$ end else HaveLock = Database_Services('GetKeyIDLock', TableName, KeyID, IgnoreSelfLock) end If HaveLock EQ True$ then TableHandle = Database_Services('GetTableHandle', TableName) If IgnoreMFSRoutines then MFSList = TableHandle<1, 1> ; // MFS routines are @SVM delimited. NumMFS = DCount(MFSList, @SVM) For MFSCnt = NumMFS to 1 Step -1 MFSRoutine = MFSList<0, 0, MFSCnt> If (MFSRoutine NE 'SI.MFS') AND (MFSRoutine NE 'RTP57') then MFSList = Delete(MFSList, 0, 0, MFSCnt) end Next MFSCnt TableHandle<1, 1> = MFSList end If Error_Services('NoError') then Write DataRow to TableHandle, KeyID then Memory_Services('SetValue', ServiceModule : '*' : 'ReadDatarow' : '*' : TableName : '*' : KeyID, DataRow) end else Error_Services('Add', 'Error writing ' : KeyID : ' to the ' : TableName : ' table in the ' : Service : ' service.') end end If IgnoreAllLocks EQ False$ then Database_Services('ReleaseKeyIDLock', TableName, KeyID) end end else Error_Services('Add', 'Unable to lock ' : KeyID : ' for the ' : TableName : ' table in the ' : Service : ' service.') end end else Error_Services('Add', 'TableName or KeyID argument was missing in the ' : Service : ' service.') end end service //---------------------------------------------------------------------------------------------------------------------- // DeleteDataRow // // TableName. The linear hash database table name. - [REQUIRED] // KeyID. The KeyID to the database table. - [REQUIRED] // // Deletes a data row for the indicated Key ID and database table. //---------------------------------------------------------------------------------------------------------------------- Service DeleteDataRow(TableName, KeyID, IgnoreSelfLock, IgnoreMFSRoutines) If TableName NE '' AND KeyID NE '' then If IgnoreSelfLock NE True$ then IgnoreSelfLock = False$ If IgnoreMFSRoutines NE True$ then IgnoreMFSRoutines = False$ HaveLock = Database_Services('GetKeyIDLock', TableName, KeyID, IgnoreSelfLock) If HaveLock EQ True$ then TableHandle = Database_Services('GetTableHandle', TableName) If IgnoreMFSRoutines then MFSList = TableHandle<1, 1> ; // MFS routines are @SVM delimited. NumMFS = DCount(MFSList, @SVM) For MFSCnt = NumMFS to 1 Step -1 MFSRoutine = MFSList<0, 0, MFSCnt> If (MFSRoutine NE 'SI.MFS') AND (MFSRoutine NE 'RTP57') then MFSList = Delete(MFSList, 0, 0, MFSCnt) end Next MFSCnt TableHandle<1, 1> = MFSList end If Error_Services('NoError') then Delete TableHandle, KeyID then Memory_Services('SetValue', ServiceModule : '*' : 'ReadDatarow' : '*' : TableName : '*' : KeyID, '') end else Error_Services('Add', 'Error deleting ' : KeyID : ' from the ' : TableName : ' table in the ' : Service : ' service.') end end Database_Services('ReleaseKeyIDLock', TableName, KeyID) end else Error_Services('Add', 'Unable to lock ' : KeyID : ' for the ' : TableName : ' table in the ' : Service : ' service.') end end else Error_Services('Add', 'TableName or KeyID argument was missing in the ' : Service : ' service.') end end service //---------------------------------------------------------------------------------------------------------------------- // GetKeyIDLock // // Attempts to perform a semaphore lock on the indicated tablename and Key ID. //---------------------------------------------------------------------------------------------------------------------- Service GetKeyIDLock(TableName, KeyID, IgnoreSelfLock) HaveLock = False$ ; // Assume false for now. If TableName NE '' AND KeyID NE '' then If IgnoreSelfLock NE True$ then IgnoreSelfLock = False$ TableHandle = Database_Services('GetTableHandle', TableName) If Error_Services('NoError') then Lock Tablehandle, KeyID then HaveLock = True$ end else If IgnoreSelfLock EQ True$ then Status = Status() If Status EQ 1 then HaveLock = True$ end end end end end else Error_Services('Add', 'TableName or KeyID argument was missing in the ' : Service : ' service.') end Response = HaveLock end service //---------------------------------------------------------------------------------------------------------------------- // ReleaseKeyIDLock // // Attempts to release a semaphore lock on the indicated tablename and Key ID. //---------------------------------------------------------------------------------------------------------------------- Service ReleaseKeyIDLock(TableName, KeyID) LockReleased = False$ ; // Assume false for now. If TableName NE '' AND KeyID NE '' then TableHandle = Database_Services('GetTableHandle', TableName) If Error_Services('NoError') then UnLock Tablehandle, KeyID then LockReleased = True$ end else Error_Services('Add', 'Unable to unlock the ' : KeyID : ' Key ID from the ' : TableName : ' table in the ' : Service : ' service. Error = ' : @File_Error<1>) end end end else Error_Services('Add', 'TableName or KeyID argument was missing in the ' : Service : ' service.') end Response = LockReleased end service //---------------------------------------------------------------------------------------------------------------------- // SearchIndex // // TableName. The linear hash database table name. - [REQUIRED] // ColumnName. The indexed column to search against. - [REQUIRED] // SearchValue. The value being searched for. - [REQUIRED] // UpdateIndex. Boolean flag to determine if the index for the indicated column should be updated before searching. // - [OPTIONAL] // // Returns an @FM delimited list of Key IDs that match the search value. //---------------------------------------------------------------------------------------------------------------------- Service SearchIndex(TableName, ColumnName, SearchValue, UpdateIndex) If UpdateIndex NE True$ then UpdateIndex = False$ ServiceKeyID := '*' : TableName : '*' : ColumnName : '*' : SearchValue ServiceKeyID = SRP_Encode(ServiceKeyID, 'BASE64') * KeyIDList = Memory_Services('GetValue', ServiceKeyID, True$, 5) KeyIDList = '' If TableName NE '' AND ColumnName NE '' AND SearchValue NE '' then If KeyIDList EQ '' then DictTableHandle = Database_Services('GetTableHandle', 'DICT.' : TableName) If Error_Services('NoError') then Set_Status(0) If UpdateIndex then Update_Index(TableName, ColumnName 0) Set_Status(0) Btree.Extract(ColumnName : @VM : SearchValue : @FM, Tablename, DictTableHandle, KeyIDList, 'S', Flag) If Flag EQ 0 then Convert @VM to @FM in KeyIDList Memory_Services('SetValue', ServiceKeyID, KeyIDList) end else Error_Services('Add', 'Error in Btree.Extract search from the ' : TableName : ' table in the ' : Service : ' service.') end end end end else Error_Services('Add', 'TableName, ColumnName, or SearchValue argument was missing in the ' : Service : ' service.') end Response = KeyIDList end service //---------------------------------------------------------------------------------------------------------------------- // CalculateColumn // // Called directly from within a calculation column. The name of the table and column is derived from the call stack // and the associated table commuter, if it exists, is called with the appropriate arguments. //---------------------------------------------------------------------------------------------------------------------- Service CalculateColumn() Response = '' ColumnName = '' RetStack = RetStack() For Each Item in RetStack using @FM If Index(Item, 'DICT.MFS', 1) then ColumnName = Item[2, \00\, 1] CharPos = BCol2() + 1 TableHandle = Item[CharPos, GetByteSize(Item), 1] Locate TableHandle<1, 2> in @TABLES(TAB_HANDLE$) using @FM setting fPos then TableName = @TABLES(0) ; // This technically returns the dictionary, but DICT. will be removed. TableName[1, 5] = '' end end Until (ColumnName NE '') OR (Item EQ '') Next Item If TableName NE '' then TableCommuter = Database_Services('GetTableCommuter', TableName) If TableCommuter NE '' then Response = Function(@TableCommuter('CalculateColumn', ColumnName)) end end end service //---------------------------------------------------------------------------------------------------------------------- // GetTableCommuter // // Returns the name of the indicated table's commuter module if it exists. If it does not exist then an empty string // will be returned. //---------------------------------------------------------------------------------------------------------------------- Service GetTableCommuter(TableName) ServiceKeyID := '*' : TableName TableCommuter = Memory_Services('GetValue', ServiceKeyID) If TableCommuter EQ '' then ObjExists = False$ ; // Assume the object code for the action handler does not exist for now. For Each AppID in @AppId If AppID _EQC 'SYSPROG' then SysObjKey = '$' : TableName : '_ACTIONS' end else SysObjKey = '$' : TableName : '_ACTIONS' : '*' : AppID end ObjExists = Memory_Services('KeyExists', SysObjKey) Until ObjExists Next AppID If Not(ObjExists) then For Each AppID in @AppId If AppID _EQC 'SYSPROG' then SysObjKey = '$' : TableName : '_ACTIONS' end else SysObjKey = '$' : TableName : '_ACTIONS' : '*' : AppID end OrigFileError = @FILE.ERROR @FILE.ERROR = '' BFS = 'RTP57' // The handle to SYSOBJ is used to find object code before it gets called Call @BFS(2, BFS, @FILE_SYSOBJ<1, 2>, SysObjKey, FMC, SysObjRecord, ActionStatus) @FILE.ERROR = OrigFileError If ActionStatus then ObjExists = True$ Until ObjExists Next AppID end If (ObjExists) then TableCommuter = TableName : '_ACTIONS' Memory_Services('SetValue', ServiceKeyID, TableCommuter) end end Response = TableCommuter end service //---------------------------------------------------------------------------------------------------------------------- // GetUserLocks // // Returns a dynamic array of user lock information. Note, this can only be done with the UD 5. This can also cause // instability with the current session and may require the Task Manager to close the session. //---------------------------------------------------------------------------------------------------------------------- Service GetUserLocks() UserLocks = RTI_LH_Info(CMD_LOCKS_INFO$, '') Response = UserLocks end service //---------------------------------------------------------------------------------------------------------------------- // IsKeyIDLocked // // Returns a Boolean flag of the lock status for the indicated table and Key ID. //---------------------------------------------------------------------------------------------------------------------- Service IsKeyIDLocked(TableName, KeyID, IgnoreSelfLock=BOOLEAN) If IgnoreSelfLock NE True$ then IgnoreSelfLock = False$ KeyIDLocked = False$ ; // Assume false for now. If (TableName NE '') AND (KeyID NE '') then Open TableName to hTable then Lock hTable, KeyID then // Able to lock Key ID. Unlock it right away. Unlock hTable, KeyID else Null end else // Unable to lock Key ID. Evaluate the type of lock. LockType = Status() If LockType EQ 0 then // Lock exists on another station. KeyIDLocked = True$ end else // Lock exists on this station. Check to see if the Ignore Self Lock flag is set. If Not(IgnoreSelfLock) then KeyIDLocked = True$ end end end else Error_Services('Add', 'Error opening the ' : TableName : ' table in the ' : Service : ' service.') end end else Error_Services('Add', 'TableName or KeyID argument was missing in the ' : Service : ' service.') end Response = KeyIDLocked end service //---------------------------------------------------------------------------------------------------------------------- // IsKeyIDSelfLocked // // Returns a Boolean flag of the self-lock status for the indicated table and Key ID. //---------------------------------------------------------------------------------------------------------------------- Service IsKeyIDSelfLocked(TableName, KeyID) KeyIDSelfLocked = False$ ; // Assume false for now. If (TableName NE '') AND (KeyID NE '') then Open TableName to hTable then Lock hTable, KeyID then // Able to lock Key ID. Unlock it right away. Unlock hTable, KeyID else Null end else // Unable to lock Key ID. Evaluate the type of lock. LockType = Status() If LockType EQ 1 then // This Key ID is self-locked. KeyIDSelfLocked = True$ end end end else Error_Services('Add', 'Error opening the ' : TableName : ' table in the ' : Service : ' service.') end end else Error_Services('Add', 'TableName or KeyID argument was missing in the ' : Service : ' service.') end Response = KeyIDSelfLocked end service //---------------------------------------------------------------------------------------------------------------------- // UnlockKeyID // // Attempts to unlock the indicated Key ID from the indicated Table Name. Note, this can only be done with the UD 5. //---------------------------------------------------------------------------------------------------------------------- Service UnlockKeyID(TableName, KeyID) KeyIDUnlocked = False$ ; // Assume false for now. Convert @Lower_Case to @Upper_Case in TableName If (TableName NE '') AND (KeyID NE '') then // First, do a sanity check to confirm that there is a lock on this Key ID. IsKeyIDLocked = Database_Services('IsKeyIDLocked', TableName, KeyID, False$) If Error_Services('NoError') AND (IsKeyIDLocked EQ False$) then // Key ID was not locked. KeyIDUnlocked = True$ end If KeyIDUnlocked NE True$ then // Key ID is still presumed to be locked. VolumePath = '' FileName = '' // Resolve the volume path for this table. hTableFull = Database_Services('ReadDataRow', 'SYSTABLES', TableName) VolumeName = hTableFull<1> VolumeRow = Database_Services('ReadDataRow', 'SYSVOLUMES', VolumeName) VolumePath = VolumeRow[-1, 'B' : @FM] VolumePath = VolumePath[-1, 'B' : \0D\] VolumePath[1, 12] = '' ; // Strip off the preceding bytes. If SRP_Path('IsRelative', VolumePath) then VolumePath = SRP_Path('Combine', Drive(), VolumePath) // Check for only a single '\' character. Add another if necessary so this is a proper UNC path. // This is a workaround for this version of SRP_Path. If VolumePath[1, 1] EQ '\' AND VolumePath[2, 1] NE '\' then VolumePath = '\' : VolumePath end VolumePath = SRP_Path('RemoveFilename', VolumePath) // Make sure there is a backslash since the RTI_LH_INFO API seems to use this. VolumePath = SRP_Path('AddBackslash', VolumePath) // Resolve the filename for this table. hTableFull = Database_Services('ReadDataRow', 'SYSTABLES', TableName) FileName = hTableFull[-1, 'B' : @FM] FileName = FileName[-1, 'B' : \0D\] FileName = FileName[1, @VM] If FileName _NEC 'SYSREPOS' then FileName[1, 12] = '' ; // Strip off the preceding bytes. FileName = FileName[-1, 'B' : '\'] // Make sure the filename is well formed. Begin Case Case (FileName[-3, 3] _EQC '.LK') OR (FileName[-3, 3] _EQC '.OV') FileName[-3, 3] = '' Case FileName _EQC 'SYSREPOS' FileName = 'REVREPOS' End Case If (VolumePath NE '') AND (FileName) NE '' then // Attempt to unlocked the Key ID. RTI_LH_Info(CMD_UNLOCK$, VolumePath, FileName, KeyID, FileName) // Confirm that the Key ID was unlocked. IsKeyIDLocked = Database_Services('IsKeyIDLocked', TableName, KeyID, False$) If Error_Services('NoError') AND (IsKeyIDLocked EQ False$) then // Key ID was not locked. KeyIDUnlocked = True$ end else // Unable to unlock the Key ID which could be because it is locked by this station. Try using the // Unlock statement. KeyIDUnlocked = Database_Services('ReleaseKeyIDLock', TableName, KeyID) end end else Error_Services('Add', 'No valid VolumePath or FileName was available in the ' : Service : ' service.') end end end else Error_Services('Add', 'TableName or KeyID argument was missing in the ' : Service : ' service.') end Response = KeyIDUnlocked end service //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Internal GoSubs ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////