Examples: Defining queries

This topic includes several examples that use the Query (QQQQRY) API.

The examples define the following query functions:

The following QQAPI header (or include) file and the QQFUNCS qu
Note: Read the Code license and disclaimer information for important legal information.
ery code are used by all the examples. The example programs follow the QQAPI header and QQFUNCS code.

QQAPI header

/********************************************************************/

#ifndef _QQAPIH
#define _QQAPIH


/*******************************************************************/
/*******************************************************************/
/*                                                                 */
/* FUNCTION:  Defines constants and structures for use             */
/*            with the QQQQRY API examples.                        */
/*                                                                 */
/* LANGUAGE:  ILE C                                                */
/*                                                                 */
/* APIs USED: None                                                 */
/*                                                                 */
/*******************************************************************/
/*******************************************************************/


/* The following define will enable some debug procedures and code */
/* #define QQDEBUG */

/* Query Open options */
#define QO_INPUT   1
#define QO_OUTPUT  2
#define QO_UPDATE  4
#define QO_DELETE  8

/* simple defines */
#define ON    1
#define OFF   0

/* user defined limits - change as needed */
#define MAX_ORDERBY    20
  /* max number of order by fields (8000 max)*/
#define MAX_JOINTESTS  20
  /* max number of join tests (999 max)*/
#define MAX_GROUPBY    20
  /* max number of order by fields (120 max)*/
/* storage sizes - increase if needed */
#define QDT_SIZE      6000
#define FORMAT_SIZE   5000
#define SELECT_SIZE   5000
#define AP_SIZE      65535     /* Initialize access plan size to 64K */


/* Required definitions - do NOT change, hard limits */
#define MAX_FILES      32      /* Maximum number of files in a query */
#define REQ_REL       "01"     /* Required value for release field */
#define REQ_VER       "00"     /* Required value for version field */
#define QFLD_SIZE      30      /* QQ API field size - see qqqqry.h */

/* define error code structure */
typedef struct
{
    int bytes_provided;
    int bytes_available;
    char msgid[(7]);
    char reserved;
    char data[(512]);
} error_code;

/* define attribute record for QUSCUSAT API */
typedef _Packed struct
{
    int  numAttrs;
    int  key;
    int  length;
    _Packed union {
      long spaceSize;    /* key = 1 */
      char initialValue; /* key = 2 */
      char autoExtend;   /* key = 3 */
    } data;
} QUSCUSAT_T;

/* define access plan structure */
typedef _Packed struct
{
    _SPCPTR storagePtr;
    long size;
    char reserved[(28]);
} ACCPLN_T;


/* Function prototypes: */
void dumpPtr(char *, char *, int );
char *strcnv400(char *, int );
int strcpy400(char *, char *, int );
void initUFCB(QDBUFCB_T *, int , Qdb_Qddfmt_t *);
void initQDT(QDBQH_T *, char , int , int ,
  char , int );
void initFile(QDBQFHDR_T *, char , char );
void initFormat(Qdb_Qddfmt_t *, char *);
void initSelection(QDBQS_T *);
void initOrderBy(QDBQKH_T *);
void initGroupBy(QDBQGH_T *);
void initJoin(QDBQJHDR_T *);
int addFile(QDBQFHDR_T *, QDBQN_T *,
  char *, char *, char *, char *);
int getRecordFmt(Qdb_Qddfmt_t *, long,
  char *, char *, char *);
long copyField(Qdb_Qddfmt_t *, char *, int ,
  Qdb_Qddfmt_t *);
void setFieldUsage(Qdb_Qddfmt_t *, char *, char );
int addSelectField(QDBQS_T *, char *, int );
int addSelectLiteral(QDBQS_T *, void *, int );
int addSelectOperator(QDBQS_T *, char *);
int addOrderBy(QDBQKH_T *, QDBQKF_T *,
  char *, int );
int addGroupBy(QDBQGH_T *, QDBQGF_T *,
  char *, int );
int addJoinTest(QDBQJHDR_T *, QDBQJFLD_T *, char *,
  int , char *, int , char *);
void addQDTsection(QDBQH_T *, char *, int , int *);
long createAccessPlanSpace(ACCPLN_T *, char *, long );
int saveQDT(QDBQH_T *, ACCPLN_T *);
int saveAccessPlan(ACCPLN_T *);
int loadQDT(QDBQH_T *, ACCPLN_T *);
long loadAccessPlan(ACCPLN_T *, char *);

#endif
/********************************************************************/

QQFUNCS query code

/********************************************************************/
#include <stdio.h>
#include <string.h>
#include <qdbrtvfd.h>
#include <qqqqry.h>
#include <quscrtus.h>
#include <qusptrus.h>
#include <quscusat.h>
#include <qusrusat.h>
#include "qqapi.h"

/*******************************************************************/
/*******************************************************************/
/*                                                                 */
/* FUNCTION:  This module contains all of the functions            */
/*            used by the examples to build the API information.   */
/*                                                                 */
/* LANGUAGE:  ILE C                                                */
/*                                                                 */
/* APIs USED: QDBRTVFD, QUSCRTUS, QUSCUSAT, QUSPTRUS, QUSRUSAT     */
/*                                                                 */
/*******************************************************************/
/*******************************************************************/

#ifdef QQDEBUG
/* dumpPtr(comment string, pointer, length)
 - prints a comment then dumps data in hexadecimal starting at the
   given pointer location for the specified length */
void dumpPtr(char *text, char *ptr, int len)
{
    int i;

    printf("%s\n", text);
    for (i=0; i < len; i++, ptr++)
    {
        printf("%02X ", (int) *ptr);
        if ((i+1) % 16 == 0)
           printf("\n");
    }
    printf("\n");
}
#endif


/* strcnv400(source string, string length)
 - convert a string to a zero terminated string */
char *strcnv400(char *str, int len)
{
static char buffer[256];

    strncpy(buffer, str, len);
    buffer[len] = (char) 0;
    return(buffer);
}


/* strcpy400(destination string, source string, source length)
 - copy a zero terminated string to a string, pad with blanks
   if necessary */
int strcpy400(char *dest, char *src, int len)
{
    int i;

    if ((i = strlen(src)) > len)
        len = i;
    if (len)
        memcpy(dest, src, strlen(src));
    if (i < len)
        memset((dest+i), ' ', len-i);
    return(len);
}


/* initUFCB(ufcb, open options, record format)
 - initialize the UFCB structure */
