17.10 - C Function Definition - Advanced SQL Engine - Teradata Database

Teradata Vantage™ - SQL External Routine Programming

Product
Advanced SQL Engine
Teradata Database
Release Number
17.10
Release Date
July 2021
Content Type
Programming Reference
Publication ID
B035-1147-171K
Language
English (United States)
/*****  C source file name: sqlxspexample.c  *****/

#define SQL_TEXT Latin_Text
#include <sqltypes_td.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <coptypes.h>
#include <coperr.h>
#include <parcel.h>
#include <dbcarea.h>
#include <dbchqep.h>

typedef struct
{
    Word            StatementNo;
    Word            Info;
    Word            Code;
    Word            Length;
    char            Msg[1];         /* 1 to 255 bytes    */
 } PclErrorFailBody, *PclErrorFailBody_pt;

struct DBCAREA DBCArea;
char * pContext;
DBCAREA *pDBCArea;
DBCAREAX *pDbcAreaX;

/******************************************************************
     Initialize()  Initialize DBCAREA.
******************************************************************/
Int32 Initialize()
{
    Int32 Result;

    pDBCArea = &DBCArea;
    pDBCArea->total_len = sizeof(struct DBCAREA);

    DBCHINI(&Result, pContext, &DBCArea);

    pDBCArea->change_opts        = 'Y'  ;
    pDBCArea->req_buf_len        = 1024;
    pDBCArea->resp_buf_len       = 1024;
    pDBCArea->use_presence_bits  = 'N'  ;
    pDBCArea->keep_resp          = 'N'  ;
    pDBCArea->loc_mode           = 'Y'  ;
    pDBCArea->var_len_req        = 'N'  ;
    pDBCArea->save_resp_buf      = 'N'  ;
    pDBCArea->two_resp_bufs      = 'N'  ;
    pDBCArea->ret_time           = 'N'  ;
    pDBCArea->wait_for_resp      = 'Y'  ;
    pDBCArea->req_proc_opt       = 'E'  ;
    pDBCArea->maximum_parcel     = 'H';
    pDBCArea->resp_mode          = 'I';
    pDBCArea->dynamic_result_sets_allowed = 'Y';

    return Result;
}

/******************************************************************
     Logon()  Establish a default connection.
******************************************************************/
Int32 Logon(char *LogonStr)
{
    Int32                   Result;
    pDBCArea->func=DBFCON;
    if (LogonStr == NULL)
    {
       pDBCArea->create_default_connection = 'Y';
    }
    else
    {
        pDBCArea->logon_len = (Int32) strlen(LogonStr);
        pDBCArea->logon_ptr = LogonStr;
    }

    DBCHCL(&Result, pContext, pDBCArea);
    if (Result != EM_OK)
        return Result;

    /* Fetch the response  */
    pDBCArea->i_sess_id = pDBCArea->o_sess_id;
    pDBCArea->i_req_id  = pDBCArea->o_req_id;
    pDBCArea->func      = DBFFET;
    DBCHCL(&Result,pContext,pDBCArea);
    if (Result != EM_OK)
        return Result;

    if ( pDBCArea->fet_parcel_flavor != PclSUCCESS )
    {
        if (   pDBCArea->fet_parcel_flavor == PclFAILURE
            || pDBCArea->fet_parcel_flavor == PclERROR )
        {
            return pDBCArea->fet_parcel_flavor;
        }
    }

    /* End the logon request */
    pDBCArea->i_sess_id = pDBCArea->o_sess_id;
    pDBCArea->i_req_id  = pDBCArea->o_req_id;
    pDBCArea->func      = DBFERQ;
    DBCHCL(&Result, pContext, pDBCArea);
    return Result;
}

/******************************************************************
     Logoff()  Disconnect.
******************************************************************/
Int32 Logoff()
{
    Int32 Result;

    pDBCArea->func = DBFDSC;
    DBCHCL(&Result, pContext, pDBCArea);
    return Result;
}

/******************************************************************
     Execute() Execute the specified request.
******************************************************************/
Int32 Execute(char *ReqStr)
{
    Int32 Result;

    /* Issue the request */
    pDBCArea->func           = DBFIRQ;
    pDBCArea->change_opts    = 'Y';
    pDBCArea->req_ptr        = ReqStr;
    pDBCArea->req_len        = (Int32) strlen(pDBCArea->req_ptr);
    DBCHCL(&Result, pContext, pDBCArea);
    if (Result != EM_OK) return Result;

    /* Fetch the result parcels */
    pDBCArea->func = DBFFET;
    pDBCArea->change_opts    = 'Y';
    pDBCArea->i_req_id  = pDBCArea->o_req_id;

    while (Result == EM_OK)
       DBCHCL(&Result, pContext, pDBCArea);

    /* End the request */
    pDBCArea->func = DBFERQ;
    DBCHCL(&Result, pContext, pDBCArea);
    return Result;
}

