17.10 - Sample Program - Access Module

Teradata® Tools and Utilities Access Module Programmer Guide

Product
Access Module
Release Number
17.10
Release Date
June 2021
Content Type
Programming Reference
Publication ID
B035-2424-061K
Language
English (United States)

amsample.c

/****************************************************************************/
/*                                                                          */
/*  Copyright 1997-2017 Teradata Corporation.                               */
/*  ALL RIGHTS RESERVED.                                                    */
/*  Teradata Corporation CONFIDENTIAL AND TRADE SECRET                      */
/*                                                                          */
/*  This copyrighted material is the Confidential, Unpublished              */
/*  Property of the Teradata Corporation.  This copyright notice            */
/*  and any other copyright notices included in machine readable            */
/*  copies must be reproduced on all authorized copies.                     */
/*                                                                          */
/* Purpose:  Present a sample Access Module that                            */
/* generates arbitrary data blocks without I/O                              */
/*                                                                          */
/* Max reads accepted is 100000000                                          */
/* Max logical records per block is 100000                                  */
/*                                                                          */
/*                                                                          */
/* Data returned conforms to the following TeraBuilder schema:              */
/*   DEFINE SCHEMA PRODUCT_SOURCE_SCHEMA                                    */
/*   DESCRIPTION 'PRODUCT INFORMATION SCHEMA'                               */
/*   (                                                                      */
/*      COL1 INTEGER,                                                       */
/*      COL2 INTEGER,                                                       */
/*      COL3 INTEGER,                                                       */
/*      COL4 VARCHAR(7)                                                     */
/*   );                                                                     */
/*                                                                          */
/* Initialization string:                                                   */
/*  "BLOCKCOUNT=<i>,RECORDCOUNT=<j>,TRACE <filename> <tracelevel>"          */
/*                                                                          */
/*  Contents:                                                               */
/*            PIDMMain - receives all Access Module calls from the          */
/*                       Teradata Client Utility via the Data Connector.    */
/*                                                                          */
/****************************************************************************/
#include <stdio.h>
#include <string.h>
#include "pmdcomt.h"
#include "pmddamt.h"
/*#define TPT_VERSION 1 */
#ifdef TPT_VERSION
#define MODULE_NAME "amsample_TPT"
#define ENVIRONMENT "Teradata Parallel Transporter"
#else
#define MODULE_NAME "amsample_SA"
#define ENVIRONMENT "Teradata Standalone Utilities"
#endif
#define MODULE_VERS "17.10.00.00"                            /* SRC_ID */
/*#define TEST_TIMEOUT 1 */
/* Initialization string keywords */
#define MAX_PARMS 256 /* maximum init string parms accepted */
#define Help_KEYWORD            "HELP"
/* Number of blocks to return */
#define BlockCount_KEYWORD      "BLOCKCOUNT"
#define BlockCount_MAX          100000000
#define BlockCount_DEFAULT      10
/* Number of records returned per block */
#define RecordsPerBlock_KEYWORD "RECORDCOUNT"
#define RecordsPerBlock_MAX     100000
#define RecordsPerBlock_DEFAULT 10
/* Log file name */
#define Trace_KEYWORD           "TRACE"
static char                     SG_ErrorText[pmiMAX_ETEXT_LEN+1];
static size_t           SG_ErrorTextLen=0;
static pmTrceLvl_t      SG_TraceLevel=pmTrceEvents;
static FILE                     *SG_AMlogFp=NULL;
static char          AXMAttr_1[]  = "AXSM AXM attribute #1 value";
static char          FileAttr_1[] = "AXSM File attribute #1 value";
static unsigned long SG_BlocksToEOF;
static unsigned long SG_RecsPerBlock;
static char AMlogFName[pmiMAX_FNAME_LEN+1];
static long SG_TimeOutSeconds;
typedef struct _LogRec
{
  pmUInt16 RecLength;
  pmUInt16 Filler1;
  pmUInt32 I_RecNum;
  pmUInt32 I_block;
  pmUInt32 I_Dummy;
  pmUInt16 Filler2;
  pmUInt16 I_charlen;
  char     V_char[7];
  char     EOR;
} LogRec_t;
#define MAX_MSGSTR_LEN 1024
#define TRACE_LOG_MAX_LENGTH MAX_MSGSTR_LEN+256
static char MsgStr[MAX_MSGSTR_LEN];
/* MACRO definitions */
#define TRCELOG(MsgTraceLevel,Format,variable) \
if ( SG_TraceLevel>=MsgTraceLevel )            \
   {                                           \
    char Trcetext[TRACE_LOG_MAX_LENGTH];       \
    sprintf (Trcetext,Format,variable);        \
        AMlog(Trcetext);                           \
   }