void initUFCB(QDBUFCB_T *ufcbPtr, int openFlags,
  Qdb_Qddfmt_t *formatPtr)
{
    _Packed struct qufcb *ufcb;

    /* verify parameters */
    if (ufcbPtr == NULL || openFlags == 0)
    {
        printf("Invalid UFCB settings\n");
        return;
    }
    /* Clear the entire UFCB */
    memset((void *) ufcbPtr, (char) 0, sizeof(QDBUFCB_T));
    /* Now start initializing values */
    ufcb = &ufcbPtr-&gt;qufcb;
    strcpy400((char *) ufcb->relver.release, REQ_REL,
      sizeof(ufcb->relver.release));
    strcpy400((char *) ufcb->relver.version, REQ_VER,
      sizeof(ufcb->relver.version));
    /* Blocked Records (BLKRCD) should be on if CPYFRMQRYF is used */
    ufcb->markcnt.flg2brcd = ON;
    ufcb->parameter.maximum = MAXFORMATS;
    /* Set the open option */
    if (openFlags&QO_INPUT)
        ufcb->open.flagui = ON;
    if (openFlags&QO_OUTPUT)
        ufcb->open.flaguo = ON;
    if (openFlags&QO_UPDATE)
        ufcb->open.flaguu = ON;
    if (openFlags&QO_DELETE)
        ufcb->open.flagud = ON;
    /* set up options to match _Ropen options */
    ufcb->parameter.keyfdbk = KEYFDBK;
    ufcb->parameter.keyonoff = ON; /* Key feedback ON */
    ufcb->parameter.filedep = FILEDEP;
    ufcb->parameter.fldonoff = ON; /* File dependent I/O ON */
    /* turn the rest of the parameters off */
    ufcb->parameter.seqonly = NOTSEQUPROC;
    ufcb->parameter.primrln1 = NOTRECORDLTH;
    ufcb->parameter.commitc = NOTCOMITCTL;
    /* if the format is supplied,
      define it in the UFCB and do level checking */
    if (formatPtr != NULL)
    {
        ufcb->parameter.lvlchk = LEVELCK;
        ufcb->parameter.lvlonoff = ON; /* Level check ON */
        ufcb->parameter.curnum = 1; /* only one format */
        /* set the format name and format level identifier */
        ufcb->parameter.recfmts = FORMATSEQ;
        memcpy(ufcb->parameter.formats[0].name, formatPtr->Qddfname,
          sizeof(ufcb->parameter.formats[0].name));
        memcpy(ufcb->parameter.formats[0].number, formatPtr->Qddfseq,
          sizeof(ufcb->parameter.formats[0].number));
    }
    else /* no format and level checking */
    {
        ufcb->parameter.lvlchk = NOTLEVELCK;
        ufcb->parameter.recfmts = NOTFORMATSEQ;
    }
    ufcb->ufcbend  = ENDLIST;
}


/* initQDT(qdt, options...)
 - initialize the QDT header */
void initQDT(QDBQH_T *qdtHdr, char alwCpyDta,
  int optAllAp, int statusMsgs,
  char optimize, int forRows)
{
    if (qdtHdr == NULL)
    {
        printf("Invalid QDT settings\n");
        return;  /* invalid pointer */
    }
    /* Clear the entire QDT */
    memset((void *) qdtHdr, (char) 0, sizeof(QDBQH_T));
    /* set the initial QDT space used size */
    qdtHdr->qdbspcsize = sizeof(QDBQH_T);
    /* QDT options... */
    /* ordering not specified */
    qdtHdr->qdbqkeyo = -1;
    /* set optimize parameter (ALLIO, FIRSTIO, MINWAIT) */
    if (optimize == QDBQFINA || optimize == QDBQFINF ||
      optimize == QDBQFINM || optimize == QDBQFINC)
        qdtHdr->qdbqfin = optimize; /* OPTIMIZE() parameter */
    else
        qdtHdr->qdbqfin = QDBQFINA; /* default to OPTIMIZE(*ALLIO) */
    /* set allow copy data parameter (YES, NO, OPTIMIZE) */
    if (alwCpyDta == QDBQTEMN || alwCpyDta ==  QDBQTEMO ||
      alwCpyDta == QDBQTEMA)
        qdtHdr->qdbqtem = alwCpyDta; /* ALWCPYDTA() parameter */
    else
        qdtHdr->qdbqtem = QDBQTEMA; /* default to ALWCPYDTA(*YES) */
    /* status messages (YES, NO) */
    qdtHdr->qdbqattr.qdbqnst = statusMsgs ? ON : OFF;
    /* optimize all access path parameter (YES, NO) */
    qdtHdr->qdbqdt_7.qdbqopta = optAllAp ? ON : OFF;
    /* optimizer for n rows parameter */
    qdtHdr->qdbq_optmrows = forRows > 0 ? forRows : 0;
}


/* initFile(file section, join type, join order option)
 - initialize the file header section */
void initFile(QDBQFHDR_T *fileHdr, char joinType, char joinOrder)
{
    if (fileHdr == NULL)
    {
        printf("Invalid File Header settings\n");
        return;  /* invalid pointer */
    }
    /* Clear the header */
    memset((void *) fileHdr, (char) 0, sizeof(QDBQFHDR_T));
    /* File Spec options... */
    /* inner, partial outer or exception join type */
    if (joinType == QDBQINNJ || joinType == QDBQOUTJ ||
      joinType == QDBQEXCJ)
        fileHdr->qdbqmfop = joinType;
    else
        fileHdr->qdbqmfop = QDBQINNJ;
    /* join order - any order or join as specified */
    fileHdr->qdbqmfor = joinOrder == QDBQMFON ? QDBQMFON : QDBQMFOA;
}


/* initFormat(format section, format name)
 - initialize the format header section */
void initFormat(Qdb_Qddfmt_t *formatHdr, char *name)
{
    if (formatHdr == NULL)
    {
        printf("Invalid Format Header settings\n");
        return;  /* invalid pointer */
    }
    /* Clear the header */
    memset((void *) formatHdr, (char) 0, sizeof(Qdb_Qddfmt_t));
    /* Format Spec options... */
    strcpy400(formatHdr->Qddfname, name, sizeof(formatHdr->Qddfname));
    formatHdr->Qddfrcid = 65535;
    formatHdr->Qddfsrcd = 65535;
    formatHdr->Qddflgs.Qddfrsid = 1;
    memset(formatHdr->Qddfseq, ' ', sizeof(formatHdr->Qddfseq));
    memset(formatHdr->Qddftext, ' ', sizeof(formatHdr->Qddftext));
    /* Format size (so far) */
    formatHdr->Qddbyava = sizeof(Qdb_Qddfmt_t);
    formatHdr->Qddbyrtn = formatHdr->Qddbyava;
}


/* initSelection(selection section)
 - initialize the selection header section */
void initSelection(QDBQS_T *selectHdr)
{
    if (selectHdr == NULL)
    {
        printf("Invalid selection settings\n");
        return;  /* invalid pointer */
    }
    /* Clear the header */
    memset((void *) selectHdr, (char) 0, sizeof(QDBQS_T));
    /* set initial selection spec size (minus dummy selection spec) */
    selectHdr->qdbqsl = sizeof(QDBQS_T) - sizeof(selectHdr->qdbqspec);
}


/* initOrderBy(orderby section)
 - initialize order by header section */
void initOrderBy(QDBQKH_T *orderByHdr)
{
    if (orderByHdr == NULL)
    {
        printf("Invalid Order By settings\n");
        return;  /* invalid pointer */
    }
    /* Clear the header */
    memset((void *) orderByHdr, (char) 0, sizeof(QDBQKH_T));
}


/* initGroupBy(groupby section)
 - initialize group by header section */
void initGroupBy(QDBQGH_T *groupByHdr)
{
    if (groupByHdr == NULL)
    {
        printf("Invalid Group By settings\n");
        return;  /* invalid pointer */
    }
    /* Clear the header */
    memset((void *) groupByHdr, (char) 0, sizeof(QDBQGH_T));
}


/* initJoin(join section)
 - initialize join header section */
