Generic search

Search a table to find the group of records that begin with the same truncated version of the table key. Change the table organization to sequential if presently random, user-ordered or hash; this is necessary because the command Fetch Generic (FG) operates only on sequentially organized tables. Access the table using a generic key by setting the low order part of key to the delimiter (usually an asterisk *). The first FG command will retrieve the first row in the group, and subsequent calls will retrieve the rest of the group. The user must test the found code after each call to make sure the group or table has not been exhausted. For more information see Fetch Generic (FG).

In COBOL
 01 xxxx-SEARCH-KEY.
     05 xxxx-SEARCH-KEY-1      PIC X(04) VALUE 'aaaa'.
     05 xxxx-SEARCH-KEY-2      PIC X VALUE '*'.
     05 xxxx-SEARCH-KEY-3      PIC X(04).

 PROCEDURE DIVISION.

 *** SETUP SEQUENTIAL/BINARY SEARCH.
 *** CHANGE-ORG.
      MOVE LOW-VALUES TO xxxx-DEFINITION-BLOCK
      MOVE 'S' TO xxxx-ORG
      MOVE 'B' TO xxxx-METHOD
      MOVE 'CD' TO xxxx-COMMAND
      CALL 'TBLBASE' USING TB-PARM
                           xxxx-COMMAND-AREA
                           xxxx-DEFINE
 *** SET UP GENERIC KEY
      MOVE PART-NO-1 TO xxxx-SEARCH-KEY-1
      MOVE ZERO TO xxxx-COUNT
      MOVE 'FG' TO xxxx-COMMAND
      MOVE 'Y'  TO xxxx-FOUND
      PERFORM WHILE xxxx-FOUND = 'Y'
          CALL 'TBLBASE' USING TB-PARM
                               xxxx-COMMAND-AREA
                               xxxx-ROW-AREA
                               xxxx-SEARCH-KEY
          IF xxxx-FOUND = 'Y'
 ***          (process table row)
          END-IF
      END-PERFORM
In C
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "dkh.h"

/*
 * DK1TEX3C
 *
 * This program will fetch all rows which satisfy the generic
 * search condition (in this case, that their key starts with
 * the string "P").
 */
 
/*
 * Assume these are user inputs.
 */
static char szTableName[6] = "AARON";
static char szStatus[6] = "NYYYN";
static char szWritePassword[2] = " ";
static char szSearchKey[2] = "P";
static int nGen = 0;
static int nKeyLength = 1;

int main(void)
{
    TbParmStruct tbParm;
    TbCommandAreaStruct tbCommArea;
    TbTableDefinitionStruct tbTableDef;
    char * pRowArea = NULL;
    char * pSearchKey = NULL;
    char sStatus[8];
    char sTableName[8];
    int nGeneration = nGen;
    int notFound = 1;
 
    /*
     * Initialize the parameters.
     */
    fixStringLength( szTableName, sTableName, 8 );
    InitTbParm( &tbParm );
    InitTbCommandArea( &tbCommArea, sTableName );
    InitTableDef( &tbTableDef );
    
    /*
     * Initialize tableBASE with CS, ChangeStatus.
     */
    fixStringLength( szStatus, sStatus, 8 );
    memcpy( tbCommArea.tbCommand, "CS", 2 );
    TBLBASE( &tbParm, &tbCommArea, sStatus );
    if( tbCommArea.tbError != TB_SUCCESS )
    {
        printf( "CS\n");
        printf( "Found code: %c\n", tbCommArea.tbFound );
        printf( "Error code: %d\n", tbCommArea.tbError );
        printf( "Sub code: %d\n", tbCommArea.tbErrorSubcode );
        return tbCommArea.tbError;
    }
    
    /*
     * Setup Sequential/Binary Search with CD, ChangeDefinition.
     */
    memcpy( tbCommArea.tbCommand, "CD", 2 );
    tbTableDef.org = 'S';
    tbTableDef.method = 'B';
    TBLBASE( &tbParm, &tbCommArea, &tbTableDef, nGeneration );
    if( tbCommArea.tbError != TB_SUCCESS )
    {
        printf( "CD\n");
        printf( "Found code: %c\n", tbCommArea.tbFound );
        printf( "Error code: %d\n", tbCommArea.tbError );
        printf( "Sub code: %d\n", tbCommArea.tbErrorSubcode );
        return tbCommArea.tbError;
    }
    
    /*
     * GD, get table definition to retrieve the row length.
     */
    memcpy( tbCommArea.tbCommand, "GD", 2 );
    TBLBASE( &tbParm, &tbCommArea, &tbTableDef, nGeneration );
    if( (tbCommArea.tbError != TB_SUCCESS)
          || (tbCommArea.tbFound == 'N') )
    {
        printf( "GD\n");
        printf( "Found code: %c\n", tbCommArea.tbFound );
        printf( "Error code: %d\n", tbCommArea.tbError );
        printf( "Sub code: %d\n", tbCommArea.tbErrorSubcode );
        return tbCommArea.tbError;
    }
    
    /*
     * Allocate space for a row (with an additional string
     * terminator) and for the key.
     */
    pRowArea = (char *) malloc( tbTableDef.rowSize + 1 );
    if( pRowArea == NULL )
       return TB_ERROR;
    memset( pRowArea, ' ', tbTableDef.rowSize);
    pSearchKey = (char *) malloc( tbTableDef.keySize );
    if( pSearchKey == NULL )
    {
        free( pRowArea );
        return TB_ERROR;
    }
    memset( pSearchKey, ' ', tbTableDef.keySize );
    
    /*
     * Call tableBASE with FG, FetchGeneric.
     */
    memcpy( tbCommArea.tbCommand, "FG", 2 );
    tbCommArea.tbCount = 0;
    tbCommArea.tbFgKeyLength = nKeyLength;
    fixStringLength( szSearchKey, pSearchKey, tbTableDef.keySize );
    while( notFound )
    {
        TBLBASE( &tbParm, &tbCommArea, pRowArea, pSearchKey );
        if( tbCommArea.tbFound == 'Y' ) {
            pRowArea[tbTableDef.rowSize] = '\0';
            printf( "Found at Row %d: %s\n",
            tbCommArea.tbCount, pRowArea );
            notFound = 1;
        }
        else
        {
            notFound = 0;
        }
    }
    
    /*
     * Call tableBASE with CL, CloseTable.
     */
    memcpy( tbCommArea.tbCommand, "CL", 2 );
    TBLBASE( &tbParm, &tbCommArea );
    if( tbCommArea.tbError != TB_SUCCESS )
    {
        printf( "CL\n");
        printf( "Found code: %c\n", tbCommArea.tbFound );
        printf( "Error code: %d\n", tbCommArea.tbError );
        printf( "Sub code: %d\n", tbCommArea.tbErrorSubcode );
        free( pRowArea );
        free( pSearchKey );
        return tbCommArea.tbError;
    }
    if( pRowArea != NULL )
        free( pRowArea );
    if( pSearchKey != NULL )
        free( pSearchKey );
        
    return TB_SUCCESS;
}