/******************************************************************
     DoTheWork()  Create the tables, call the stored procedure.
******************************************************************/
void DoTheWork()
{
    Int32       Result;
    Int32       a;
    Int32       CallReqNo;
    Int32       Flavor;
    char        ReqStr[255];
    Int32*      pInt32;
    char*       pChar;

    /* Create a trace table */
    Result = Execute("DROP TABLE TraceTable;");
    if (Result != EM_OK) return;

    Result = Execute("CREATE TABLE TraceTable(SeqNo INT GENERATED BY 
DEFAULT AS IDENTITY, Flavor INT, Text VARCHAR(100));");
    if (Result != EM_OK) return;

    /* Create a table to insert and select rows */
    Result = Execute("DROP TABLE tab1;");
    if (Result != EM_OK) return;

    Result = Execute("CREATE TABLE tab1(a INT, b INT);");
    if (Result != EM_OK) return;

    /* Insert the rows */
    for (a=1;a<=10;a++)
    {
        pDBCArea->using_data_ptr        = (char *) &a;
        pDBCArea->using_data_len        = sizeof(a);
        Result = Execute("USING(a INT) INSERT tab1(:a, :a);");
        if (Result != EM_OK) return;
    }

    /* Call a procedure which will return a result set */
    pDBCArea->func           = DBFIRQ;
    pDBCArea->change_opts    = 'Y';
    pDBCArea->req_ptr        = "CALL p1('SEL * FROM tab1 ORDER BY 1');";
    pDBCArea->req_len        = (Int32) strlen(pDBCArea->req_ptr);
    DBCHCL(&Result, pContext, pDBCArea);
    if (Result != EM_OK) return;

    /* Remember the request number */
    CallReqNo = pDBCArea->o_req_id;

    /* Fetch the result parcels and insert into the trace table */
    while (Result == EM_OK)
    {
        /* Fetch a parcel from the CALL */
        pDBCArea->func = DBFFET;
        pDBCArea->change_opts    = 'Y';
        pDBCArea->i_req_id  = CallReqNo;

        DBCHCL(&Result, pContext, pDBCArea);
        if (Result != EM_OK) return;
        Flavor = pDBCArea->fet_parcel_flavor;

        /* Put this parcel into the trace table */
        pDBCArea->func           = DBFIRQ;
        pDBCArea->change_opts    = 'Y';
        pDBCArea->using_data_ptr = (char *) &Flavor;
        pDBCArea->using_data_len = sizeof(Flavor);

        if (pDBCArea->fet_parcel_flavor == PclSUCCESS)
        {
            pDBCArea->req_ptr = 
               "USING (a INT) INSERT tracetable(,:a,'Success')";
            pDBCArea->req_len = (Int32) strlen(pDBCArea->req_ptr);
        }
        else if (pDBCArea->fet_parcel_flavor == PclDATAINFO)
        {
            pDBCArea->req_ptr = 
               "USING (a INT) INSERT tracetable(,:a,'DataInfo')";
            pDBCArea->req_len = (Int32) strlen(pDBCArea->req_ptr);
        }
        else if (pDBCArea->fet_parcel_flavor == PclXDIX)
        {
            pDBCArea->req_ptr = 
               "USING (a INT) INSERT tracetable(,:a,'DataInfoX')";
            pDBCArea->req_len = (Int32) strlen(pDBCArea->req_ptr);
        }
        else if (pDBCArea->fet_parcel_flavor == PclRECORD)
        {
            /* Point to the integer in the record parcel, */
            /* skip past the indicator byte               */
            pChar = pDBCArea->fet_data_ptr;
            pChar++;
            pInt32 = (Int32 *) pChar;
            sprintf(ReqStr, 
               "USING (a INT) INSERT tracetable(,:a,'Record %d ')",
               *pInt32);
            pDBCArea->req_ptr = ReqStr;
            pDBCArea->req_len = (Int32) strlen(pDBCArea->req_ptr);
        }
        else if (pDBCArea->fet_parcel_flavor == PclENDSTATEMENT)
        {
            pDBCArea->req_ptr = 
               "USING (a INT) INSERT tracetable(,:a,'EndStatement')";
            pDBCArea->req_len = (Int32) strlen(pDBCArea->req_ptr);
        }
        else if (pDBCArea->fet_parcel_flavor == PclENDREQUEST)
        {
            pDBCArea->req_ptr = 
               "USING (a INT) INSERT tracetable(,:a,'EndRequest')";
            pDBCArea->req_len = (Int32) strlen(pDBCArea->req_ptr);
        }
        else if (pDBCArea->fet_parcel_flavor == PclRESULTSET)
        {
            pDBCArea->req_ptr = 
               "USING (a INT) INSERT tracetable(,:a,'ResultSet')";
            pDBCArea->req_len = (Int32) strlen(pDBCArea->req_ptr);
        }
        else if (pDBCArea->fet_parcel_flavor == PclFAILURE)
        {
            pChar = pDBCArea->fet_data_ptr;
            pChar += 4;
            pInt32 = (Int32 *) pChar;
            pChar += 4;
            for(a=0;a<strlen(pChar);a++)
               if(pChar[a]==0x27) pChar[a]=' ';
            sprintf(ReqStr,
               "USING (a INT) INSERT tracetable(,:a,'Failure %d %s')",
               (*pInt32)&0x0000ffff, pChar);
            pDBCArea->req_ptr = ReqStr;
            pDBCArea->req_len = (Int32) strlen(pDBCArea->req_ptr);
        }
        else
        {
            pDBCArea->req_ptr = 
               "USING (a INT) INSERT tracetable(,:a,'')";
            pDBCArea->req_len = (Int32) strlen(pDBCArea->req_ptr);
        }
        DBCHCL(&Result, pContext, pDBCArea);
        if (Result != EM_OK) return;

        /* Fetch the success etc from the insert into the trace table */
        pDBCArea->func = DBFFET;
        pDBCArea->change_opts = 'Y';
        pDBCArea->i_req_id = pDBCArea->o_req_id;
        while (Result == EM_OK)
            DBCHCL(&Result, pContext, pDBCArea);

        /* End the insert request */
        pDBCArea->func = DBFERQ;
        DBCHCL(&Result, pContext, pDBCArea);

        /* Go and fetch the next parcel from the CALL */
    }
}

/******************************************************************
     Entry point for the external stored procedure.
******************************************************************/
void sqlxspex(
           char      sqlstate[6],
           SQL_TEXT  extname[129],
           SQL_TEXT  specific_name[129],
           SQL_TEXT  error_message[257])
{
    Initialize();

    Logon(NULL);

    DoTheWork();

    Logoff();

}