void initJoin(QDBQJHDR_T *joinHdr)
{
    if (joinHdr == NULL)
    {
        printf("Invalid Join settings\n");
        return;  /* invalid pointer */
    }
    /* Clear the header */
    memset((void *) joinHdr, (char) 0, sizeof(QDBQKH_T));
    /* set initial join spec size */
    joinHdr->qdbqjln = sizeof(QDBQJHDR_T);
}


/* addFile (file section, file spec section, file name, file library,
   file member, file format)
 - add file information to the file section */
int addFile(QDBQFHDR_T *fileHdr, QDBQN_T *fileSpec,
  char *filename, char *library, char *member, char *format)
{
    int i;
    QDBQFLMF_T *fileSpecPtr;

    if (fileHdr == NULL || fileSpec == NULL || filename == NULL)
        return(0);  /* invalid data */
    if (fileHdr->qdbqfilnum == MAX_FILES)
        return(0);  /* no more files allowed */
    /* increment the count of file specs */
    i = fileHdr->qdbqfilnum++;
    /* initialize the file spec area */
    memset((void *) &fileSpec[i], (char) 0, sizeof(QDBQN_T));
    fileSpecPtr = (QDBQFLMF_T *) &fileSpec[i].qdbqflmf;
    /* fill in the data... */
    strcpy400(fileSpecPtr->qdbqfile, filename,
      sizeof(fileSpecPtr->qdbqfile));
    if (library == NULL)
        strcpy400(fileSpecPtr->qdbqlib, QDBQLIBL,
          sizeof(fileSpecPtr->qdbqlib));
    else
        strcpy400(fileSpecPtr->qdbqlib, library,
          sizeof(fileSpecPtr->qdbqlib));
    if (member == NULL)
        strcpy400(fileSpecPtr->qdbqmbr, QDBQFRST,
          sizeof(fileSpecPtr->qdbqmbr));
    else
        strcpy400(fileSpecPtr->qdbqmbr, member,
          sizeof(fileSpecPtr->qdbqmbr));
    if (format == NULL)
        strcpy400(fileSpecPtr->qdbqfmt, QDBQONLY,
          sizeof(fileSpecPtr->qdbqfmt));
    else
        strcpy400(fileSpecPtr->qdbqfmt, format,
          sizeof(fileSpecPtr->qdbqfmt));
    /* return the amount of storage used in the file specs */
    return(fileHdr->qdbqfilnum*sizeof(QDBQN_T));
}


/* getRecordFmt(format, format storage size(max),
   file name, file library, file format)
 - get a record format (using QDBRTVFD) */
int getRecordFmt(Qdb_Qddfmt_t *formatPtr, long spaceSize,
  char *filename, char *libname, char *formatname)
{
    error_code errcod;
    char override = '1';  /* process overrides */
    char fileLibname[20];
    char outFilLib[20];
    char format[10];

    if (formatPtr == NULL || filename == NULL)
        return(0);  /* missing data */
    errcod.bytes_provided = 512;
    errcod.msgid[0] = (char) 0;
    /* set up temporary variables... */
    strcpy400(fileLibname, filename, 10);
    if (libname == NULL)
        strcpy400(&fileLibname[10], QDBQLIBL, 10);
    else
        strcpy400(&fileLibname[10], libname, 10);
    if (formatname == NULL)
        strcpy400(format, filename, 10);
    else
        strcpy400(format, formatname, 10);
    /* call the RTVFD API to get the record format */
    QDBRTVFD((char *) formatPtr, spaceSize, outFilLib,
      "FILD0200",
      fileLibname, format, &override,
        "*LCL      ", "*EXT      ", &errcod);
    if (errcod.msgid[0])
    {
        printf("API QDBRTVFD failed\n");
        printf("msgid = %7s\n", strcnv400(errcod.msgid,
          sizeof(errcod.msgid)));
    }
    if (formatPtr->Qddbyrtn != formatPtr->Qddbyava)
        return(0);  /* missing data */
    /* return total storage used in format */
    return(formatPtr->Qddbyrtn);
}


/* copyField(format, field name, file number, existing format)
 - copy a field from an existing format */
long copyField(Qdb_Qddfmt_t *formatPtr, char *fieldName, int fieldFile,
  Qdb_Qddfmt_t *oldFormatPtr)
{
    int i;
    long fieldSize;
    char padField[30];
    Qdb_Qddffld_t *fieldPtr, *oldFieldPtr;

    if (formatPtr == NULL || fieldName == NULL || oldFormatPtr == NULL)
        return(0);  /* missing data */
    strcpy400(padField, fieldName, 30);
    /* set up field pointers */
    fieldPtr = (Qdb_Qddffld_t *) ((char *) formatPtr +
      formatPtr->Qddbyava);
    oldFieldPtr = (Qdb_Qddffld_t *) (oldFormatPtr + 1);
    /* loop through all the fields, looking for a match */
    for (i=0; i < oldFormatPtr->Qddffldnum; i++,
      oldFieldPtr = (Qdb_Qddffld_t *) ((char *) oldFieldPtr +
      oldFieldPtr->Qddfdefl))
    /* if a match was found... */
    if (memcmp(oldFieldPtr->Qddfflde, padField, 30) == 0)
    {
        /* copy the field over */
        fieldSize = oldFieldPtr->Qddfdefl;
        memcpy(fieldPtr, oldFieldPtr, fieldSize);
        /* set the file number it was defined in */
        fieldPtr->Qddfjref = fieldFile;
        /* increment the format header information */
        formatPtr->Qddffldnum++;
        formatPtr->Qddfrlen += fieldPtr->Qddffldb;
        formatPtr->Qddbyava += fieldSize;
        formatPtr->Qddbyrtn = formatPtr->Qddbyava;
        break;
    }
    /* return total storage used in format */
    return(formatPtr->Qddbyrtn);
}


/* setFieldUsage(format, field name, usage)
 - set the field usage in a format */
void setFieldUsage(Qdb_Qddfmt_t *formatPtr, char *fieldName, char usage)
{
    int i;
    char padField[30];
    Qdb_Qddffld_t *fieldPtr;

    if (formatPtr == NULL)
        return;  /* missing data */
    if (fieldName != NULL)
        strcpy400(padField, fieldName, 30);
    /* set up field pointers */
    fieldPtr = (Qdb_Qddffld_t *) (formatPtr + 1);
    /* loop through all the fields, looking for a match */
    for (i=0; i < formatPtr->Qddffldnum; i++,
      fieldPtr = (Qdb_Qddffld_t *) ((char *) fieldPtr +
      fieldPtr->Qddfdefl))
    /* if all fields to be set or a match was found... */
    if (fieldName == NULL ||
      memcmp(fieldPtr->Qddfflde, padField, 30) == 0)
        fieldPtr->Qddffiob = usage;
}


/* addSelectField(section section, field name, file number for field)
 - add a selection for a file field to the selection section */
