/* * This C program will read an DSPJRN outfile of *TYPE1 and return the * number of bytes that could have been saved if JMD, Jounral Minimal * Data - the minimize entry specific data option, had been used. The * result of this check is a bit over-optimistic, since the actual * implementation needs some space for metadata. NOTE: This program * does not work with entries larger than 32K. * * The following is an example of a DSPJRN command with the options * required: DSPJRN JRN(LIB/JRN) OUTPUT(*OUTFILE) OUTFILFMT(*TYPE1) OUTFILE(LIB/OUTFILE) ENTDTALEN(*CALC) * * ENTDTALEN(*CALC) calculates the length of the longest data field and * sets all rows in the outfile to be of that same length. *CALC is * needed to give a uniform row length in the outfile. * * Syntax: * SEQONLY lib file * lib - library * outfile - dspjrn outfile * * Compile Statement: CRTSQLCI OBJ(LIB/JMDCHECK) SRCFILE(LIB/JMDCHECK) COMMIT(*NONE) OBJTYPE(*PGM) * * Run Statement: CALL LIB/JMDCHECK PARM('LIB' 'OUTFILE') */ /* include the necessary C header files */ #include #include #include #include /* toupper() call */ /* Statements required for embedded SQL */ EXEC sql include SQLCA; EXEC sql include SQLDA; /* Begin main function */ int main(int argc, char *argv[]) { EXEC SQL BEGIN DECLARE SECTION; int i; /* a simple counter */ long int numents = 0; /* number of entry types in outfile */ long int diff = 0; /* number of modified bytes in an entry */ long int sumdiff = 0; /* sum of the number of modified bytes */ long int curr_ent = 1; /* current entry being processed */ long int entsize = 0; /* size of esd (Entry Specific Data) entries */ long int sumsaved = 0; /* sum of saved bytes if JMD was used */ long int totalBytes = 0; /* total size of UB/UP entries (in bytes) */ long int rrnumberUB = 0; /* the relative record number of the before entry */ long int rrnumberUP = 0; /* the relative record number of the update entry */ char esdUB[32766]; /* 32K is the largest entry specific data entry this */ char esdUP[32766]; /* program will handle */ /* before entry obj/lib/mbr/job character arrays */ char objnameUB[11]; /* character array to hold the object name */ char libnameUB[11]; /* character array to hold the library name */ char mbrnameUB[11]; /* character array to hold the member name */ char jobnameUB[11]; /* character array to hold the job name */ /* update entry obj/lib/mbr/job character arrays */ char objnameUP[11]; /* character array to hold the object name */ char libnameUP[11]; /* character array to hold the library name */ char mbrnameUP[11]; /* character array to hold the member name */ char jobnameUP[11]; /* character array to hold the job name */ char selstmt[200]; /* character arrays to hold our select */ char sel2stmt[200]; /* statements */ char sel3stmt[200]; /* statements */ char statement[200]; char lib[11]; /* character array to hold input library name */ char outfile[11]; /* character array to hold outfile name */ //boolean validData = TRUE; int validData = 1; EXEC SQL DECLARE c1 CURSOR FOR exestmt; /* declare SQL cursor C1 */ EXEC SQL DECLARE c2 CURSOR FOR actstmt; /* declare SQL cursor C2 */ EXEC SQL END DECLARE SECTION; /****************************************** * Parsing command line / error checking ******************************************/ if (argc != 3) { printf("ERROR - proper syntax is: JMDCheck lib outfile"); } else { /* extract the library from the first argument */ sprintf(lib, "%s", argv[1]); /* extract the outfile from the second argument */ sprintf(outfile, "%s", argv[2]); /* convert the lib, outfile to upper case */ for (i = 0; i < 10; i++) { lib[i] = toupper(lib[i]); outfile[i] = toupper(outfile[i]); } /* get the number of UB/UP entries in the file - since these are the */ /* only entries which can be minimized */ sprintf(selstmt, "SELECT COUNT(*) FROM %s/%s WHERE", lib, outfile); sprintf(sel2stmt, " JOENTT='UB' or JOENTT='UP'"); sprintf(statement, "%s%s", selstmt, sel2stmt); EXEC SQL PREPARE actstmt FROM :statement; EXEC SQL OPEN c2; /* open the SQL view (cursor) */ EXEC SQL /* set the number of Jrn_Min Candidate */ FETCH c2 INTO :numents; /* Jounral entries */ EXEC SQL CLOSE c2; /* close the SQL cursor */ /* get the length of the UB/UP entries in the file - all are the same */ /* since ENTDTALEN(*CALC) was used to set all entries in the outfile */ /* to a uniform length */ sprintf(selstmt, "SELECT JOENTL FROM %s/%s WHERE", lib, outfile); sprintf(sel2stmt, " JOENTT='UB' or JOENTT='UP' group by JOENTL"); sprintf(statement, "%s%s", selstmt, sel2stmt); EXEC SQL PREPARE actstmt FROM :statement; EXEC SQL OPEN c2; /* open the SQL view (cursor) */ EXEC SQL FETCH c2 INTO :entsize; /* set the size of entries */ EXEC SQL CLOSE c2; /* close the SQL cursor */ /* output the number of Entries to the screen */ printf("\n\n\n\n\n\n\n"); printf("Number of UB/UP Candidate Journal Entries = %d\n", numents); /* Create SQL query which will loop through each UB/UP entry * in the outfile comparing each UB character to UP to find out * how many bytes changed. */ sprintf(selstmt, "SELECT JOESD, JOOBJ, JOLIB, JOMBR, "); sprintf(sel2stmt, " JOJOB, JOCTRR FROM %s/%s", lib, outfile); sprintf(sel3stmt, " WHERE JOENTT='UB' OR JOENTT='UP'"); sprintf(statement, "%s%s%s", selstmt, sel2stmt, sel3stmt); EXEC SQL PREPARE exestmt FROM :statement; EXEC SQL OPEN c1; /* open the SQL view (cursor) */ /* loop through each entry in the outfile */ while(curr_ent <= numents && validData) { diff = 0; /* get the next available entry - UB/UP entries always come in */ /* pairs and are always back to back with consecutive sequence */ /* numbers, so we are able to compare two consecutive entries */ /* as long as they have the same relative record number */ EXEC SQL FETCH c1 INTO :esdUB, :objnameUB, :libnameUB, :mbrnameUB, :jobnameUB, :rrnumberUB; EXEC SQL FETCH c1 INTO :esdUP, :objnameUP, :libnameUP, :mbrnameUP, :jobnameUP, :rrnumberUP; /* check that the before and update entries are from the same */ /* place (relative record number, obj, lib, mbr, job) */ if(rrnumberUB == rrnumberUP && (strcmp(objnameUB, objnameUP) == 0) && (strcmp(libnameUB, libnameUP) == 0) && (strcmp(mbrnameUB, mbrnameUP) == 0) && (strcmp(jobnameUB, jobnameUP) == 0)) { /* There are 125 bytes of standard information in the outfile */ /* prior to the entry specific data. The entry size includes */ /* all of the data in the outfile row, but since we only want */ /* the entry specific data, we need to subtract 125 bytes from */ /* our entry size. */ for(i=0; i < (entsize - 125); i++) { if(esdUB[i] != esdUP[i]) { diff++; } } } else { validData = 0; /* if the data is not of the correct */ /* type set valid data to false */ } sumdiff += diff; totalBytes += (entsize - 125); /* add the size of the esd to the total size */ curr_ent += 2; /* we compared two consecutive entries, */ /* so need to increment our counter by two */ } if(validData) { printf("Difference: %d bytes.\n", sumdiff); printf("Total bytes: %d bytes.\n", totalBytes); } else { printf("UB did not match UP - Before images must be collected."); } EXEC SQL CLOSE c1; } return 0; }