//-----------------------------------------------------------------------------> // // CkIndex.Pkg // // Version: 1.0.0 // // The purpose of this package is to check all indexes of one or more data files // in case of a need for reindexing. Of course one can simply reindex if the // need is suspected, but in a production situation where the database isn't // in-house, the down-time to reindex can be expensive both in terms of // production time lost and customer confidence. // // This utility can be run with all users on, it doesn't lock files or save data. // // External calls // // File_Loop [file #] [Message Object #] // // If file # is 0 all files will be checked, if a valid number, only // that file will be checked. // // If the Message Object # is populated, the appropriate user screen // message is returned to that object. This is useful for displaying // busybox messages in the calling view rather than with Sentinel. // // Example: Send File_Loop to oIndex_Check iFile iMsgObj // // Show_Errors // // Dumps the error array to an output box // // Example: Send Show_Errors to oIndex_Check to iRC // //-----------------------------------------------------------------------------> Class cIndex_Check Is A Message Procedure Construct_Object // Used to hold field data from each data record Object oField_Array is an Array End_Object // oField_Array // Holds index number where error found Object oIndex_Errors is an Array End_Object // Index_Errors // All errors found Object oErrors Is an Array End_Object End_Procedure //---------------------------------------------------------------------> // Check_File -- Main checking loop, called from file_loop //---------------------------------------------------------------------> Procedure Check_File Handle hFile Integer iMsgObj Integer hField hFields iBadIndex iBadData iRC hOverlap Integer iRecnum iCkRecnum iIndex iIndexes iSegment iSegments iType String sVal sName Number nVal Date dVal Boolean bErr bWorking bVal get_Attribute DF_FILE_LOGICAL_NAME of hFile to sName If (iMsgObj > 0) Set Value of iMsgObj item 0 to ("Working on "+sName) // Clear arrays from last use. Send Delete_Data to oField_Array Send Delete_Data to oIndex_Errors Move 0 to iBadData Move 0 to iBadIndex // Get_Attribute DF_FILE_NUMBER_FIELDS of hFile to hFields Get_Attribute DF_FILE_LAST_INDEX_NUMBER of hFile to iIndexes Clear hFile vFind hFile 0 GT While (Found and iBadIndex = 0) Get_Field_Value hFile 0 to iRecnum // Move all Field Values to an Array For hField from 0 to HFields Get_Attribute DF_FIELD_TYPE of hFile hField to iType // No do text and BCD fields, they can't be indexed If (iType = DF_BCD or iType = DF_DATE or iType = DF_ASCII or DF_OVERLAP) Begin Get_Field_Value hFile hField to sVal Set Array_Value of oField_Array item hField to sVal End Loop For iIndex from 1 to iIndexes Get_Attribute DF_INDEX_NUMBER_SEGMENTS of hFile iIndex to iSegments // In case there are "holes" in the list of indexes // -- 7 total indexes but no #4... If (iSegments > 0) Begin // use bWorking to make sure we are still checking an index // We set it to FALSE on a new record. If we have an index // to check, we set it to TRUE so we know it did something. // If we don't check any indexes for that record, then we // no longer need to continue looking because all indexes // are bad. Move (FALSE) to bWorking // Skip indexes that have already errored Get Integer_Value of oIndex_Errors item iIndex to bErr If Not (bErr) Begin Move (TRUE) to bWorking // Load each index segment from the stored values Clear hFile For iSegment from 1 to iSegments // Check the segment type so we use the right variable Get_Attribute DF_INDEX_SEGMENT_FIELD of hFile iIndex iSegment to hField Get_Attribute DF_FIELD_TYPE of hFile hField to iType If (iType = DF_BCD) Begin Get String_Value of oField_Array item hField to nVal Set_Field_Value hFile hField to nVal End Else If (iType = DF_Date) Begin Get String_Value of oField_Array item hField to dVal Set_Field_Value hFile hField to dVal End Else If (iType = DF_ASCII) Begin Get String_Value of oField_Array item hField to sVal Set_Field_Value hFile hField to sVal End Else If (iType = DF_OVERLAP) Begin Move hField to hOverlap // Check each field in the file to see if it is in the overlap For hField from 0 to hFields // skip the overlap field If (hField <> hOverlap) Begin Get_Attribute DF_FIELD_OVERLAP of hFile hOverlap hField to bVal If (bVal) Begin Get_Attribute DF_FIELD_TYPE of hFile hField to iType If (iType = DF_BCD) Begin Get String_Value of oField_Array item hField to nVal Set_Field_Value hFile hField to nVal End Else If (iType = DF_Date) Begin Get String_Value of oField_Array item hField to dVal Set_Field_Value hFile hField to dVal End Else If (iType = DF_ASCII) Begin Get String_Value of oField_Array item hField to sVal Set_Field_Value hFile hField to sVal End End End Loop End Loop // All segments //-----------------------------------------------> // Find the next record in the index being tested //-----------------------------------------------> vFind hFile iIndex EQ // Check for a duplicate record -- key data is the same, // but recnum found might be different from the intended one Get_Field_Value hFile 0 to iCkRecnum If (Finderr or (Found and iRecnum <> iCkRecnum)) Begin // Got an error, first check to see if the record still exists Clear hFile Set_Field_Value hFile 0 to iRecnum vFind hFile 0 EQ // If it does, report an index problem If (Found) Begin Set Array_Value of oIndex_Errors item iIndex to TRUE Get Item_Count of oErrors to iRC Set Array_Value of oErrors item iRC to; (string("File "+trim(sName)+", index "+string(iIndex)+" has errors at record "+string(iRecnum))) Move 1 to iBadIndex End // Otherwise go on End End End // # Segments Loop // All indexes // Last record number Clear hFile Set_Field_Value hFile 0 to iRecnum vFind hFile 0 GT [Finderr] Break Loop // File by recnum // Close hFile End_Procedure // Check_File //---------------------------------------------------------------------> // Called from the calling procedure for showing errors //---------------------------------------------------------------------> Function Show_Errors Returns Integer Local Integer iCount iICount Local String sLine Move (Item_Count(oErrors(Self)) - 1) to iIcount For iCount From 0 to iIcount Get Array_Value of oErrors Item iCount to sLine Showln sLine Loop Function_Return iIcount End_Function //---------------------------------------------------------------------> // Do all files in filelist other than alias files. // To do a single file, call with the file number. All files, leave // hFile = 0. // // hFile -- file number // iMsgObj -- Object ID of display object for showing messages to the user //---------------------------------------------------------------------> Procedure File_Loop Integer hFile Integer iMsgObj Integer iRC iICount String sName sDataPath Get CurrentDataPath of ProgramWorkspace to sDataPath // Single file If (hFile > 0) Begin get_Attribute DF_FILE_LOGICAL_NAME of hFile to sName Get Get_File_Exists (sDataPath+"\"+sName+'.dat') to iRC If iRC Begin // Check to see if file can be opened Send Ignore_Error to Error_Info_Object 4177 Open hFile If Not [Found] Begin Get Item_Count of oErrors to iRC Set Array_Value of oErrors item iRC to; (string("File "+(String(hFile))+" could not be opened.")) End Else Send Check_File hFile iMsgObj End Else Send Stop_Box "File doesn't exist." End // Whole filelist else Begin repeat get_Attribute DF_FILE_NEXT_USED of hFile to hFile if (hFile <> 0) begin //-----------------------------------------------> // Use logical rather than root so alias files // are not checked //-----------------------------------------------> // Check to see if file can be opened get_Attribute DF_FILE_LOGICAL_NAME of hFile to sName Get Get_File_Exists (sDataPath+"\"+sName+'.dat') to iRC If iRC Begin Send Ignore_Error to Error_Info_Object 4177 Open hFile If Not [Found] Begin Get Item_Count of oErrors to iRC Set Array_Value of oErrors item iRC to; (string("File "+(String(hFile))+" could not be opened.")) End Else Send Check_File hFile iMsgObj End End until (hFile=0) end Move (Item_Count(oErrors(Self))) to iIcount if (iMsgObj > 0) Begin If (iIcount > 0) Set Value of iMsgObj item 0 to ("All done, errors have been found.") Else Set Value of iMsgObj item 0 to ("All done, no errors found.") end End_Procedure End_Class Object oIndex_Check Is A cIndex_Check End_Object