int addSelectField(QDBQS_T *selectHdr, char *fieldName, int fieldFile)
{
    QDBQSIT_T *selectItemPtr;
    QDBQSOPF_T *selectFldPtr;
    int itemSize;

    if (selectHdr == NULL || fieldName == NULL)
        return(0);  /* invalid data */
    /* set up all the section for adding a field */
    selectItemPtr = (QDBQSIT_T *) ((char *) selectHdr +
      selectHdr->qdbqsl);
    itemSize = sizeof(QDBQSIT_T) - sizeof(selectItemPtr->qdbqsitm);
    memset((void *) selectItemPtr, (char) 0, itemSize);
    selectFldPtr = (QDBQSOPF_T *) ((char *) selectItemPtr + itemSize);
    memset((void *) selectFldPtr, (char) 0, sizeof(QDBQSOPF_T));
    /* set up the selection item information for a field */
    selectItemPtr->qdbqslen = itemSize + sizeof(QDBQSOPF_T);
    /* length */
    selectItemPtr->qdbqsitt = QDBQOPF; /* type is field */
    /* now set up the field */
    strcpy400(selectFldPtr->qdbqsofn, fieldName,
      sizeof(selectFldPtr->qdbqsofn));
    selectFldPtr->qdbqsofj = fieldFile;
    /* update the header statistics */
    selectHdr->qdbqsnum++;  /* increment number of select specs */
    selectHdr->qdbqsl += selectItemPtr->qdbqslen;  /* total length */
    /* return the total storage now in the selection section */
    return(selectHdr->qdbqsl);
}


/* addSelectLiteral(selection section, literal, size of literal data)
 - add a selection for a literal to the selection section */
int addSelectLiteral(QDBQS_T *selectHdr, void *literal, int sizeLit)
{
    QDBQSIT_T *selectItemPtr;
    QDBQSOCH_T *selectLitPtr;
    void *selectDataPtr;
    int itemSize;

    if (selectHdr == NULL || literal == NULL || sizeLit < 1)
        return(0);  /* invalid data */
    /* set up all the sections for adding a literal */
    selectItemPtr = (QDBQSIT_T *)
      ((char *) selectHdr + selectHdr->qdbqsl);
    itemSize = sizeof(QDBQSIT_T) - sizeof(selectItemPtr->qdbqsitm);
    memset((void *) selectItemPtr, (char) 0, itemSize);
    selectLitPtr = (QDBQSOCH_T *) ((char *) selectItemPtr + itemSize);
    memset((void *) selectLitPtr, (char) 0, sizeof(QDBQSOCH_T));
    selectDataPtr = (void *) (selectLitPtr + 1);
    /* set up the selection item information for a literal */
    selectItemPtr->qdbqslen = itemSize + sizeof(QDBQSOCH_T) + sizeLit;
    selectItemPtr->qdbqsitt = QDBQOPC;  /* literal type */
    /* now set up the literal */
    selectLitPtr->qdbqsocl = sizeLit;  /* literal size */
    selectLitPtr->qdbqsoft = '\xFF';
      /* use job format for date/time fields */
    memcpy(selectDataPtr, literal, sizeLit);
      /* save the literal value */
    /* update the header statistics */
    selectHdr->qdbqsnum++;  /* increment number of select specs */
    selectHdr->qdbqsl += selectItemPtr->qdbqslen;  /* total length */
    /* return the total storage now in the selection section */
    return(selectHdr->qdbqsl);
}


/* addSelectOperator(selection section, operator type)
 - add a selection for an operator to the selection section */
int addSelectOperator(QDBQS_T *selectHdr, char *operator)
{
    QDBQSIT_T *selectItemPtr;
    QDBQSOPR_T *selectOprPtr;
    QDBQSOP2_T *selectWldPtr;
    int itemSize;
    int oprSize;

    if (selectHdr == NULL || operator == NULL)
        return(0);  /* invalid data */
    /* set up all the sections for adding an operator */
    selectItemPtr = (QDBQSIT_T *)
      ((char *) selectHdr + selectHdr->qdbqsl);
    itemSize = sizeof(QDBQSIT_T) - sizeof(selectItemPtr->qdbqsitm);
    memset((void *) selectItemPtr, (char) 0, itemSize);
    selectOprPtr = (QDBQSOPR_T *) ((char *) selectItemPtr + itemSize);
    oprSize = sizeof(QDBQSOPR_T) + sizeof(QDBQSOP2_T);
    memset((void *) selectOprPtr, (char) 0, oprSize);
    /* set up the selection item information for an operator */
    selectItemPtr->qdbqslen = itemSize + oprSize;  /* length */
    selectItemPtr->qdbqsitt = QDBQOPTR;  /* operator type */
    /* now set up the operator */
    memcpy(selectOprPtr->qdbqsop, operator,
      sizeof(selectOprPtr->qdbqsop));
    /* wildcard operator set up */
    if (memcmp(operator, QDBQWILD, 2) == 0)
    {
       selectOprPtr->qdbqswc1 = '_';
       selectOprPtr->qdbqswc2 = '*';
       selectWldPtr = (QDBQSOP2_T *) (selectOprPtr + 1);
       memcpy(selectWldPtr->qdbqsdb1,"\42_", 2);
       memcpy(selectWldPtr->qdbqsdb2,"\42*", 2);
    }
    /* update the header statistics */
    selectHdr->qdbqsnum++;  /* increment number of select specs */
    selectHdr->qdbqsl += selectItemPtr->qdbqslen;  /* total length */
    /* return the total storage now in the selection section */
    return(selectHdr->qdbqsl);
}


/* addOrderBy(orderby section, orderby specs section, key field name,
   descend sort option
 - add an order by to the order by section */
int addOrderBy(QDBQKH_T *orderByHdr, QDBQKF_T *orderByFld,
  char *keyfield, int descend)
{
    int i;
    QDBQKF_T *orderByFldPtr;

    if (orderByHdr == NULL || orderByFld == NULL || keyfield == NULL)
        return(0);
    if (orderByHdr->qdbqknum == MAX_ORDERBY)
        return(0);
    /* increment the order by spec counter */
    i = orderByHdr->qdbqknum++;
    /* add the new orderby data */
    orderByFldPtr = &orderByFld[i];
    memset((void *) orderByFldPtr, (char) 0, sizeof(QDBQKF_T));
    strcpy400(orderByFldPtr->qdbqkfld, keyfield,
        sizeof(orderByFldPtr->qdbqkfld));
    orderByFldPtr->qdbqksq.qdbqksad = (descend) ? ON : OFF;
    /* return the space used by the order by specs */
    return(orderByHdr->qdbqknum*sizeof(QDBQKF_T));
}


/* addGroupBy(groupby section, groupby field spec section,
   groupby field name, file number of groupby field)
 - add a group by to the group by section */
int addGroupBy(QDBQGH_T *groupByHdr, QDBQGF_T *groupByFld,
  char *groupfield, int fromFile)
{
    int i;
    QDBQGF_T *groupByFldPtr;

    if (groupByHdr == NULL || groupByFld == NULL || groupfield == NULL)
        return(0);
    if (groupByHdr->qdbqgfnum == MAX_GROUPBY)
        return(0);
    /* increment the group by spec counter */
    i = groupByHdr->qdbqgfnum++;
    /* add the new groupby data */
    groupByFldPtr = (QDBQGF_T *) &groupByFld[i];
    memset((void *) groupByFldPtr, (char) 0, sizeof(QDBQGF_T));
    strcpy400(groupByFldPtr->qdbqgfld, groupfield,
        sizeof(groupByFldPtr->qdbqgfld));
    groupByFldPtr->qdbqgflj = fromFile;
    /* return the space used by the group by specs */
    return(groupByHdr->qdbqgfnum*sizeof(QDBQGF_T));
}


