KSDS example

The example in Figure 1 shows a sample program (CCNGVS2) with two functions from an employee record entry system with a mainline driver to process selected options (display, display next, update, delete, create). The update routine is an example of KSDS clusters, and the display routine is an example of both KSDS clusters and alternate indexes.

For these examples, the clusters and alternate indexes should be defined as follows:
The update routine is passed the following:
The display routine is passed the following:

By definition, the primary key is unique and therefore the employee number was chosen for this key. The user_id is also a unique key; therefore, it was chosen as the unique alternate index key. The name field may not be unique; therefore, it was chosen as the non-unique alternate index key.

Figure 1. KSDS example
/* this example demonstrates the use of a KSDS file */
/* part 1 of 2-other file is CCNGVS3 */

#include <stdio.h>
#include <string.h>

/* global definitions                                             */

struct data_struct {
              char   emp_number[4];
              char   user_id[8];
              char   name[20];
              char   pers_info[37];
};

#define  REC_SIZE                69
#define  CLUS_KEY_SIZE            4
#define  AIX_UNIQUE_KEY_SIZE      8
#define  AIX_NONUNIQUE_KEY_SIZE  20

static void print_amrc() {
    __amrc_type currErr = *__amrc; /* copy contents of __amrc     */
                                   /* structure so that values    */
                                   /* don't get jumbled by printf */
    printf("R15 value   = %d\n", currErr.__code.__feedback.__rc);
    printf("Reason code = %d\n", currErr.__code.__feedback.__fdbk);
    printf("RBA         = %d\n", currErr.__RBA);
    printf("Last op     = %d\n", currErr.__last_op);
    return;
}

/* update_emp_rec() function definition                           */

int update_emp_rec (struct data_struct *data_ptr,
                    struct data_struct *orig_data_ptr,
                    FILE   *fp)
{
    int          rc;
    char         buffer[REC_SIZE+1];
/*  Check to see if update will change primary key (emp_number)   */

    if (memcmp(data_ptr->emp_number,orig_data_ptr->emp_number,4) !=
0) {
       /* Check to see if changed primary key exists               */
       rc = flocate(fp,&(data_ptr->emp_number),CLUS_KEY_SIZE,__KEY_EQ);
       if (rc == 0) {
          print_amrc();
          printf("Error: new employee number already exists\n");
          return 10;
       }

       clearerr(fp);

       /* Write out new record                                    */
       rc = fwrite(data_ptr,1,REC_SIZE,fp);
       if (rc != REC_SIZE || ferror(fp)) {
          print_amrc();
          printf("Error: write with new employee number failed\n");
          return 20;
       }

       /* Locate to old employee record so it can be deleted       */
       rc = flocate(fp,&(orig_data_ptr->emp_number),CLUS_KEY_SIZE,
                    __KEY_EQ);
       if (rc != 0) {
          print_amrc();
          printf("Error: flocate to original employee number failed\n");
          return 30;
       }

       rc = fread(buffer,1,REC_SIZE,fp);
       if (rc != REC_SIZE || ferror(fp)) {
          print_amrc();
          printf("Error: reading old employee record failed\n");
          return 40;
       }

       rc = fdelrec(fp);
       if (rc != 0) {
          print_amrc();
          printf("Error: deleting old employee record failed\n");
          return 50;
       }
   } /* end of checking for change in primary key                */
    else { /* Locate to current employee record                  */
       rc = flocate(fp,&(data_ptr->emp_number),CLUS_KEY_SIZE,__KEY_EQ);
       if (rc == 0) {
          /* record exists, so update it                         */
          rc = fread(buffer,1,REC_SIZE,fp);
          if (rc != REC_SIZE || ferror(fp)) {
             print_amrc();
             printf("Error: reading old employee record failed\n");
             return 60;
          }
          rc = fupdate(data_ptr,REC_SIZE,fp);
          if (rc == 0) {
             print_amrc();
             printf("Error: updating new employee record failed\n");
             return 70;
          }
       }
       else { /* record doesn't exist so write out new record  */
          clearerr(fp);
          printf("Warning: record previously displayed no longer\n");
          printf("       : exists, new record being created\n");
          rc = fwrite(data_ptr,1,REC_SIZE,fp);
          if (rc != REC_SIZE || ferror(fp)) {
             print_amrc();
             printf("Error: write with new employee number failed\n");
             return 80;
          }
       }
    }
    return 0;
}

/* display_emp_rec() function definition                              */

