IBM Support

Check Damage on Physical Files (CHKPF)

Troubleshooting


Problem

This document provides source for an example program that checks each physical file or table of a library for damaged rows or records.
Also see TechNote Recovering Records from Damaged Files and Index Check Tool for checking access path issues.

Resolving The Problem

This document provides source for an example program that checks each physical file or table of a library for damaged rows or records. Assistance with this sample program is beyond the scope of Support Line service.

The Check Damage on Physical Files (CHKPF) command allows you to check each physical file or table of a library for rows or records that cannot be read by the operating system. The command runs over a specific library or all libraries on the system. The command checks only the physical files and report errors. It does not perform any recovery action.

CHKPF only checks the record level structures. It doesn't check the integrity of field level data. CHKPF will determine if the DENT byte for a record is a valid value or not. If not then the record will be flagged damaged. But there can be instances of the DENT byte value being valid however due to data shifting or other problems, the actual data located within fields my not be valid for the specific data type anymore. CHKPF cannot determine these instances where the field data is no longer valid for the data type. Only by mapping this data back into the same data types would it cause data mapping errors. Since the CHKPF does not write the data back into a similar file, this level of damage is not detected. There are no IBM tools to determine this level of damage. No errors, VLOGs, or tools would indicate. Only by customer or someone familiar with the data manually looking through the data could errors like this be noticed.

So to be clear, CHKPF will not detect field level damage where the data may no longer be valid for the data type of the field. It also will not detect any corruption of data in fields such that the data value is still valid for the field, but no longer the same as what it was prior to the damage.

The command will not look for damage in other file systems (for example, /QDLS, or /QNTS or /QOPT) nor will it scan for damage to other object types. This source provided here is a more robust version of the example provided in APAR II10690. Use SNDPTFORD to get the cover letter for II10690.

 
Caution: This program may not be included in programs for resale. The source is provided as is. IBM offers a consulting agreement to assist with implementing this program, or contact your software service provider for assistance.

The CHKPF command uses the system cross-reference file (QADBXREF in library QSYS) to determine the physical files to be checked for each library. If the system cross-reference file is damaged, this command does not run. The Reclaim Database Cross Reference files (RCLDBXREF *FIX) or Reclaim Storage (RCLSTG SELECT(*DBXREF)) command must be run to correct the system cross-reference files prior to running the CHKPF command.

The CHKPF command can be run in batch or interactively. Physical files that are found to have unreadable rows are identified by a message sent to the user profile message queue of the user profile running or submitting the CHKPF command. Physical files that are identified with unreadable records should be reviewed individually prior to performing any damage recovery. Refer to the Backup and Recovery Guide for the appropriate recovery technique.

Creating the CHKPF Command

To create the CHKPF command, do the following:
1. Create a source member of type TXT (CRTSRCPF) called CHKPF in source file QTXTSRC of library QGPL. Update the source member with the following statement:

CREATE TABLE QGPL/CHKPF (DBXLIB CHAR (10) NOT NULL WITH DEFAULT,
DBXFIL CHAR (10) NOT NULL WITH DEFAULT)
2. Create table CHKPF in library QGPL by running the SQL statement entered into source member CHKPF:

RUNSQLSTM SRCFILE(QGPL/QTXTSRC) SRCMBR(CHKPF) COMMIT(*NONE)
3. Create a source member of type CLP called CHKPF in source file QCLSRC of library QGPL. Update the source member with the following statements:

If you have the QMGTOOLS (MustGather Tools) library on your IBM i (see this TechNote for information on QMGTOOLS) you may already have this source. Here's how to check

a) ADDLIBLE QMGTOOLS
b) GO MG
c) 12. Display build date
- if you have a "Build date and version" of 26Mar2016 or later, continue to (d)
d) WRKMBRPDM QMGTOOLS/QMGDBSQL