/* addJoinTest(join section, join test section, join from field name,
   join from file number, join to field name, join to file number,
   join operator)
 - add a join test to the join section */
int addJoinTest(QDBQJHDR_T *joinHdr,
  QDBQJFLD_T *joinSpec, char *fromFld,
  int fromFile, char *toFld, int toFile, char *joinOp)
{
    int i;
    QDBQJFLD_T *joinSpecPtr;

    if (joinHdr == NULL || joinSpec == NULL)
        return(0);
    if (joinHdr->qdbqjknum == MAX_JOINTESTS)
        return(0);
    /* increment the join test counter */
    i = joinHdr->qdbqjknum++;
    memset((void *) &joinSpec[i], (char) 0, sizeof(QDBQJFLD_T));
    /* add the new join data */
    joinSpecPtr = &joinSpec[i];
    strcpy400(joinSpecPtr->qdbqjfnm, fromFld,
      sizeof(joinSpecPtr->qdbqjfnm));
    joinSpecPtr->qdbqjfnum = fromFile;  /* 1, 2, 3, etc */
    strcpy400(joinSpecPtr->qdbqjtnm, toFld,
      sizeof(joinSpecPtr->qdbqjtnm));
    joinSpecPtr->qdbqjtnum = toFile;  /* 1, 2, 3, etc */
    /* Join operator - see #defines in QQ API include */
    strcpy400(joinSpecPtr->qdbqjop, joinOp,
      sizeof(joinSpecPtr->qdbqjop));
    /* set size of entire join spec */
    joinHdr->qdbqjln += sizeof(QDBQJFLD_T);
    /* return the space used by the join tests */
    return(joinHdr->qdbqjknum*sizeof(QDBQJFLD_T));
}


/* addQDTsection(qdt, new section, size of new section, qdt offset)
 - place a new section into the QDT */
void addQDTsection(QDBQH_T *qdtHdr, char *newSection,
  int newSize, int *offset)
{
    char *sectionPtr;

    /* position to the current end of the QDT */
    sectionPtr = (char *) qdtHdr + qdtHdr->qdbspcsize;
    /* append in the new section data */
    memcpy(sectionPtr, newSection, newSize);
    /* if an offset is to be stored, remember it now */
    if (offset != NULL)
        *offset = qdtHdr->qdbspcsize;
    /* update the QDT size */
    qdtHdr->qdbspcsize += newSize;
}


/* createAccessPlanSpace(access plan, user space name, size)
 - creates a *USRSPC object for storing the access plan */
long createAccessPlanSpace(ACCPLN_T *accessPlan, char *name,
  long spaceSize)
{
    QUSCUSAT_T chgAttr;
    _SPCPTR usrSpcPtr;
    char library[10];
    char value = (char) 0;
    char text[50];
    error_code errcode;

    errcode.bytes_provided = 512;

    strcpy400(text,"Access Plan for QQ API example",50);
    /* Create the User Space */
    QUSCRTUS(name,
             "ACCESSPLAN",
             spaceSize,
             &value,
             "*ALL      ",
             text,
             "*YES      ",
             &errcode,
             "*USER     ");
    if (errcode.msgid[0])
    {
        printf("Create User Space API failed!\n");
        printf("msgid = %7s\n", strcnv400(errcode.msgid,
          sizeof(errcode.msgid)));
        return(-1);
    }

    /* Change the User Space to allow Auto-Extend */
    strcpy400(library,&name[10],10);
    chgAttr.numAttrs = 1;
    chgAttr.key = 3; /* Auto extend */
    chgAttr.length = sizeof(char);
    chgAttr.data.autoExtend = '1';
    QUSCUSAT(library,
             name,
             &chgAttr,
             &errcode);
    if (errcode.msgid[0])
    {
        printf("Change User Space Attributes FAILED!\n");
        printf("msgid = %7s\n", strcnv400(errcode.msgid,
          sizeof(errcode.msgid)));
        return(-1);
    }

    /* Retrieve Space Pointer to the User Space */
    QUSPTRUS(name,
             &usrSpcPtr,
             &errcode);
    if (errcode.msgid[0])
    {
        printf("Retrieve Space Pointer to User Space FAILED!\n");
        printf("msgid = %7s\n", strcnv400(errcode.msgid,
          sizeof(errcode.msgid)));
        return(-1);
    }
    /* Now move to the access plan itself (on 16 byte boundary) */
    accessPlan->storagePtr = (_SPCPTR) ((char*) usrSpcPtr + 16);

    return(0);
}


/* saveAccessPlan(access plan)
 - update the size in the access plan (QQQQRY actually wrote the data) */
int saveAccessPlan(ACCPLN_T *accessPlan)
{
    _SPCPTR usrSpcPtr;

    /* Position to the start of the user space */
    usrSpcPtr = (_SPCPTR) ((char*) accessPlan->storagePtr - 16);
    /* Write the access plan size out at the start */
    memcpy(usrSpcPtr, (void *) &accessPlan->size,
      sizeof(accessPlan->size));
#ifdef QQDEBUG
    printf("AP size = %ld\n", accessPlan->size);
#endif
    return(0);
}


/* saveQDT(qdt, access plan)
 - append the QDT to the end of the access plan */
int saveQDT(QDBQH_T *qdtPtr, ACCPLN_T *accessPlan)
{
    _SPCPTR usrSpcPtr;

    /* Position to the just after the access plan */
    usrSpcPtr = (_SPCPTR) ((char*) accessPlan->storagePtr +
      accessPlan->size);
    /* Write the QDT size out */
    memcpy(usrSpcPtr, &qdtPtr->qdbspcsize, sizeof(qdtPtr->qdbspcsize));
#ifdef QQDEBUG
    printf("qdt size = %ld\n", qdtPtr->qdbspcsize);
#endif
    /* Move up the user space pointer */
    usrSpcPtr = (_SPCPTR) ((char *) usrSpcPtr + 16);
    /* Write the QDT itself out */
    memcpy(usrSpcPtr, qdtPtr, qdtPtr->qdbspcsize);
    return(0);
}


/* loadQDT(qdt, access plan)
 - load the QDT from the end of the access plan */
int loadQDT(QDBQH_T *qdtPtr, ACCPLN_T *accessPlan)
{
    _SPCPTR usrSpcPtr;

    /* Position to the just after the access plan */
    usrSpcPtr = (_SPCPTR) ((char*) accessPlan->storagePtr +
      accessPlan->size);
    /* Write the QDT size out */
    memcpy((void *) &qdtPtr->qdbspcsize, usrSpcPtr,
      sizeof(qdtPtr->qdbspcsize));
#ifdef QQDEBUG
    printf("qdt size = %ld\n", qdtPtr->qdbspcsize);
#endif
    /* Move up the user space pointer */
    usrSpcPtr = (_SPCPTR) ((char *) usrSpcPtr + 16);
    /* Write the QDT itself out */
    memcpy((void *) qdtPtr, usrSpcPtr, qdtPtr->qdbspcsize);
    return(qdtPtr->qdbspcsize);
}


/* loadAccessPlan(access plan, userspace name)
 - loads an access plan from a *USRSPC object */
