COMPILE FUNCTION NextKey(TableName) /*********************************************************************************************************************** Name : NextKey Description : Routine to find next sequential key for a table. January 5, 1997 - John C. Henry, J.C. Henry, Inc. Parameters : TableName [in] -- Name of the database table for which the next sequential key is being requested NextNo [out] -- Next sequential key for the given Tablename. History : (Date, Initials, Notes) 01/05/97 jch Original programmer. 11/13/18 djs Supplemented Set_Status(error) with Error_Services for more robust error reporting due to the fact that this function is periodically returning 0 as a key when two users attempt to access the same resource (%SK% column) simultaneously. Updated the Lock statement to delay before reattempting when failing based upon a set time delay (10 seconds currently) rather than a number of loop cycles as originally designed. ***********************************************************************************************************************/ #pragma precomp SRP_PreCompiler $Insert LOGICAL Declare Function Msg, Set_FSError, GetTickCount, Error_Services, Environment_Services, Logging_Services Declare Subroutine ErrMsg, Msg, Yield, Winyield, Sleepery, Error_Services, Logging_Services LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\NextKey' LogDate = Oconv(Date(), 'D4/') LogTime = Oconv(Time(), 'MTS') LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' NextKeyLog.csv' Headers = 'Logging DTM' : @FM : 'User': @FM : 'Tablename' : @FM : 'Notes' objLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, Comma$, Headers, '', False$, False$) LoggingDTM = LogDate : ' ' : LogTime LogData = '' LogData<1> = LoggingDTM LogData<2> = @User4 LogData<3> = Tablename LogData<4> = 'Beginning NextKey routine.' Logging_Services('AppendLog', objLog, LogData, @RM, @FM) ErrorTitle = "Error in Function 'NEXTKEY' " OPEN 'DICT.':TableName TO DictVar ELSE Mesg = 'Unable to open DICT.':TableName:' Table.' stat = Set_Status(1,'STPROC',ErrorTitle:@SVM:Mesg) Error_Services('Add', Mesg) RETURN 0 END OPEN TableName TO TableVar ELSE Mesg = 'Unable to open ':TableName:'Table.' stat = Set_Status(1,'STPROC',ErrorTitle:@SVM:Mesg) Error_Services('Add', Mesg) LogData<4> = Mesg Logging_Services('AppendLog', objLog, LogData, @RM, @FM) RETURN 0 END TimeExpired = False$ Start = GetTickCount() Locked = 0 Tries = 0 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // RDS Zero Bug Fix - DJS - Released for UAT on 11/14/2018 Loop TimeElapsed = GetTickCount() - Start If TimeElapsed > 120000 then TimeExpired = True$ ; // 120000ms = 2 minutes Lock DictVar,"%SK%" then Locked = True$ LogData<4> = '%SK% record locked.' Logging_Services('AppendLog', objLog, LogData, @RM, @FM) end else LogData<4> = 'Failed to lock %SK% record. Reattempting...' Logging_Services('AppendLog', objLog, LogData, @RM, @FM) // Pause for a moment to allow the column to be unlocked by the lock holder. // Yield() allows for pending Windows messages to be handled. Sleepery(10) WinYield() Yield();Yield();Yield();Yield();Yield();Yield();Yield();Yield() end Until Locked or TimeExpired repeat If TimeExpired then Mesg = 'Unable to lock "%SK%" record in DICT.':TableName:' table.' stat = Set_Status(-1,'STPROC',ErrorTitle:@SVM:Mesg) Error_Services('Add', Mesg) LogData<4> = Mesg Logging_Services('AppendLog', objLog, LogData, @RM, @FM) return 0 end If RowExists('DICT.':TableName, '%SK%') then LogData<4> = '%SK% record exists. Attempting to read next key in sequence...' Logging_Services('AppendLog', objLog, LogData, @RM, @FM) // This is the common case. Sequential counter record already exists (i.e. the table already exists and a // sequential counter record is already in the database). Read NextNo from DictVar, '%SK%' then // Log new key LogData<4> = NextNo:' key read from %SK% record.' Logging_Services('AppendLog', objLog, LogData, @RM, @FM) end else // Failed to read the '%SK%' record. Record error on error stack (Error_Services) and return 0 (failure). ErrorCode = Status() ErrorMessage = "Failed to read '%SK%' record from DICT.":TableName:". Error code: ":ErrorCode:". File error: ":@FILE_ERROR:"." Error_Services('Add', ErrorMessage) LogData<4> = Mesg Logging_Services('AppendLog', objLog, LogData, @RM, @FM) RETURN 0 end end else LogData<4> = '%SK% record does not exist. Creating record and returning key value 1.' Logging_Services('AppendLog', objLog, LogData, @RM, @FM) // This is a new table and therefore we need to create a %SK% record to store a sequential counter NextNo = 1 end WRITE NextNo+1 ON DictVar,'%SK%' ELSE Mesg = "Unable to update next Sequential Number in DICT.":TableName:"." stat = Set_Status(-1,'STPROC',ErrorTitle:@SVM:Mesg) Error_Services('Add', Mesg) LogData<4> = Mesg Logging_Services('AppendLog', objLog, LogData, @RM, @FM) RETURN 0 END UNLOCK DictVar,'%SK%' ELSE Mesg = 'Unable to unlock "%SK%" record in DICT.':TableName:' Table.' stat = Set_Status(-1,'STPROC',ErrorTitle:@SVM:Mesg) Error_Services('Add', Mesg) LogData<4> = Mesg Logging_Services('AppendLog', objLog, LogData, @RM, @FM) RETURN 0 END LogData<4> = 'Ending NextKey routine.' Logging_Services('AppendLog', objLog, LogData, @RM, @FM) RETURN NextNo