Else, here's the source you can copy and paste
   /* THE CHKPF COMMAND WILL USE CPYF TO READ EVERY RECORD OF EVERY    */
     /* PHYSICAL FILE OR TABLE OF A LIBRARY OR ALL LIBRARIES ON THE      */

      /* SYSTEM. UPON COMPLETION ANY PF'S WITH DATA ERRORS WILL BE        */
      /* IDENTIFIED. THESE PF'S SHOULD BE REVIEWED FOR POSSIBLE INVALID   */
      /* DATA CONTENTS OR DAMAGE.                                         */

                     PGM        PARM(&LIBRARY)
                     DCL        VAR(&LIBRARY) TYPE(*CHAR) LEN(10)
                     DCL        VAR(&MSGTXT) TYPE(*CHAR) LEN(512)
                     DCL        VAR(&MSGID) TYPE(*CHAR) LEN(7)
                     DCL        VAR(&MSGKEY) TYPE(*CHAR) LEN(4) VALUE('9999')
                     DCL        VAR(&MSGTXT1) TYPE(*CHAR) LEN(256)
                     DCL        VAR(&PFCNT) TYPE(*DEC) LEN(9 0)
                     DCL        VAR(&PFCNTA) TYPE(*CHAR) LEN(9)
                     DCL        VAR(&PFERR) TYPE(*DEC) LEN(9 0)
                     DCL        VAR(&PFERRA) TYPE(*CHAR) LEN(9)
                     DCL        VAR(&USER) TYPE(*CHAR) LEN(10)

        /* FILE CHKPF MUST BE CREATED PRIOR TO COMPILING THIS CL PROGRAM.  */
                     DCLF       FILE(CHKPF)

        /* MESSAGES OF FAILING FILES ARE SENT TO THE JOB'S USER PROFILE. */
                     RTVJOBA    USER(&USER)

        /* VALIDATE THE LIBRARY NAME. */
                     IF         COND(&LIBRARY *NE '*ALL') THEN(DO)
                     CHKOBJ     OBJ(&LIBRARY) OBJTYPE(*LIB)
                     MONMSG     MSGID(CPF0000) EXEC(DO)
                     CHGVAR     VAR(&MSGTXT) VALUE('Library ' *CAT &LIBRARY +
                                  *BCAT 'not found or not available.')
                     SNDPGMMSG  MSG(&MSGTXT) TOPGMQ(*PRV) TOMSGQ(*TOPGMQ) +
                                  MSGTYPE(*COMP)
                     GOTO       CMDLBL(ENDOFPGM)
                     ENDDO
                     ENDDO

        /* OPEN THE SYSTEM CROSS REFERENCE FILE FOR PROCESSING OF PF'S. */
                     OVRDBF     FILE(QADBXREF)
                     IF         COND(&LIBRARY *EQ '*ALL') THEN(DO)
                     OPNQRYF    FILE((QSYS/QADBXREF)) OPTION(*INP) +
                                  FORMAT(QGPL/CHKPF) QRYSLT('DBXATR = +
                                  %VALUES("PF" "TB")') KEYFLD(*FILE)
                     ENDDO
                     ELSE       CMD(DO)
                     OPNQRYF    FILE((QSYS/QADBXREF)) OPTION(*INP) +
                                  FORMAT(QGPL/CHKPF) QRYSLT('DBXLIB = ''' +
                                  *CAT &LIBRARY *CAT ''' *AND DBXATR = +
                                  %VALUES("PF" "TB")') KEYFLD(*FILE)
                     ENDDO

        /* OUTPUT THE PF'S TO BE CHECKED TO THE CHKPF FILE. */
                     DLTF       FILE(QTEMP/CHKPF)
                     MONMSG     MSGID(CPF0000)
                     CRTDUPOBJ  OBJ(CHKPF) FROMLIB(QGPL) OBJTYPE(*FILE) +
                                  TOLIB(QTEMP)
                     CPYFRMQRYF FROMOPNID(QADBXREF) TOFILE(QTEMP/CHKPF) +
                                  MBROPT(*REPLACE) FMTOPT(*NOCHK)
                     CLOF       OPNID(QADBXREF)
                     DLTOVR     FILE(QADBXREF)

        /* PROCESS THE RECORDS IN THE CHKPF FILE. */
                     OVRDBF     FILE(CHKPF) TOFILE(QTEMP/CHKPF)
         READ:       DLTF       FILE(QTEMP/&DBXFIL)
                                                     MONMSG     MSGID(CPF0000 CPD0000)
                     RCVF
                     MONMSG     MSGID(CPF0864) EXEC(GOTO CMDLBL(ENDREAD))
                     CHGVAR     VAR(&PFCNT) VALUE(&PFCNT + 1)
                     IF         COND(&DBXFIL *EQ 'CHKPF') THEN(GOTO +
                                  CMDLBL(READ))

        /* DELETE THE FILE IN QTEMP IF IT EXISTS. */
                     DLTF       FILE(QTEMP/&DBXFIL)
                     MONMSG     MSGID(CPF2105)

        /* CHECK THE PF BY COPYING IT TO A NEW FILE IN QTEMP. */
                     CPYF       FROMFILE(&DBXLIB/&DBXFIL) +
                                  TOFILE(QTEMP/&DBXFIL) FROMMBR(*ALL) +
                                  TOMBR(*FROMMBR) MBROPT(*REPLACE) +
                                  CRTFILE(*YES) FROMRCD(1) +
                                  INCCHAR(*RCD 1 *EQ '@#$%') +
                                  ERRLVL(0)

        /* ACCEPT EXPECTED ERROR CONDITIONS AND CONTINUE. */
                     MONMSG     MSGID(CPF2817) EXEC(DO)
                     RCVMSG     MSGTYPE(*LAST) RMV(*NO) KEYVAR(&MSGKEY) /* +
                                  Message CPF2817. */
         RECEIVE:    RCVMSG     MSGTYPE(*PRV) MSGKEY(&MSGKEY) +
                                  KEYVAR(&MSGKEY) MSG(&MSGTXT1) +
                                  MSGID(&MSGID) /* Actual failing message +
                                  ID. */
                     IF         COND(&MSGID *EQ 'CPF2868') THEN(GOTO +
                                  CMDLBL(READ)) /* No members in file. */
                     IF         COND(&MSGID *EQ 'CPF2883') THEN(GOTO +
                                  CMDLBL(RECEIVE)) /* Generic create error. */
                     IF         COND(&MSGID *EQ 'CPF320B') THEN(GOTO +
                                  CMDLBL(READ)) /* Data dictionary file. */
                     IF         COND(&MSGID *EQ 'CPF2833') THEN(GOTO +
                                  CMDLBL(TEST1)) /* Record length < 4. */
IF         COND(&MSGID *EQ 'CPF2869') THEN(GOTO +
                                  CMDLBL(READ)) /* Empty member. */
                     GOTO       CMDLBL(SNDERROR)
                     ENDDO
                     MONMSG     MSGID(CPF2952) EXEC(DO)
                     RCVMSG     MSGTYPE(*LAST) RMV(*NO) KEYVAR(&MSGKEY) /* +
                                  Message CPF2952. */
                     RCVMSG     MSGTYPE(*PRV) MSGKEY(&MSGKEY) +
                                  KEYVAR(&MSGKEY) MSG(&MSGTXT1) +
                                  MSGID(&MSGID) /* Actual failing message +
                                  ID. */
                     IF         COND(&MSGID *EQ 'CPF4234') THEN(GOTO +
                                  CMDLBL(READ)) /* I/O not allowed. */
                     GOTO       CMDLBL(SNDERROR)
                     ENDDO

        /* REPORT PF ERROR FOR ALL OTHER MESSAGE ID'S. */
                     MONMSG     MSGID(CPF0000) EXEC(GOTO CMDLBL(ERROR))
                     GOTO       CMDLBL(READ)

        /* RETEST CPYF IF RECORD LENGTH IS LESS THAN 4. */
         TEST1:      CPYF       FROMFILE(&DBXLIB/&DBXFIL) +
                                  TOFILE(QTEMP/&DBXFIL) FROMMBR(*ALL) +
                                  TOMBR(*FROMMBR) MBROPT(*REPLACE) +
                                  CRTFILE(*YES) FROMRCD(1) +
                                  INCCHAR(*RCD 1 *EQ '@') +
                                  ERRLVL(0)

        /* REPORT PF ERROR FOR ANY ERROR MESSAGE. */
                     MONMSG     MSGID(CPF0000) EXEC(GOTO CMDLBL(ERROR))
                     GOTO       CMDLBL(READ)

        /* DETERMINE FAILING ERROR MESSAGE. */
         ERROR:      RCVMSG     MSGTYPE(*LAST) RMV(*NO) KEYVAR(&MSGKEY)
                     RCVMSG     MSGTYPE(*PRV) MSGKEY(&MSGKEY) +
                                  KEYVAR(&MSGKEY) MSG(&MSGTXT1) +
                                  MSGID(&MSGID)

        /* SEND PF ERROR MESSAGE TO THE JOB'S USER PROFILE MESSAGE QUEUE. */
         SNDERROR:   CHGVAR     VAR(&MSGTXT) VALUE('Error on file ' *CAT +
                                  &DBXFIL *BCAT 'in library ' *CAT &DBXLIB +
                                  *TCAT '. Failing message is ' *CAT &MSGID +
                                  *BCAT ': ' *CAT &MSGTXT1)
                     SNDMSG     MSG(&MSGTXT) TOUSR(&USER)
                     MONMSG     MSGID(CPF0000)

        /* SEND PF ERROR MESSAGE TO THE JOB'S PROGRAM MESSAGE QUEUE. */
                     CHGVAR     VAR(&PFERR) VALUE(&PFERR + 1)
                     CHGVAR     VAR(&MSGTXT) VALUE('File ' *CAT &DBXFIL +
                                  *BCAT 'in library ' *CAT &DBXLIB *BCAT +
                                  'in error.')
                     SNDPGMMSG  MSG(&MSGTXT) TOPGMQ(*PRV) TOMSGQ(*TOPGMQ) +
                                  MSGTYPE(*DIAG)
                     GOTO       CMDLBL(READ)

        /* SEND FILE COUNT MESSAGES TO THE JOB'S PROGRAM MESSAGE QUEUE. */
         ENDREAD:    CHGVAR     VAR(&PFCNTA) VALUE(&PFCNT)
                     CHGVAR     VAR(&MSGTXT) VALUE(&PFCNTA *BCAT 'physical +
                                  files processed for library ' *CAT +
                                  &LIBRARY *TCAT '.')
                     SNDPGMMSG  MSG(&MSGTXT) TOPGMQ(*PRV) TOMSGQ(*TOPGMQ) +
                                  MSGTYPE(*COMP)
                     IF         COND(&PFERR *EQ 0) THEN(DO)
                     CHGVAR     VAR(&MSGTXT) VALUE('No errors found.')
                     SNDPGMMSG  MSG(&MSGTXT) TOPGMQ(*PRV) TOMSGQ(*TOPGMQ) +
                                  MSGTYPE(*COMP)
                     ENDDO
                     ELSE       CMD(DO)
                     CHGVAR     VAR(&PFERRA) VALUE(&PFERR)
                     CHGVAR     VAR(&MSGTXT) VALUE(&PFERRA *BCAT 'physical +
                                  files were in error for library ' *CAT +
                                  &LIBRARY *TCAT '. Review the previous job +
                                  log messages for additional information.')
                     SNDPGMMSG  MSG(&MSGTXT) TOPGMQ(*PRV) TOMSGQ(*TOPGMQ) +
                                  MSGTYPE(*COMP)
                     ENDDO

         ENDOFPGM:   DLTOVR     FILE(CHKPF)
                     ENDPGM
4. Create program CHKPF in library QGPL. Library QGPL must be in your library list:

CRTCLPGM PGM(QGPL/CHKPF) SRCFILE(QGPL/QCLSRC) SRCMBR(CHKPF)
5. Create source member of type CMD CHKPF in source file QCMDSRC of library QGPL. Update the source member with the following statements:

CMD        PROMPT('Check Damage on Physical Files')
PARM       KWD(LIBRARY) TYPE(*CHAR) LEN(10) +
                  DFT(*ALL) MIN(0) PROMPT('Library name')
6. Create command CHKPF in library QGPL:

CRTCMD CMD(QGPL/CHKPF) PGM(QGPL/CHKPF) SRCFILE(QGPL/QCMDSRC) SRCMBR(CHKPF)

The CHKPF command is now ready for use. Prior to running the CHKPF command for all libraries, it is advisable to verify that the command works by running it for a single library first, for example, QGPL.
Running CHKPF creates a spooled file for each file tested. If no errors are found, the spooled file is empty. The joblog can also report message CPC2957 - No records copied. This means that the records are not damaged. If the damage is at the file level, the joblog shows the message CPD3244 - File nnnnnn in Library mmmmmm is damaged. If a library does not have any files in it, no messages will be issued.

[{"Business Unit":{"code":"BU070","label":"IBM Infrastructure"},"Product":{"code":"SWG60","label":"IBM i"},"Component":"Db2 for i","Platform":[{"code":"PF012","label":"IBM i"}],"Version":"Version Independent","Edition":"","Line of Business":{"code":"LOB68","label":"Power HW"}}]

Historical Number

N1010157

Document Information

Modified date:
26 November 2024

UID

nas8N1010157