long loadAccessPlan(ACCPLN_T *accessPlan, char *name)
{
    Qus_SPCA_0100_t usrSpcAttr;
    _SPCPTR usrSpcPtr;
    error_code errcode;

    errcode.bytes_provided = 512;
    errcode.msgid[0] = (char) 0;

    /* Retrieve Space Pointer to the User Space */
    QUSPTRUS(name, &usrSpcPtr, &errcode);
    if (errcode.msgid[0])
    {
        printf("Retrieve Space Pointer to User Space FAILED!\n");
        printf("msgid = %7s\n", strcnv400(errcode.msgid,
          sizeof(errcode.msgid)));
        return(0);
    }

    /* Retrieve Size of Access Plan */
    QUSRUSAT(&usrSpcAttr,
            sizeof(Qus_SPCA_0100_t),
            "SPCA0100",
            name,
            &errcode);
    if (errcode.msgid[0])
    {
        printf("Retrieve User Space Attributes FAILED!\n");
        printf("msgid = %7s\n", strcnv400(errcode.msgid,
          sizeof(errcode.msgid)));
        return(0);
    }
#ifdef QQDEBUG
    else
    {
        printf("Original User Space Attributes\n");
        printf("Bytes Returned  ==> %d\n",usrSpcAttr.Bytes_Returned);
        printf("Bytes Available ==> %d\n",usrSpcAttr.Bytes_Available);
        printf("Space Size      ==> %d\n",usrSpcAttr.Space_Size);
        printf("Auto Extend     ==> %c\n",
          usrSpcAttr.Automatic_Extendability);
    }
#endif
    /* Pull the access plan size out first */
    memcpy((void *) &accessPlan->size, usrSpcPtr,
      sizeof(accessPlan->size));
#ifdef QQDEBUG
    printf("AP size = %ld\n", accessPlan->size);
#endif
    /* Now move to the access plan itself (on 16 byte boundary) */
    accessPlan->storagePtr = (_SPCPTR) ((char*) usrSpcPtr + 16);

    return(accessPlan->size);
}


/********************************************************************/

Defining a simple query

This QQQQRY API example defines a simple query to perform ordering. The following is the equivalent SQL:

SELECT * FROM OPENFILE1
ORDER BY LNAME
/********************************************************************/
/*  PROGRAM:  QQAPI1                                                */
/*                                                                  */
/*  LANGUAGE:  ILE C                                  */
/*                                                                  */
/*  DESCRIPTION:  THIS PROGRAM DEFINES A SIMPLE QUERY TO PERFORM    */
/*    ORDERING.                                                     */
/*                                                                  */
/*  APIs USED:  QQQQRY                                              */
/*                                                                  */
/********************************************************************/


#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <recio.h>
#include <qdbrtvfd.h>
#include <qqqqry.h>
#include "qqapi.h"

/* get the record format from the file */
#pragma mapinc("recfmt","APIQQ/OPENFILE1(OPENFILE1)","input","p z",,)
#include "recfmt"



/* main - start of the program
 *
 * Flow:
 * - initialize variables
 * - override to set up sharing
 * - build various QDT sections
 * - build QDT with those sections
 * - QQQQRY to run the query
 * - open the data path
 * - read the data and display it
 * - close the data paths
 *
 */
main()
{
    /* record I/O variables */
    _RIOFB_T *feedback;
    _RFILE *file1;
    APIQQ_OPENFILE1_OPENFILE1_i_t recBuf;
    int recCount = 0;

    /* Query variables */
    QDBUFCB_T ufcbBuf;
    char qdtBuf[QDT_SIZE];
    char formatBuf[FORMAT_SIZE];
    QDBQH_T *qdtPtr;
    Qdb_Qddfmt_t *formatPtr;
    QDBQFHDR_T fileHdr;
    QDBQN_T fileSpec[MAX_FILES];
    QDBQKH_T orderByHdr;
    QDBQKF_T orderByFld[MAX_ORDERBY];
    int formatSize;
    int fileSpecSize;
    int orderBySize;
    error_code errcod;


    errcod.bytes_provided = 512;
    /* initialize the pointers */
    qdtPtr = (QDBQH_T *) qdtBuf;
    formatPtr = (Qdb_Qddfmt_t *) formatBuf;

    /* initialize the headers */
    initQDT(qdtPtr, QDBQTEMO, ON, ON, QDBQFINA, 0);
    initFile(&fileHdr, QDBQINNJ, QDBQMFOA);
    initOrderBy(&orderByHdr);

    /* set up override to allow sharing */
    system("OVRDBF FILE(OPENFILE1) SHARE(*YES)");
    /* Note:  If level checking is not done
       (ie. no format on initUFCB) then
       the override above must specify LVLCHK(*NO) */

    /* build the individual QDT sections */
    fileSpecSize = addFile(&fileHdr, fileSpec, "OPENFILE1",
      NULL, NULL, NULL);
    formatSize = getRecordFmt(formatPtr, FORMAT_SIZE, "OPENFILE1",
      NULL, NULL);
    orderBySize = addOrderBy(&orderByHdr, orderByFld, "LNAME", OFF);

    /* initialize the UFCB */
    initUFCB(&ufcbBuf, QO_INPUT, formatPtr);

    /* Now build the real QDT... */
    addQDTsection(qdtPtr, (char *) &fileHdr,
      sizeof(fileHdr), &qdtPtr->qdbqfilo);
    addQDTsection(qdtPtr, (char *) fileSpec, fileSpecSize, NULL);
    addQDTsection(qdtPtr, (char *) formatPtr,
      formatSize, &qdtPtr->qdbqfldo);
    addQDTsection(qdtPtr, (char *) &orderByHdr, sizeof(orderByHdr),
      &qdtPtr->qdbqkeyo);
    addQDTsection(qdtPtr, (char *) orderByFld, orderBySize, NULL);

    /* Finally, run the query! */
    QQQQRY("RUNQRY    ", (char *) &ufcbBuf, qdtBuf, NULL, NULL,
      &errcod);
    if (errcod.msgid[0])
    {
        printf("API QQQQRY failed\n");
        printf("msgid = %7s\n", strcnv400(errcod.msgid,
          sizeof(errcod.msgid)));
    }
    /* Now access the data */
    if ((file1 = _Ropen("OPENFILE1", "rr riofb=N")) == NULL)
    {
        printf("Error opening file\n");
        exit(1);
    }

    /* Perform any record I/O here... */
    _Rformat(file1, "OPENFILE1 ");
    printf("First name   Last name         State\n");
    feedback = _Rreadn(file1, (void *) &recBuf, sizeof(recBuf), __DFT);
    while (feedback->num_bytes == sizeof(recBuf))
    {
       recCount++;
       printf("%s   ", strcnv400(recBuf.FNAME, sizeof(recBuf.FNAME)));
       printf("%s   ", strcnv400(recBuf.LNAME, sizeof(recBuf.LNAME)));
       printf("%s\n",  strcnv400(recBuf.STATE, sizeof(recBuf.STATE)));
       feedback = _Rreadn(file1, (void *) &recBuf,
         sizeof(recBuf), __DFT);
    }
    printf("%d records selected\n", recCount);

    /* Close the file */
    _Rclose(file1);

    /* close out the QDT file handle */
    system("RCLRSC");
}

Defining a join query