int display_emp_rec (struct data_struct *data_ptr,
                     struct data_struct *orig_data_ptr,
                     FILE *clus_fp, FILE *aix_unique_fp,
                     FILE *aix_non_unique_fp)
{
    int     rc = 0;
    char    buffer[REC_SIZE+1];

    /* Primary Key Search                                             */
    if (memcmp(data_ptr->emp_number, "\0\0\0\0", 4) != 0) {
       rc = flocate(clus_fp,&(data_ptr->emp_number),CLUS_KEY_SIZE,
                    __KEY_EQ);
       if (rc != 0) {
          printf("Error: flocate with primary key failed\n");
          return 10;
       }

       /* Read record for display                                     */
       rc = fread(orig_data_ptr,1,REC_SIZE,clus_fp);
       if (rc != REC_SIZE || ferror(clus_fp)) {
          printf("Error: reading employee record failed\n");
          return 15;
       }
    }

    /* Unique Alternate Index Search                                  */
    else if (data_ptr->user_id[0] != '\0') {
       rc = flocate(aix_unique_fp,data_ptr->user_id,AIX_UNIQUE_KEY_SIZE,
                   __KEY_EQ);
       if (rc != 0) {
          printf("Error: flocate with user id failed\n");
          return 20;
       }

       /* Read record for display                                     */
       rc = fread(orig_data_ptr,1,REC_SIZE,aix_unique_fp);
       if (rc != REC_SIZE || ferror(aix_unique_fp)) {
          printf("Error: reading employee record failed\n");
          return 25;
       }
    }
    /* Non-unique Alternate Index Search                              */
    else if (data_ptr->name[0] != '\0') {
       rc = flocate(aix_non_unique_fp,data_ptr->name,
                    AIX_NONUNIQUE_KEY_SIZE,__KEY_GE);
       if (rc != 0) {
          printf("Error: flocate with name failed\n");
          return 30;
       }

       /* Read record for display                                     */
       rc = fread(orig_data_ptr,1,REC_SIZE,aix_non_unique_fp);
       if (rc != REC_SIZE || ferror(aix_non_unique_fp)) {
          printf("Error: reading employee record failed\n");
          return 35;
       }
    }
    else {
       printf("Error: invalid search argument; valid search arguments\n"
              "     : are either employee number, user id, or name\n");
       return 40;
    }
    /* display record data                                            */
    printf("Employee Number: %.4s\n", orig_data_ptr->emp_number);
    printf("Employee Userid: %.8s\n", orig_data_ptr->user_id);
    printf("Employee Name:   %.20s\n", orig_data_ptr->name);
    printf("Employee Info:   %.37s\n", orig_data_ptr->pers_info);
    return 0;
}
/* main() function definition                                         */

int main() {
    FILE*               clus_fp;
    FILE*               aix_ufp;
    FILE*               aix_nufp;
    int                 i;
    struct data_struct  buf1, buf2;

    char data[3][REC_SIZE+1] = {
"   1LARRY   LARRY               HI, I'M LARRY,                      ",
"   2DARRYL1 DARRYL              AND THIS IS MY BROTHER DARRYL,      ",
"   3DARRYL2 DARRYL                                                  "
    };

    /* open file three ways                                           */
    clus_fp = fopen("dd:cluster", "rb+,type=record");
    if (clus_fp == NULL) {
       print_amrc();
       printf("Error: fopen(\"dd:cluster\"...) failed\n");
       return 5;
    }

    /* assume base cluster was loaded with at least one dummy record  */
    /* so aix could be defined                                        */
    aix_ufp = fopen("dd:aixuniq", "rb,type=record");
    if (aix_ufp == NULL) {
       print_amrc();
       printf("Error: fopen(\"dd:aixuniq\"...) failed\n");
       return 10;
    }

    /* assume base cluster was loaded with at least one dummy record  */
    /* so aix could be defined                                        */
    aix_nufp = fopen("dd:aixnuniq", "rb,type=record");
    if (aix_nufp == NULL) {
       print_amrc();
       printf("Error: fopen(\"dd:aixnuniq\"...) failed\n");
       return 15;
    }

    /* load sample records                                            */
    for (i = 0; i < 3; ++i) {
       if (fwrite(data[i],1,REC_SIZE,clus_fp) != REC_SIZE) {
          print_amrc();
          printf("Error: fwrite(data[%d]...) failed\n", i);
          return 66+i;
       }
    } 
    
    /* display sample record by primary key                           */
    memcpy(buf1.emp_number, "   1", 4);
    if (display_emp_rec(&buf1, &buf2, clus_fp, aix_ufp, aix_nufp) != 0)
       return 69;

    /* display sample record by nonunique aix key                     */
    memset(buf1.emp_number, '\0', 4);
    buf1.user_id[0] = '\0';
    memcpy(buf1.name, "DARRYL                    ", 20);
    if (display_emp_rec(&buf1, &buf2, clus_fp, aix_ufp, aix_nufp) != 0)
       return 70;

    /* display sample record by unique aix key                        */
    memcpy(buf1.user_id, "DARRYL2 ", 8);
    if (display_emp_rec(&buf1, &buf2, clus_fp, aix_ufp, aix_nufp) != 0)
       return 71;

    /* update record just read with new personal info                 */
    memcpy(&buf1, &buf2, REC_SIZE);
    memcpy(buf1.pers_info, "AND THIS IS MY OTHER BROTHER DARRYL. ", 37);
    if (update_emp_rec(&buf1, &buf2, clus_fp) != 0) return 72;

    /* display sample record by unique aix key                        */
    if (display_emp_rec(&buf1, &buf2, clus_fp, aix_ufp, aix_nufp) != 0)
       return 73;

    return 0;
}

