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 KSDS cluster has a record size of 150 with a key length of
4 with offset 0.
The unique KSDS AIX® has a key length of 20 with an offset of 10.
The non-unique KSDS AIX has a key length of 40 with an offset of 30.
The update routine is passed the following:
data_ptr, which points to the information that
is to be updated
orig_data_ptr, which points to the information
that was originally displayed using the display option
A file pointer to the KSDS cluster
The display routine is passed the following:
data_ptr, which points to the information that
was entered on the screen for the search query
orig_data_ptr, which is returned with the information
for the record to be displayed if it exists
File pointers for the primary cluster, unique alternate index
and non-unique alternate index
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))
/*