This QQQQRY API example defines a join query. The following is the equivalent SQL:

SELECT * FROM OPENFILE1 A, OPENFILE2 B
WHERE STATE = 'AK' AND
      A.ACCTNUM = B.CUSTNUM
/********************************************************************/
/*  PROGRAM:  QQAPI7                                                */
/*                                                                  */
/*  LANGUAGE:  ILE C                                                */
/*                                                                  */
/*  DESCRIPTION:  THIS PROGRAM DEFINES A JOIN QUERY.                */
/*                                                                  */
/*  APIs USED:  QQQQRY                                              */
/*                                                                  */
/********************************************************************/


#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <recio.h>
#include <qdbrtvfd.h>
#include <qqqqry.h>
#include "qqapi.h"

/* get the record format from the file */
#pragma mapinc("recfmt","APIQQ/FORMAT1(FORMAT1)","input","p z",,)
#include "recfmt"



/* main - start of the program
 *
 * Flow:
 * - initialize variables
 * - override to set up sharing
 * - build various QDT sections
 * - build QDT with those sections
 * - QQQQRY to run the query
 * - open the data path
 * - read the data and display it
 * - close the data paths
 *
 */
main()
{
    /* record I/O variables */
    _RIOFB_T *feedback;
    _RFILE *file1;
    APIQQ_FORMAT1_FORMAT1_i_t recBuf;
    int recCount = 0;

    /* Query variables */
    QDBUFCB_T ufcbBuf;
    char qdtBuf[QDT_SIZE];
    char formatBuf[FORMAT_SIZE];
    char selectBuf[SELECT_SIZE];
    QDBQH_T *qdtPtr;
    Qdb_Qddfmt_t *formatPtr;
    QDBQS_T *selectPtr;
    QDBQFHDR_T fileHdr;
    QDBQN_T fileSpec[MAX_FILES];
    QDBQJHDR_T joinHdr;
    QDBQJFLD_T joinSpec[MAX_JOINTESTS];
    int formatSize;
    int fileSpecSize;
    int selectSize;
    int joinSize;
    error_code errcod;


    errcod.bytes_provided = 512;
    /* initialize the pointers */
    qdtPtr = (QDBQH_T *) qdtBuf;
    formatPtr = (Qdb_Qddfmt_t *) formatBuf;
    selectPtr = (QDBQS_T *) selectBuf;

    /* initialize the headers */
    initQDT(qdtPtr, QDBQTEMO, ON, ON, QDBQFINA, 0);
    initFile(&fileHdr, QDBQINNJ, QDBQMFOA);
    initSelection(selectPtr);
    initJoin(&joinHdr);

    /* set up override to allow sharing */
    system("OVRDBF FILE(OPENFILE1) SHARE(*YES) LVLCHK(*NO)");
    /* Note:  If level checking is not done
       (ie. no format on initUFCB) then
       the override above must specify LVLCHK(*NO) */

    /* build the individual QDT sections */
    addFile(&fileHdr, fileSpec, "OPENFILE1", NULL, NULL, NULL);
    fileSpecSize = addFile(&fileHdr, fileSpec, "OPENFILE2",
      NULL, NULL, NULL);
    formatSize = getRecordFmt(formatPtr, FORMAT_SIZE, "FORMAT1",
      NULL, NULL);
    joinSize = addJoinTest(&joinHdr, joinSpec, "ACCTNUM", 1,
      "CUSTNUM" , 2, "EQ");
    /* build selection test:  STATE = 'AK' */
    addSelectField(selectPtr, "STATE", 1);
    addSelectLiteral(selectPtr, "'AK'", 4);
    selectSize = addSelectOperator(selectPtr, QDBQEQ);

    /* initialize the UFCB */
    initUFCB(&ufcbBuf, QO_INPUT, NULL);

    /* Now build the real QDT... */
    addQDTsection(qdtPtr, (char *) &fileHdr,
      sizeof(fileHdr), &qdtPtr->qdbqfilo);
    addQDTsection(qdtPtr, (char *) fileSpec, fileSpecSize, NULL);
    addQDTsection(qdtPtr, (char *) formatPtr,
      formatSize, &qdtPtr->qdbqfldo);
    addQDTsection(qdtPtr, (char *) &joinHdr,
      sizeof(joinHdr),&qdtPtr->qdbqjoio);
    addQDTsection(qdtPtr, (char *) joinSpec, joinSize, NULL);
    addQDTsection(qdtPtr, (char *) selectPtr,
      selectSize, &qdtPtr->qdbqselo);

    /* Finally, run the query! */
    QQQQRY("RUNQRY    ", (char *) &ufcbBuf, qdtBuf, NULL, NULL,
      &errcod);
    if (errcod.msgid[0])
    {
        printf("API QQQQRY failed\n");
        printf("msgid = %7s\n", strcnv400(errcod.msgid,
          sizeof(errcod.msgid)));
    }
    /* Now access the data */
    if ((file1 = _Ropen("OPENFILE1", "rr riofb=N")) == NULL)
    {
        printf("Error opening file\n");
        exit(1);
    }

    /* Perform any record I/O here... */
    _Rformat(file1, "FORMAT1");
    printf("Last name        Item name\n");
    feedback = _Rreadn(file1, (void *) &recBuf, sizeof(recBuf), __DFT);
    while (feedback->num_bytes == sizeof(recBuf))
    {
       recCount++;
       printf("%s  ", strcnv400(recBuf.LNAME, sizeof(recBuf.LNAME)));
       printf("%s\n", strcnv400(recBuf.ITEMNAME,
         sizeof(recBuf.ITEMNAME)));
       feedback = _Rreadn(file1, (void *) &recBuf,
         sizeof(recBuf), __DFT);
    }
    printf("%d records selected\n", recCount);

    /* Close the file */
    _Rclose(file1);

    /* close out the QDT file handle */
    system("RCLRSC");
}

Defining a join query with selection, grouping, and ordering

This QQQQRY API example defines a join query with selection, grouping, and ordering. The following is the equivalent SQL:

SELECT LNAME, FNAME, ITEMCODE, ITEMNAME, STATUS
FROM OPENFILE1, OPENFILE2
WHERE STATE = 'AK' AND CUSTNUM = ACCTNUM
GROUP BY LNAME, FNAME, ITEMCODE, ITEMNAME, STATUS
ORDER BY ITEMNAME
/********************************************************************/
/*  PROGRAM:  QQAPI11                                               */
/*                                                                  */
/*  LANGUAGE:  ILE C                                                */
/*                                                                  */
/*  DESCRIPTION:  THIS PROGRAM DEFINES A JOIN QUERY WITH SELECTION  */
/*    GROUPING AND ORDERING.                                        */
/*                                                                  */
/*  APIs USED:  QQQQRY                                              */
/*                                                                  */
/********************************************************************/


#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <qdbrtvfd.h>
#include <qqqqry.h>
#include "qqapi.h">



/* main - start of the program
 *
 * Flow:
 * - initialize variables
 * - override to set up sharing
 * - build various QDT sections
 * - build QDT with those sections
 * - QQQQRY to run the query
 * - open the data path
 * - read the data and display it
 * - close the data paths
 *
 */
