VSAM Record Level Sharing & Copying Records

By | July 31, 2013

Since IDCAMS REPRO does not support VSAM datasets in RLS mode (and neither does SORT, nor FileAID) you can’t use it to backup or restore a CLUSTER while it is open somewhere else.  This is something that ShareOption/5 used to allow but this product is defunct.  I’d like to be able to copy/merge one KSDS to another while the dataset is open to CICS adding new records, replacing the records in the target dataset that have the same keys as the records in the source dataset (and leaving the other target dataset records extant) while the target dataset is being shared in RLS mode.

Access method services do not use RLS when performing an IDCAMS EXPORT, IMPORT, PRINT, or REPRO command. If the RLS keyword is specified in the DD statement of a data set to be opened by access method services, the keyword is ignored and the data set is opened and accessed in non-RLS mode.  — z/OS DFSMS Using Data Sets

So, let’s do this in C, because I happen to have access to the C compiler.

??=pragma filetag("IBM-1047")
#pragma langlvl(extended)

/*
Merge a KSDS (sysut1) with another (sysut2) adding new reqcords and
replacing existing records. The KSDSs must be defined with the same
record length, key position and key length otherwise results are
unpredictable.
*/

#include <stdio.h>

int main(void)
{
  FILE *             sysut1;
  FILE *             sysut2;
  unsigned int       rec1l;
  unsigned char *    rec1p;
  unsigned char *    rec2p;
  int                sysut1_reads = 0;
  int                sysut2_writes = 0;
  int                sysut2_updates = 0;
  struct __fileData  filedata1;
  struct __fileData  filedata2;
  char               filename1[256];
  char               filename2[256];

  /* setenv("_EDC_IO_TRACE","(//DD:*,2,)",1); */

  sysut1 = fopen("dd:sysut1", "rb,type=record");
  if (sysut1 == NULL) { perror("dd:sysut1 open error"); exit(16); }
  fldata(sysut1, filename1, &filedata1);
  printf("Note: %s opened (SYSUT1)\n", filedata1.__dsname);
  if (filedata1.__vsamRLS == __RLS) printf("Note: SYSUT1 is using RLS\n");
  if (filedata1.__vsamRLS == __TVS) printf("Note: SYSUT1 is using TVS\n");
  rec1p = (unsigned char *) malloc(filedata1.__maxreclen);

  sysut2 = fopen("dd:sysut2", "rb+,type=record");
  if (sysut2 == NULL) { perror("dd:sysut2 open error"); exit(16); }
  fldata(sysut2, filename2, &filedata2);
  printf("Note: %s opened (SYSUT2)\n", filedata2.__dsname);
  if (filedata2.__vsamRLS == __RLS) printf("Note: SYSUT2 is using RLS\n");
  if (filedata2.__vsamRLS == __TVS) printf("Note: SYSUT2 is using TVS\n");
  rec2p = (unsigned char *) malloc(filedata2.__maxreclen);

  if (filedata1.__maxreclen > filedata2.__maxreclen)
    printf("Note: SYSUT1 maximum record length is greater than SYSUT2\n");
  if ((filedata1.__vsamRKP    != filedata2.__vsamRKP)
  ||  (filedata1.__vsamkeylen != filedata2.__vsamkeylen))
    printf("Note: SYSUT1 key position/length differs from SYSUT2\n");

  putchar('\n');

  /* -- */

  rec1l = fread(rec1p, 1, filedata1.__maxreclen, sysut1);

  while (rec1l > 0)                                           
  {
    ++sysut1_reads;
    if (flocate(sysut2, rec1p+filedata2.__vsamRKP,                                         
                        filedata2.__vsamkeylen, __KEY_EQ) == 0)
    {
      fread(rec2p, 1, filedata2.__maxreclen, sysut2);
      if (ferror(sysut2)) { perror("dd:sysut2 read error"); exit(16); }
      fupdate(rec1p, rec1l, sysut2);   
      if (ferror(sysut2)) { perror("dd:sysut2 update error"); exit(16); }
      ++sysut2_updates;
    }
    else
    {
      clearerr(sysut2);
      fwrite(rec1p, 1, rec1l, sysut2);             
      if (ferror(sysut2)) { perror("dd:sysut2 write error"); exit(16); }
      ++sysut2_writes;
    }

    rec1l = fread(rec1p, 1, filedata1.__maxreclen, sysut1);

  }

  if (ferror(sysut1)) { perror("dd:sysut1 read error"); exit(16); }

  printf("      %5i SYSUT1 records read\n", sysut1_reads); 
  printf("      %5i SYSUT2 records updated\n", sysut2_updates); 
  printf("      %5i SYSUT2 new records written\n", sysut2_writes); 

  fclose(sysut1);
  fclose(sysut2);

}

Compile with something like this…

//*
// JCLLIB ORDER=(CBC.SCCNPRC)
//*
//CC        EXEC EDCCB,
// INFILE='XXXXXXX.SRC.C(VSAMCOPY)',
// OUTFILE='XXXXXXX.SRC.LOAD(VSAMCOPY),DISP=SHR',
// CPARM='LIST,SOU,XREF,NOMARG,NOSEQ,RENT,OPT,ARCH(10),TUNE(10),LOC'
//*

Obviously, seeing ARCH(10), I must be running on (at least) a zEC12, eh? Anyway, this new program can be executed with something like:

//*
//COPY     EXEC PGM=VSAMCOPY
//STEPLIB  DD DISP=SHR,DSN=XXXXXXX.SRC.LOAD
//SYSUT1   DD DISP=SHR,DSN=VSAM.INPUT,RLS=NRI
//SYSUT2   DD DISP=SHR,DSN=VSAM.OUTPUT,RLS=NRI
//SYSOUT   DD SYSOUT=*
//SYSPRINT DD SYSOUT=*

Leave a Reply

Your email address will not be published. Required fields are marked *