#define EXIT_FAILURE() \
SG_ErrorTextLen = strlen(SG_ErrorText); \
AMstdout(SG_ErrorText);                 \
return pmrcFailure;
#define CHECK_ARG_PRESENT(index) \
if ( index+1 >= argc )\
{\
sprintf (SG_ErrorText,"option %s: argument missing",argv[index]);\
EXIT_FAILURE();\
}\
if ( strlen(argv[index+1]) == 0 )\
{\
sprintf (SG_ErrorText,"option %s: argument missing",argv[index]);\
EXIT_FAILURE();\
}
***********************************************************************/
/* AMlog */
***********************************************************************/
static void AMlog ( char *str )
{
if ( SG_AMlogFp != NULL )
{
    fprintf (SG_AMlogFp,"%s\n",str);
    fflush (SG_AMlogFp);
}
return;
}
/***********************************************************************/
/* AMstdout                                                            */
/* (Access Module standard output)                                     */
/* Used when trace file not open.                                      */
/***********************************************************************/
static void AMstdout ( char *str )
{
/* If used with Teradata Parallel Transporter,                         */
/* stdout may by blocked (bit-bucket)                                  */
/* Send all stdout to a predefined file.                               */
/* (could be a parameter)                                              */

#if defined (TPT_VERSION)
#define AMstdoutFName "AMstdout.txt"
static FILE *AMstdoutFp=NULL;
if ( AMstdoutFp == NULL )  AMstdoutFp = fopen(AMstdoutFName,"w");
if ( AMstdoutFp != NULL )
{
    fprintf (AMstdoutFp,"%s: %s\n",MODULE_NAME,str);
    fflush (AMstdoutFp);
}
/* If used with Standalone Utilities, stdout is available */
#else
printf ( "%s: %s\n",MODULE_NAME,str );
#endif
AMlog(str); /* ALL stdout should be in log */
return;
}
/**********************************************************************/
/* ShowParms */
/* Display AM parameters */
/**********************************************************************/
#undef CurrentFunction
#define CurrentFunction "ShowParms"
static void ShowParms ( )
{
AMstdout("Parameters:");

/* Help */
sprintf(MsgStr,"%s: Show this information\n\tsyntax %s",
                Help_KEYWORD,Help_KEYWORD);
AMstdout(MsgStr);

/* BLOCKCOUNT <value> */
sprintf(MsgStr,"%s: %s\n\t%s\n\tsyntax: %s %s %d\n\t%s %d",
        BlockCount_KEYWORD,
        "Specifies the number of record blocks to return.",
        "When this value has been satisfied, an end-of-file will be returned.",

        BlockCount_KEYWORD,
        "<count> where <count> is within the range of 1 to",
        BlockCount_MAX,
        "the default is",
        BlockCount_DEFAULT);
AMstdout(MsgStr);

/* RECORDCOUNT <value> */
sprintf(MsgStr,"%s: %s\n\tsyntax: %s %s %d\n\t%s %d",
                RecordsPerBlock_KEYWORD,
                "Specifies the number of records returned in each block.",
                RecordsPerBlock_KEYWORD,
                "<count> where <count> is within the range of 1 to",
                RecordsPerBlock_MAX,
                "the default is",
                RecordsPerBlock_DEFAULT);
AMstdout(MsgStr);

/* TRACE <filename> <tracelevel> */
sprintf(MsgStr,"%s: %s\n\tsyntax: %s %s \n\t%s \n\t%s %d and %d",
                Trace_KEYWORD,
                "Specifies both the filename and trace level for the log",
                Trace_KEYWORD,
                "<filename> <tracelevel>",
                "where <filename> is any valid file system object",
                "and <tracelevel> is between",
                pmTrceNone,pmTrceInfo);
AMstdout(MsgStr);
return;
}
/**********************************************************************/
/* ParseParms                                                         */
/* parse init string                                                  */
/**********************************************************************/
#undef CurrentFunction
#define CurrentFunction "ParseParms"
static pmReturnType ParseParms ( pmiInit_t* Parms )
{
char *pParameter;
int   i, j, ipos, ioffs, rc;
pmReturnType retcode;
char    *argv[MAX_PARMS];
int             argc;
int             initstrl;
int             bUseParmFile = 0;
if ((initstrl = Parms->InitStrL) > 0)  pParameter = Parms->InitStr;
else
{
        sprintf(SG_ErrorText,"!ERROR! Empty initialization string");
        EXIT_FAILURE();
}
/* =================================== convert initstr to argc argv */
ipos = ioffs = 0;
argc = 0;
for (i=0;i<MAX_PARMS;i++)  argv[i] = 0;
while (ipos < initstrl)
{
/* get offset to next non-whitespace */
        ioffs = strspn(&pParameter[ipos]," \n\t\r\f");
        ipos = ipos + ioffs;
        if (ipos >= initstrl)  break;
        /* get offset to next whitespace */
        ioffs = strcspn(&pParameter[ipos]," \n\t\r\f\0");
        if ( argc > MAX_PARMS-1 )
        {
           sprintf(SG_ErrorText,"Too many initialization string parameters");
           EXIT_FAILURE();
        }
        argv[argc] = (char*)malloc(ioffs+1);
        strncpy(argv[argc],&(pParameter[ipos]),ioffs);
        memcpy(argv[argc]+(ioffs),"\0",1);
        ipos = ipos+ioffs;
        argc++;
}
if ( argc < 1 )
{
        sprintf(SG_ErrorText,"Empty initialization string");
        EXIT_FAILURE();
}
argv[argc] = 0;
SG_BlocksToEOF = 0;
SG_RecsPerBlock = 0;
AMlogFName[0] = '\0';
SG_TraceLevel = pmTrceNone;
/* ============================ process initstr arguments and values */
i=0;
retcode = pmrcOK;
do
{
        int bValidKeywordFound = 0;
        char KeyWord[100];
        for (j=0;j<strlen(argv[i]);j++) argv[i][j] = toupper(argv[i][j]);
        strcpy(KeyWord,argv[i]);
        sprintf(MsgStr,"Parameter Keyword: '%s'",KeyWord);
        AMstdout(MsgStr);
        if ( !strcmp(KeyWord,Help_KEYWORD) )
        {
                ShowParms();
                bValidKeywordFound = 1;
                i++;
        }
        if ( !strcmp(KeyWord,BlockCount_KEYWORD) )
        {
            CHECK_ARG_PRESENT (i);
            SG_BlocksToEOF = atol (argv[i+1]);
            if (    SG_BlocksToEOF > BlockCount_MAX ||
                    SG_BlocksToEOF < 1 )
            {
                sprintf SG_ErrorText,"Invalid '%s' keyword value (%d). %s %d",
                         KeyWord,SG_BlocksToEOF,
                         "Valid range is 1 to",BlockCount_MAX);
                EXIT_FAILURE();
            }

            bValidKeywordFound = 1;
            i = i + 2;
        }
        if ( !strcmp(KeyWord,RecordsPerBlock_KEYWORD) )
        {
            CHECK_ARG_PRESENT (i);
            SG_RecsPerBlock = atol (argv[i+1]);
            if (    SG_RecsPerBlock > RecordsPerBlock_MAX ||
                    SG_RecsPerBlock < 1 )
            {
                sprintf (SG_ErrorText,"Invalid '%s' keyword value (%d). %s %d",
                        KeyWord,SG_RecsPerBlock,
                        "Valid range is 1 to",RecordsPerBlock_MAX);
                EXIT_FAILURE();
            }
            bValidKeywordFound = 1;
            i = i + 2;
        }
        if ( !strcmp(KeyWord,Trace_KEYWORD) )
        {
            CHECK_ARG_PRESENT (i);
            if ( strlen(argv[i+1]) > pmiMAX_FNAME_LEN )
            {
                sprintf (SG_ErrorText,"Invalid '%s' keyword value (%s). %s %d",
                         KeyWord,argv[i+1],
                         "Maximum length is",pmiMAX_FNAME_LEN );
                EXIT_FAILURE();
            }
            strcpy(AMlogFName,argv[i+1]);
            if ( argc < i+2 )
            {
                sprintf (SG_ErrorText,"Keyword '%s' %s (trace level) expected",
                         KeyWord,"second parmameter");
                EXIT_FAILURE();
            }
            SG_TraceLevel = atol (argv[i+2]);
            if ( SG_TraceLevel < pmTrceNone || SG_TraceLevel> pmTrceInfo )
            {
                sprintf (SG_ErrorText,"Invalid '%s' %s (%d). %s %d to %d",
                    KeyWord,"keyword value",SG_TraceLevel,
                    "Valid range is",pmTrceNone,pmTrceInfo);
                EXIT_FAILURE();
            }
            bValidKeywordFound = 1;
            i = i + 3;
        }
        if ( !bValidKeywordFound )
        {
                sprintf(MsgStr,"Keyword '%s' ignored - not recognized",KeyWord);
                AMstdout(MsgStr);
                i++;
        }
}       while ( i<argc && retcode == pmrcOK );
/* free up memory */
for (i=0;i<MAX_PARMS;i++) {if (argv[i] != 0)  free(argv[i]);}