main()
{
    /* file I/O variables */
#define REC_SIZE  52
    FILE *file1;
    char recBuf[REC_SIZE];
    int recCount = 0, found;

    /* Query variables */
    QDBUFCB_T ufcbBuf;
    char qdtBuf[QDT_SIZE];
    char formatBuf[FORMAT_SIZE];
    char tempFormatBuf[FORMAT_SIZE];
    char selectBuf[SELECT_SIZE];
    QDBQH_T *qdtPtr;
    Qdb_Qddfmt_t *formatPtr;
    Qdb_Qddfmt_t *tempFormatPtr;
    QDBQS_T *selectPtr;
    QDBQFHDR_T fileHdr;
    QDBQN_T fileSpec[MAX_FILES];
    QDBQJHDR_T joinHdr;
    QDBQJFLD_T joinSpec[MAX_JOINTESTS];
    QDBQKH_T orderByHdr;
    QDBQGH_T groupByHdr;
    QDBQKF_T orderByFld[MAX_ORDERBY];
    QDBQGF_T groupByFld[MAX_GROUPBY];
    int formatSize;
    int fileSpecSize;
    int orderBySize;
    int groupBySize;
    int selectSize;
    int joinSize;
    error_code errcod;

    memset( (void *) &errcod, (char) 0, sizeof(error_code) );
    errcod.bytes_provided = 512;
    /* initialize the pointers */
    qdtPtr = (QDBQH_T *) qdtBuf;
    formatPtr = (Qdb_Qddfmt_t *) formatBuf;
    tempFormatPtr = (Qdb_Qddfmt_t *) tempFormatBuf;
    selectPtr = (QDBQS_T *) selectBuf;

    /* initialize the headers */
    initQDT(qdtPtr, QDBQTEMO, ON, ON, QDBQFINA, 0);
    initFile(&fileHdr, QDBQINNJ, QDBQMFOA);
    initFormat(formatPtr, "JOINFMT01");
    initOrderBy(&orderByHdr);
    initGroupBy(&groupByHdr);
    initSelection(selectPtr);
    initJoin(&joinHdr);

    /* set up override to allow sharing */
    system("OVRDBF FILE(OPENFILE1) SHARE(*YES) LVLCHK(*NO)");
    /* Note:  If level checking is not done
       (ie. no format on initUFCB) then
       the override above must specify LVLCHK(*NO) */

    /* build the individual QDT sections */
    addFile(&fileHdr, fileSpec, "OPENFILE1", NULL, NULL, NULL);
    fileSpecSize = addFile(&fileHdr, fileSpec, "OPENFILE2",
      NULL, NULL, NULL);
    /* get the first format and copy some fields */
    getRecordFmt(tempFormatPtr, FORMAT_SIZE, "OPENFILE1",
      NULL, NULL);
    copyField(formatPtr, "LNAME", 1, tempFormatPtr);
    copyField(formatPtr, "FNAME", 1, tempFormatPtr);
    /* clear the old format data */
    memset(tempFormatPtr, 0, FORMAT_SIZE);
    /* get the second format and copy some more fields */
    getRecordFmt(tempFormatPtr, FORMAT_SIZE, "OPENFILE2", NULL, NULL);
    copyField(formatPtr, "ITEMCODE", 2, tempFormatPtr);
    copyField(formatPtr, "ITEMNAME", 2, tempFormatPtr);
    formatSize = copyField(formatPtr, "STATUS", 2, tempFormatPtr);
    /* set all the fields to input only */
    setFieldUsage(formatPtr, NULL, 1);
    /* build selection test:  STATE = 'AK' */
    addSelectField(selectPtr, "STATE", 1);
    addSelectLiteral(selectPtr, "'AK'", 4);
    selectSize = addSelectOperator(selectPtr, QDBQEQ);
    joinSize = addJoinTest(&joinHdr, joinSpec, "ACCTNUM", 1,
      "CUSTNUM" , 2, "EQ");
    orderBySize = addOrderBy(&orderByHdr, orderByFld,
      "ITEMNAME", OFF);
    addGroupBy(&groupByHdr, groupByFld, "LNAME", 0);
    addGroupBy(&groupByHdr, groupByFld, "FNAME", 0);
    addGroupBy(&groupByHdr, groupByFld, "ITEMCODE", 0);
    addGroupBy(&groupByHdr, groupByFld, "ITEMNAME", 0);
    groupBySize = addGroupBy(&groupByHdr, groupByFld, "STATUS", 0);


    /* initialize the UFCB */
    initUFCB(&ufcbBuf, QO_INPUT, NULL);
    /* set up for sequential only processing since it is a group by */
    ufcbBuf.qufcb.parameter.seqonly = SEQUPROC;
    ufcbBuf.qufcb.parameter.seqonoff = ON;
    ufcbBuf.qufcb.parameter.numonoff = ON;
    ufcbBuf.qufcb.parameter.numrecs = 1;

    /* Now build the real QDT... */
    addQDTsection(qdtPtr, (char *) &fileHdr,
      sizeof(fileHdr), &qdtPtr->qdbqfilo);
    addQDTsection(qdtPtr, (char *) fileSpec, fileSpecSize, NULL);
    addQDTsection(qdtPtr, (char *) formatPtr,
      formatSize, &qdtPtr->qdbqfldo);
    addQDTsection(qdtPtr, (char *) &joinHdr,
      sizeof(joinHdr),&qdtPtr->qdbqjoio);
    addQDTsection(qdtPtr, (char *) joinSpec, joinSize, NULL);
    addQDTsection(qdtPtr, (char *) selectPtr,
      selectSize, &qdtPtr->qdbqselo);
    addQDTsection(qdtPtr, (char *) &orderByHdr, sizeof(orderByHdr),
      &qdtPtr->qdbqkeyo);
    addQDTsection(qdtPtr, (char *) orderByFld, orderBySize, NULL);
    addQDTsection(qdtPtr, (char *) &groupByHdr, sizeof(groupByHdr),
      &qdtPtr->qdbqgrpo);
    addQDTsection(qdtPtr, (char *) groupByFld, groupBySize, NULL);

    /* Finally, run the query! */
    QQQQRY("RUNQRY    ", (char *) &ufcbBuf, qdtBuf,
      NULL, NULL, &errcod);
    if (errcod.msgid[0])
    {
        printf("API QQQQRY failed\n");
        printf("msgid = %7s\n", strcnv400(errcod.msgid,
          sizeof(errcod.msgid)));
    }
    /* Now access the data */
    if ((file1 = fopen("OPENFILE1", "rb")) == NULL)
    {
        printf("Error opening file\n");
        exit(1);
    }

    /* Perform any record I/O here... */
    printf("Last name        First name  Code   \
Item                  St\n");
    found = fread((void *) &recBuf, REC_SIZE, 1, file1);
    while (found)
    {
       recCount++;
       printf("%s  ", strcnv400(recBuf, 15));
       printf("%s  ", strcnv400(&recBuf[15], 10));
       printf("%s  ", strcnv400(&recBuf[25], 5));
       printf("%s  ", strcnv400(&recBuf[30], 20));
       printf("%s\n", strcnv400(&recBuf[50], 2));
       found = fread((void *) &recBuf, REC_SIZE, 1, file1);
    }
    printf("%d records selected\n", recCount);

    /* Close the file */
    fclose(file1);

    /* close out the QDT file handle */
    system("RCLRSC");
}