The JCL in the sample code (CCNGVS3) in Figure 2 can be used to test the example code in Figure 1.

Figure 2. KSDS example
//* this example illustrates the use of a KSDS file
//* part 2 of 2-other file is CCNGVS2
//*--------------------------------------------------------
//* Delete cluster, and AIX and PATH
//*--------------------------------------------------------
//DELETEC EXEC PGM=IDCAMS
//SYSPRINT  DD SYSOUT=*
//SYSIN     DD *
    DELETE -
        userid.KSDS.CLUSTER -
        CLUSTER -
        PURGE -
        ERASE
//*--------------------------------------------------------
//* Define KSDS
//*--------------------------------------------------------
//DEFINE  EXEC PGM=IDCAMS
//VOLUME    DD UNIT=SYSDA,DISP=SHR,VOL=SER=(XXXXXX)
//SYSPRINT  DD SYSOUT=*
//SYSIN     DD *
    DEFINE CLUSTER -
        (NAME(userid.KSDS.CLUSTER) -
        FILE(VOLUME) -
        VOL(XXXXXX) -
        TRK(4 4)  -
        RECSZ(69 100) -
        INDEXED -
        NOREUSE -
        KEYS(4 0) -
        OWNER(userid) ) -
      DATA -
        (NAME(userid.KSDS.DA)) -
      INDEX -
        (NAME(userid.KSDS.IX))
/*
//*--------------------------------------------------------
//* Repro data into KSDS
//*--------------------------------------------------------
//REPRO   EXEC PGM=IDCAMS
//SYSPRINT  DD SYSOUT=*
//SYSIN     DD *
   REPRO INDATASET(userid.DUMMY.DATA) -
      OUTDATASET(userid.KSDS.CLUSTER)
/*
//*--------------------------------------------------------
//* Define unique AIX, define and build PATH
//*--------------------------------------------------------
//DEFAIX  EXEC PGM=IDCAMS
//SYSPRINT  DD SYSOUT=*
//SYSIN     DD *
    DEFINE AIX -
        (NAME(userid.KSDS.UAIX) -
        RECORDS(25)  -
        KEYS(8,4)    -
        VOL(XXXXXX)  -
        UNIQUEKEY -
        RELATE(userid.KSDS.CLUSTER)) -
      DATA -
        (NAME(userid.KSDS.UAIXDA)) -
      INDEX -
        (NAME(userid.KSDS.UAIXIX))
    DEFINE PATH -
        (NAME(userid.KSDS.UPATH) -
        PATHENTRY(userid.KSDS.UAIX))
    BLDINDEX -
        INDATASET(userid.KSDS.CLUSTER) -
        OUTDATASET(userid.KSDS.UAIX)
/*
//*--------------------------------------------------------
//* Define nonunique AIX, define and build PATH
//*--------------------------------------------------------
//DEFAIX  EXEC PGM=IDCAMS
//SYSPRINT  DD SYSOUT=*
//SYSIN     DD *
    DEFINE AIX -
        (NAME(userid.KSDS.NUAIX) -
        RECORDS(25)  -
        KEYS(20, 12)    -
        VOL(XXXXXX)  -
        NONUNIQUEKEY -
        RELATE(userid.KSDS.CLUSTER)) -
      DATA -
        (NAME(userid.KSDS.NUAIXDA)) -
      INDEX -
        (NAME(userid.KSDS.NUAIXIX))
    DEFINE PATH -
        (NAME(userid.KSDS.NUPATH) -
        PATHENTRY(userid.KSDS.NUAIX))
    BLDINDEX -
        INDATASET(userid.KSDS.CLUSTER) -
        OUTDATASET(userid.KSDS.NUAIX)
/*
//*--------------------------------------------------------
//* Run the testcase
//*--------------------------------------------------------
//GO        EXEC PGM=CCNGVS2,REGION=5M
//STEPLIB  DD DSN=userid.TEST.LOAD,DISP=SHR
//         DD DSN=CEE.SCEERUN,DISP=SHR
//SYSPRINT  DD SYSOUT=*
//SYSTERM   DD SYSOUT=*
//SYSOUT    DD SYSOUT=*
//PLIDUMP   DD SYSOUT=*
//SYSABEND  DD SYSOUT=*
//SYSUDUMP  DD SYSOUT=*
//CLUSTER   DD DSN=userid.KSDS.CLUSTER,DISP=SHR
//AIXUNIQ   DD DSN=userid.KSDS.UPATH,DISP=SHR
//AIXNUNIQ  DD DSN=userid.KSDS.NUPATH,DISP=SHR
//*--------------------------------------------------------
//* Print out the cluster
//*--------------------------------------------------------
//PRINTF    EXEC PGM=IDCAMS
//SYSPRINT   DD SYSOUT=*
//SYSIN      DD *
   PRINT -
       INDATASET(userid.KSDS.CLUSTER) CHAR
/*