/* =============== Confirm that required parameters have been defined */
/* and display parameters in effect                                   */
if ( !SG_BlocksToEOF )
{
        SG_BlocksToEOF = BlockCount_DEFAULT;
        sprintf(MsgStr,"Keyword '%s' not provided. %s.",BlockCount_KEYWORD,
                "It's value will be set to the default");
        AMstdout(MsgStr);
}
sprintf(MsgStr,"Keyword '%s' value defined as %d.",
                BlockCount_KEYWORD,SG_BlocksToEOF);
AMstdout(MsgStr);
if ( !SG_RecsPerBlock )
{
        SG_RecsPerBlock = RecordsPerBlock_DEFAULT;
        sprintf(MsgStr,"Keyword '%s' not provided. %s.",RecordsPerBlock_KEYWORD,
                "It's value will be set to the default");
        AMstdout(MsgStr);
}
sprintf(MsgStr,"Keyword '%s' value defined as %d.",
        RecordsPerBlock_KEYWORD,SG_RecsPerBlock);
AMstdout(MsgStr);
if ( strlen(AMlogFName) )
{
        sprintf(MsgStr,"Keyword '%s' value defined as '%s' '%d'",
                        Trace_KEYWORD,AMlogFName,SG_TraceLevel);
}
else sprintf(MsgStr,"Keyword '%s' not defined",Trace_KEYWORD);
AMstdout(MsgStr);
return pmrcOK;
}
/****************************************************************************/
/****************************************************************************/
/* Main routine                                                             */
/****************************************************************************/
/****************************************************************************/
#ifdef WIN32
__declspec(dllexport)
#endif
void PIDMMain ( pmiCmdBlock_t *Opts, void *OptParms )
{
pmReturnType      retcode=pmrcOK;
static pmUInt32 SG_BufferLen;
static pmUInt32 SG_rec_cnt;
static pmUInt32 SG_block_cnt;
static LogRec_t SG_LogicalRecords[RecordsPerBlock_MAX];
pmUInt32 i;
pmUInt16 RecLength;
char *cptr;
static bHeadersAnnounced = 0;
char AtrName[pmMAX_ATR_NAME_LEN+1];
/* Announce which version of the header files were used                       */
/* at compile time.  If the wrong headers, or packing option,                 */
/* were used, everything goes south without explanation.                */
/* We do this before any of the parameters are referenced.              */
/* So, if things go awry, we'll know if this was the problem.           */
if ( !bHeadersAnnounced )
{
        AMstdout(PM_COPYRIGHT_NOTICE);
        sprintf (       MsgStr,"Sample Access Module ('%s') Version: %s.",
                                MODULE_NAME,MODULE_VERS);
        AMstdout(MsgStr);
        sprintf (MsgStr,"Compiled for %s (%s).",PLATFORM_ID,ENVIRONMENT);
        AMstdout(MsgStr);
        AMstdout(pmdcomt_ID);
        AMstdout(pmddamt_ID);
        bHeadersAnnounced = 1;
}
/****************************************************************************/
/* This is the main decision block                                          */
/* Specific action taken is determined by the value                         */
/* of the Reqtype field in the Opts parameter                               */
/****************************************************************************/
switch (Opts->Reqtype)                            /* switch on request type */
{
/*--------------------------------------------------------------------------*/
/* AXSM Initialization                                                      */
/*--------------------------------------------------------------------------*/
     case pmiPIDMOptInit:
                TRCELOG(pmTrceInfo,"%s","Entry pmiPIDMOptInit");
/* Make sure the the headers used by the DataConnector                      */
/* are the same versions that this AXSM used                                */
/* when compiling!                                                          */
        if (  ((pmiInit_t*)OptParms)->InterfaceVerNo  != pmInterfaceVersionD
           || ((pmiInit_t*)OptParms)->InterfaceVerNoD != pmiInterfaceVersion )
           retcode = pmrcBadVer;
/* Set that all important AXSM identifying void pointer                     */
/* that the AXSM can use for anything                                       */
        ((pmiInit_t*)OptParms)->PIData = 0;
/* Examine init string */
        retcode = ParseParms( (pmiInit_t*)OptParms );
        if ( retcode )  break;
        if ( SG_TraceLevel > pmTrceNone )
        {
            SG_AMlogFp = fopen(AMlogFName,"w");
            if ( SG_AMlogFp == NULL )  AMstdout("Trace log file open failed!");
        }
        AMlog(PM_COPYRIGHT_NOTICE);
        sprintf (MsgStr,"Sample Access Module ('%s') Version: %s.",
                        MODULE_NAME,MODULE_VERS);
        AMlog(MsgStr);
        sprintf (MsgStr,"Compiled for %s (%s).",PLATFORM_ID,ENVIRONMENT);
        AMlog(MsgStr);
        AMlog(pmdcomt_ID);
        AMlog(pmddamt_ID);
        switch ( SG_TraceLevel )
        {
            case pmTrceNone:
                sprintf (MsgStr,"Trace level set to 'None' (%d)",pmTrceNone);
                break;
            case pmTrceEvents:
                sprintf (MsgStr,"Trace level set to 'Events' (%d)",
                                pmTrceEvents);
                break;
            case pmTrceIOcounts:
                sprintf (MsgStr,"Trace level set to 'IOcounts' (%d)",
                                pmTrceIOcounts);
                break;
            case pmTrceIObufs:
                sprintf (MsgStr,"Trace level set to 'IObufs' (%d)",
                                pmTrceIObufs);
                break;
            case pmTrceInfo:
                sprintf (MsgStr,"Trace level set to 'Info' (%d)",pmTrceInfo);
                break;
            default:
                sprintf (MsgStr,"%s (%d) %s (%d)",
                    "Invalid trace level",SG_TraceLevel,
                    "reset to 'Events'",pmTrceEvents);
                SG_TraceLevel = pmTrceEvents;
        }
        AMlog(MsgStr);
        sprintf (MsgStr,"AM will provide %d blocks of %d records each %s",
                         SG_BlocksToEOF,SG_RecsPerBlock,
                         "in 'FastLoad' format (pmIDFBin1Plus)");
        AMstdout(MsgStr);
        break;
/*--------------------------------------------------------------------------*/
/* File Open                                                                */
/*--------------------------------------------------------------------------*/
     case pmiPIDMOptOpen:
                TRCELOG(pmTrceInfo,"%s","Entry pmiPIDMOptOpen");
       SG_block_cnt = 0;                       /* set 'blocks read' to zero */
       SG_BufferLen = 0;               /* Initialize 'actual' buffer length */
       SG_rec_cnt = 0;                   /* set 'records generated' to zero */
/*                         Fill in 'SG_LogicalRecords' for subsequent reads */
/*                                Format as 'text' data (trailing EOR byte) */
       RecLength = sizeof(SG_LogicalRecords[0]) -
                   sizeof(SG_LogicalRecords[0].RecLength) -
                   sizeof(SG_LogicalRecords[0].EOR);
       for (i=0;i<SG_RecsPerBlock;i++)
           {
            SG_LogicalRecords[i].RecLength = RecLength;
            SG_LogicalRecords[i].I_RecNum = 0;
            SG_LogicalRecords[i].I_block  = 1;
            SG_LogicalRecords[i].I_Dummy  = 222;
            SG_LogicalRecords[i].I_charlen = 7;
            strcpy(SG_LogicalRecords[i].V_char,"XasciiX");
            SG_LogicalRecords[i].EOR = 0x0a;
           }
       SG_BufferLen = SG_RecsPerBlock*sizeof(SG_LogicalRecords[0]);
/* Fill in device max block size, internal header length                    */
/* and that all important file identifying void pointer                     */
/* that the Access Module can use for anything                              */
       ((pmiOpen_t*)OptParms)->BlkSize = SG_BufferLen;
       ((pmiOpen_t*)OptParms)->BlkHeaderLen = 0;
       ((pmiOpen_t*)OptParms)->FIData = 0;
       break;
/*--------------------------------------------------------------------------*/
/* File Close                                                               */
/*--------------------------------------------------------------------------*/
     case pmiPIDMOptClose:
     case pmiPIDMOptCloseR:
                TRCELOG(pmTrceInfo,"%s","Entry pmiPIDMOptClose[R]");
       break;
/*--------------------------------------------------------------------------*/
/* Read                                                                     */
/*--------------------------------------------------------------------------*/
     case pmiPIDMOptRead:
         TRCELOG(pmTrceInfo,"%s","Entry pmiPIDMOptRead");
/* EOF? */
         SG_block_cnt++;
         if ( SG_block_cnt > SG_BlocksToEOF )
         {
             TRCELOG(pmTrceEvents,"%s","End-of-File");
                     ((pmiRW_t*)OptParms)->BufferLen = 0;
             retcode = pmrcEOF;
             break;
         }
#ifdef TEST_TIMEOUT
         if ( SG_block_cnt > 1 )
         {
             TRCELOG(pmTrceEvents,"%s","Arbitrary timeout");
             ((pmiRW_t*)OptParms)->BufferLen = 0;
             retcode = pmrcTimeout;
             break;
         }
#endif
/* Update MyBuffer for this read */
         for (i=0;i<SG_RecsPerBlock;i++)
         {
              SG_rec_cnt++;
              SG_LogicalRecords[i].I_RecNum = SG_rec_cnt;
              SG_LogicalRecords[i].I_block  = SG_block_cnt;
         }
/* Copy generated block to DataConnector buffer */
         memcpy( ((pmiRW_t*)OptParms)->Buffer,SG_LogicalRecords,SG_BufferLen);
/* Return the record length */
         ((pmiRW_t*)OptParms)->BufferLen = SG_BufferLen;
         if ( SG_AMlogFp != NULL )
         {
             TRCELOG(pmTrceInfo,"%s","calling amHexDmp() for local copy");
             amHexDmp (  SG_AMlogFp,(char *)SG_LogicalRecords,
                         (unsigned)SG_BufferLen,"i->",1);
             TRCELOG(pmTrceInfo,"%s","calling amHexDmp() for interface copy");
             amHexDmp (  SG_AMlogFp,(char *)((pmiRW_t*)OptParms)->Buffer,
                        (unsigned)((pmiRW_t*)OptParms)->BufferLen,"x->",1);
         }
         TRCELOG(pmTrceInfo,"%s","Exit pmiPIDMOptRead");
     break;
/*--------------------------------------------------------------------------*/
/* Get and Put Access Module or File attributes                             */
/*--------------------------------------------------------------------------*/
     case pmiPIDMOptGetA_A:
         TRCELOG(pmTrceInfo,"%s","Entry pmiPIDMOptGetA_A");
         strcpy (AtrName,((pmiAttr_t*)OptParms)->AttrName);
         if ( strcmp(AtrName,"AXMAttribute#1") )
         {
             sprintf(MsgStr,"Attribute '%s' not recognized. %s",
                     AtrName,"Value can not be supplied");
             retcode = pmrcBadAttrName;
         }
         else
         {
             sprintf(MsgStr,"Attribute '%s' recognized. %s '%s' returned",
                             AtrName,"Value",AXMAttr_1);
             strcpy(&((pmiAttr_t*)OptParms)->AttrValue[0],AXMAttr_1);
                    ((pmiAttr_t*)OptParms)->AttrValueLen = strlen(AXMAttr_1);
         }
         break;
     case pmiPIDMOptGetF_A:
         TRCELOG(pmTrceInfo,"%s","Entry pmiPIDMOptGetF_A");
         strcpy (AtrName,((pmiAttr_t*)OptParms)->AttrName);
         if ( strcmp(AtrName,"FileAttribute#1") )
         {
             sprintf(MsgStr,"Attribute '%s' not recognized. %s",
                     AtrName,"Value can not be supplied");
             retcode = pmrcBadAttrName;
         }
         else
         {
             sprintf(MsgStr,"Attribute '%s' recognized. %s '%s' returned",
                            AtrName,"Value",FileAttr_1);
             strcpy(&((pmiAttr_t*)OptParms)->AttrValue[0],FileAttr_1);
             ((pmiAttr_t*)OptParms)->AttrValueLen = strlen(FileAttr_1);
         }
         AMstdout(MsgStr);
         break;
/* Handle/receive attributes with Access Module scope */
     case pmiPIDMOptPutA_A:
         TRCELOG(pmTrceInfo,"%s","Entry pmiPIDMOptPutA_A");
         strcpy (AtrName,((pmiAttr_t*)OptParms)->AttrName);
         sprintf (MsgStr,"Received AXSMOD attribute '%s'",AtrName);
         TRCELOG(pmTrceEvents,"%s",MsgStr);
         sprintf (MsgStr,"Checking for valid %s attributes",ENVIRONMENT);
         TRCELOG(pmTrceEvents,"%s",MsgStr);
/* TPT_VERSION symbol                                                   */
/* tells us that we're compiling for use with the                       */
/* Teradata Parallel Transporter environment                            */
#ifdef TPT_VERSION
{
#include "pxoper.h"
PX_OperatorHandle operatorHandle;
char *cPtr;
PX_Length PX_Len;
PXSTC_Code PX_rc;
/* TPT operator handle */
#define MY_TPT_DC_ATTR_VALUE  "SAMPLE_ATTR_CHAR_VALUE"
#define AM_ATTR_TPT_DCOP_AM_NAME "AccessModuleName"
        if ( strcmp(AtrName,PM_ATR_TPT_OP_HANDLE))
        {
                sprintf (MsgStr,"Rejected attribute: '%s'",AtrName);
                AMstdout(MsgStr);
                retcode = pmrcBadAttrName;
                break;
        }
        sprintf (MsgStr,"Recognized attribute: '%s'",AtrName);
        AMstdout(MsgStr);
        memcpy((char*)&operatorHandle,((pmiAttr_t*)OptParms)->AttrValue,
                             ((pmiAttr_t*)OptParms)->AttrValueLen);
        sprintf(MsgStr,"%s: operatorHandle=x'%x'",MODULE_NAME,operatorHandle);
        TRCELOG(pmTrceEvents,"%s",MsgStr);
/* With the Teradata Parallel Transporter operator handle,                    */
/* All the TPT DataConnector operator attributes are available.               */
/* First, we get the Access Module name attribute.  This attribute            */
/* is the name of this module and must have existed in order to               */
/* get this Access Module running.                                            */
/* The symbol AM_ATTR_TPT_DCOP_AM_NAME is defined in pxoper.h                 */
        sprintf (MsgStr,"Retrieving attribute '%s'",AM_ATTR_TPT_DCOP_AM_NAME);
        AMstdout(MsgStr);
        PX_rc = PX_GetAttribute(operatorHandle,
                                AM_ATTR_TPT_DCOP_AM_NAME,
                                (PX_AttributeValue*)&cPtr,&PX_Len);
        if ( PX_rc == PX_NotFound )
                sprintf (MsgStr,"Attribute '%s' not found.",
                                AM_ATTR_TPT_DCOP_AM_NAME);
        else if ( PX_rc )
                sprintf (MsgStr,"PX_GetAttribute failed, rc=%d",
                                AM_ATTR_TPT_DCOP_AM_NAME);
        else sprintf (MsgStr,"Retrieved attribute value '%s'",cPtr);
        AMstdout(MsgStr);
/* The symbol MY_TPT_DC_ATTR_VALUE is defined within this Access Module.     */
/* As it is used here, it is a VARCHAR and appears in the DataConnector's    */
/* attribute definition list as:                                             */
/* VARCHAR SAMPLE_ATTR_CHAR_VALUE,                                           */
        sprintf (MsgStr,"Retrieving attribute '%s'",MY_TPT_DC_ATTR_VALUE);
        AMstdout(MsgStr);
        PX_rc = PX_GetAttribute(operatorHandle,
                                 MY_TPT_DC_ATTR_VALUE,
                                 (PX_AttributeValue*)&cPtr,&PX_Len);
        if ( PX_rc == PX_NotFound )
             sprintf (MsgStr,"Attribute '%s' not found.",MY_TPT_DC_ATTR_VALUE);
        else if ( PX_rc )
              sprintf (MsgStr,"PX_GetAttribute failed, rc=%d",
                                MY_TPT_DC_ATTR_VALUE,PX_rc);
        else sprintf (MsgStr,"Retrieved attribute value '%s'",cPtr);
        AMstdout(MsgStr);
}
#else
/* Handle attributes received from the standalone utilities                 */
{
/* ATTRIBUTE DEFINES SHOULD (but do not have to) BE IN HEADER               */
/* pmdcomt.h - available to AMs and DC clients                              */
        if (!strcmp(AtrName,PM_ATR_NAME_TIMEOUT))
        {
            char AtrValue[100];
            strcpy (AtrValue,((pmiAttr_t*)OptParms)->AttrValue);
            SG_TimeOutSeconds = atol (AtrValue);
            sprintf (MsgStr,"Recognized attribute: '%s' = %d seconds",
                              AtrName,SG_TimeOutSeconds);
        }
        else if (!strcmp(AtrName,PM_ATR_NAME_CHARSET_NAME)   ||
                        !strcmp(AtrName,PM_ATR_NAME_CHARSET_NUMBER) ||
                        !strcmp(AtrName,PM_ATR_NAME_WR_BOM)         ||
                        !strcmp(AtrName,PM_ATR_NAME_BYTE_ORDER)         )
        {
                sprintf (MsgStr,"Recognized attribute: '%s' %s",
                                AtrName,"(no action taken)");
        }
        else
        {
                sprintf (MsgStr,"Unrecognized attribute: '%s'",AtrName);
                retcode = pmrcBadAttrName;
        }
        AMstdout(MsgStr);
}
#endif
       break;
        case pmiPIDMOptPutF_A:
                TRCELOG(pmTrceInfo,"%s","Entry pmiPIDMOptPutF_A");
                strcpy (AtrName,((pmiAttr_t*)OptParms)->AttrName);
                sprintf (MsgStr,"Received FILE attribute '%s'",AtrName);
                TRCELOG(pmTrceEvents,"%s",MsgStr);
                if ( !strcmp( AtrName,"FileAttribute#1") )
                {
                        sprintf (MsgStr,"Recognized attribute: '%s' %s",
                                        AtrName,"(no action taken)");
                }
                else
                {
                    sprintf (MsgStr,"Unrecognized attribute: '%s'",AtrName);
                    retcode = pmrcBadAttrName;
                }
                AMstdout(MsgStr);
                break;
/*--------------------------------------------------------------------------*/
/* Access Module shutdown                                                   */
/*--------------------------------------------------------------------------*/
        case pmiPIDMOptShut:
                TRCELOG(pmTrceInfo,"%s","Entry pmiPIDMOptShut");
/*                              If any files are currently open, close them */
                retcode = pmrcOK;
                break;
/*--------------------------------------------------------------------------*/
/* Access Module identification                                             */
/*--------------------------------------------------------------------------*/
     case pmiPIDMOptID:
         TRCELOG(pmTrceInfo,"%s","Entry pmiPIDMOptID");
/*      Supply the single module name for this Access Module identification */
/*                 If more modules are added, their identifying information */
/*                          must be appended to the list via VerIDList.Next */
         strcpy( ((pmiID_t*)OptParms)->VerIDList.ModuleName,MODULE_NAME);
         strcpy( ((pmiID_t*)OptParms)->VerIDList.ModuleVers,MODULE_VERS);
         ((pmiID_t*)OptParms)->VerIDList.Next = 0;
         break;
/*--------------------------------------------------------------------------*/
/* NULL ops for checkpoint                                                  */
/*--------------------------------------------------------------------------*/
     case pmiPIDMOptGetPos:
     case pmiPIDMOptSetPos:
        break;
default:
/* Handle unknown request type                                              */
         retcode = pmrcUnsupported;
}  /* end switch on request type */
/* Insert the established return code into the command block                */
/* for return DataConnector                                                 */
    Opts->Retcode = retcode;
/* If there's a Access Module specific error, indicated by a return code    */
/* of pmrcFailure, insert the associated error text into                    */
/* the command block for return to the DataConnector                        */
    if ( retcode == pmrcFailure )
       {
        Opts->ErrMsg.Data =  &SG_ErrorText[0];
        Opts->ErrMsg.DataLength = SG_ErrorTextLen;
       }
    else
       {
        Opts->ErrMsg.Data =  0;
        Opts->ErrMsg.DataLength = 0;
       }
sprintf(MsgStr,"Returnning retcode=%d",retcode);
if ( retcode )
{ TRCELOG(pmTrceEvents,"%s",MsgStr); }
else
{ TRCELOG(pmTrceInfo,"%s",MsgStr); }
    return;
}