Function Database_Services(@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 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. 11/06/17 fjt [SRPFW-195] Added to FW v16.0.12 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. 01/22/19 fjt [SRPFW-195] Updated to include codes in error reporting 02/28/19 dmb [SRPFW-195] Add safety check in GetTableHandle to make sure the table's full handle is still in @TABLES before using the cached handle. 03/12/19 dmb [SRPFW-270] Add ClearTableHandle service so it is easy to remove the cached table handle when situations such as aliasing a table from a different volume occurs. 03/12/19 dmb [SRPFW-270] Add SetTableAlias service to alias a table and call the ClearTableHandle service if thealias was successful. 05/03/19 dmb [SRPFW-273] Initialize TableName in the CalculateColumn service to prevent potential VNAV errors. 05/11/20 dmb [SRPFW-313] Add GetTableNames service. 06/29/20 dmb [SRPFW-282] Update the GetTableNames service to support ExcludeDictionaries and ExcludeIndexes arguments. 08/04/20 djs Commented out UnlockKeyID service. This service causes OpenInsight to crash. Use ReleaseKeyIDLock instead. ***********************************************************************************************************************/ #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, SRP_Array Declare subroutine Memory_Services, Database_Services, Verify_LH, SRP_Stopwatch, Btree.Extract, Update_Index, Set_Status Declare subroutine RTI_LH_Info, Alias_Table, Push.Select, Pop.Select 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 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //---------------------------------------------------------------------------------------------------------------------- // 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 //---------------------------------------------------------------------------------------------------------------------- // 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 = '' TableName = '' 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 //---------------------------------------------------------------------------------------------------------------------- // ClearTableHandle // // TableName. The linear hash database table name. - [REQUIRED] // // Clears the table handle array array from cache. This will force the GetTableHandle service to call the Open statement // again. //---------------------------------------------------------------------------------------------------------------------- Service ClearTableHandle(TableName) If TableName NE '' then ServiceKeyID = ServiceModule : '*GetTableHandle' ServiceKeyID := '*' : TableName Memory_Services('SetValue', ServiceKeyID, '') end else Error_Services('Add', 'TableName 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 // [SRPFW-195] Updated / Added by GAC 18 May 2018 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. Error = ' : @File_Error<1>) end end * If Error_Services('NoError') 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 //---------------------------------------------------------------------------------------------------------------------- // 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 //---------------------------------------------------------------------------------------------------------------------- // 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 ActionStatus = '' 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 //---------------------------------------------------------------------------------------------------------------------- // 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) TableHandle = '' If TableName NE '' then ServiceKeyID := '*' : TableName Locate TableName in @Tables(tab_name$) using @FM setting fPos then If @Tables(tab_handle$) NE '' then // Only check for a cached handle if the table and its handle is still in @TABLES. Otherwise the handle is // probably stale and will hang OI when utilized. TableHandle = Memory_Services('GetValue', ServiceKeyID) end end 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 end else Error_Services('Add', 'TableName was missing in the ' : Service : ' service.') end Response = TableHandle end service //---------------------------------------------------------------------------------------------------------------------- // GetTableNames // // ApplicationTablesOnly - Boolean flag to determine if only application database tables should be returned (i.e., // exclude SYSTEM and non-RTP57 tables). Default is True. // ExcludeDictionaries - Boolean flag to determine if dictionary tables should be excluded. Default is False. // ExcludeIndexes - Boolean flag to determine if index tables should be excluded. Default is False. // // Returns an @FM list of currently attached OpenInsight database tables. //---------------------------------------------------------------------------------------------------------------------- Service GetTableNames(ApplicationTablesOnly=BOOLEAN, ExcludeDictionaries=BOOLEAN, ExcludeIndexes=BOOLEAN) TableNames = '' ; // Initialize the return variable. If ApplicationTablesOnly NE False$ then ApplicationTablesOnly = True$ If ExcludeDictionaries NE True$ then ExcludeDictionaries = False$ If ExcludeIndexes NE True$ then ExcludeIndexes = False$ TableNames = @Tables(tab_name$) TableTypes = @Tables(tab_vol_name$) If ApplicationTablesOnly EQ True$ then Tables = '' For Each TableType in TableTypes using @FM setting fPos TableName = TableNames If (TableType[1, 'F*'] EQ 'RTP57') AND Not(TableType EQ 'RTP57*REVBOOT') AND Not(TableType EQ 'RTP57*O4WFILES') AND Not(TableType EQ 'RTP57*AREV_DIR') then Tables := TableName : @FM end Next TableType Tables[-1, 1] = '' Transfer Tables to TableNames end If ExcludeDictionaries EQ True$ then Tables = '' For Each TableName in TableNames using @FM If TableName[1, 5] NE 'DICT.' then Tables := TableName : @FM end Next TableType Tables[-1, 1] = '' Transfer Tables to TableNames end If ExcludeIndexes EQ True$ then Tables = '' For Each TableName in TableNames using @FM If TableName[1, 1] NE '!' then Tables := TableName : @FM end Next TableType Tables[-1, 1] = '' Transfer Tables to TableNames end TableNames = SRP_Array('SortRows', TableNames, 'AL1', 'LIST', @FM, @VM) Response = TableNames 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(tab_name$) using @FM setting fPos then TableProperties<1> = @TABLES(tab_account$) ; // DatabaseID TableProperties<2> = @TABLES(tab_file_sys$) ; // MFS/BFS List VolumeID = @TABLES(tab_vol_name$) ; // Volume ID Locate VolumeID in @VOLUMES(vol_name$) using @FM setting fPos then TableProperties<3> = @VOLUMES(vol_label$) ; // Volume Label TableProperties<4> = @VOLUMES(vol_location$) ; // Volume Path TableProperties<5> = @VOLUMES(vol_file_sys$) ; // 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 //---------------------------------------------------------------------------------------------------------------------- // 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 //---------------------------------------------------------------------------------------------------------------------- // 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 //---------------------------------------------------------------------------------------------------------------------- // 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 // [SRPFW-195] 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. Error = ' : @File_Error<1>) end end end end else Error_Services('Add', 'TableName or KeyID argument was missing in the ' : Service : ' service.') end Response = DataRow 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 = '' 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, False$, True$) Set_Status(0) Flag = '' 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 //---------------------------------------------------------------------------------------------------------------------- // SetTableAlias // // TableName - The linear hash database table name. - [Required] // AliasName - The alias name being set. - [Required] // Volume - The location path or volume name where the table exists. - [Required] // DatabaseID - Database ID of the table being aliased. Defaults to the current Database ID (@DBID) - [Optional] // // Attempts to create an alias for the indicated table, volume, and database. It returns a True$ if successful or a // False$ if unsuccessful. //---------------------------------------------------------------------------------------------------------------------- Service SetTableAlias(TableName, AliasName, Volume, DatabaseID) Success = False$ ; // Assume not successful for now. If (TableName NE '') AND (AliasName NE '') AND (Volume NE '') then Set_Status(0) If DatabaseID EQ '' then DatabaseID = @DBID Push.Select(F1, F2, F3, F4) ; // Protect cursors in case Alias_Table fails. Alias_Table(Volume : '', DatabaseID : '', TableName : '', AliasName : '') Pop.Select(F1, F2, F3, F4) ; // Restore cursors. StatusCode = '' If Get_Status(StatusCode) then Error_Services('Add', 'Error calling the Alias_Table routine in the ' : Service : ' service. Status Code : ' : StatusCode) end else // Setting an alias could changes the handle so clear the cached handle to avoid it being stale. Success = True$ Database_Services('ClearTableHandle', AliasName) end Set_Status(0) end else Error_Services('Add', 'TableName, AliasName, or Volume argument was missing in the ' : Service : ' service.') end Response = Success 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) * 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. * hTable = Database_Services('GetTableHandle', TableName) * Unlock hTable, KeyID then * KeyIDUnlocked = True$ * end else * Error_Services('Add', 'Unable to unlock ' : KeyID : ' from the ' : TableName : ' table in the ' : Service : ' service.') * end * 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 //---------------------------------------------------------------------------------------------------------------------- // 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 //---------------------------------------------------------------------------------------------------------------------- // VerifyLHAll // // Performs a health check against 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 //---------------------------------------------------------------------------------------------------------------------- // 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 // [SRPFW-195] Updated / added by GAC 18 May 2018 If Error_Services('NoError') then Write DataRow to TableHandle, KeyID then Memory_Services('SetValue', ServiceModule : '*' : 'ReadDatarow' : '*' : TableName : '*' : KeyID, DataRow) end else ErrorMsg = Error_Services('GetMessage') Error_Services('Add', 'Error writing ' : KeyID : ' to the ' : TableName : ' table in the ' : Service : ' service. Error message: ':ErrorMsg) end end * If Error_Services('NoError') then If IgnoreAllLocks EQ False$ then Database_Services('ReleaseKeyIDLock', TableName, KeyID) end * 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 //---------------------------------------------------------------------------------------------------------------------- // 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) 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. hTable = Database_Services('GetTableHandle', TableName) Unlock hTable, KeyID then KeyIDUnlocked = True$ end else Error_Services('Add', 'Unable to unlock ' : KeyID : ' from the ' : TableName : ' table in the ' : Service : ' service.') end 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 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////