C Function Definition - Advanced SQL Engine - Teradata Database

SQL External Routine Programming

Product
Advanced SQL Engine
Teradata Database
Release Number
17.05
17.00
Published
June 2020
Language
English (United States)
Last Update
2021-01-24
dita:mapPath
qwr1571437338192.ditamap
dita:ditavalPath
lze1555437562152.ditaval
dita:id
B035-1147
lifecycle
previous
Product Category
Teradata Vantage™
#define SQL_TEXT Latin_Text
#include <sqltypes_td.h>
#include <string.h>
#define BUFFER_SIZE 100000
#define PREFIX_SIZE 500
/* Aggregate intermediate record */
typedef struct
{
    FNC_LobLength_t length;
    int             initflag;
    LOB_REF         ref;
    BYTE            prefix[PREFIX_SIZE];
} intrec_t;
/***************************************************************
    load_rec()  Initialize the intrec structure for a specified
                object;
***************************************************************/
static void
load_rec (intrec_t* rec, LOB_LOCATOR loc)
{
    LOB_CONTEXT_ID id;
    FNC_LobLength_t actsize;
    rec->length = FNC_GetLobLength(loc);
    rec->initflag = 1;
    FNC_LobOpen(loc, &id, 0, PREFIX_SIZE);
    FNC_LobRead(id, rec->prefix, PREFIX_SIZE, &actsize);
    FNC_LobClose(id);
   /* if the object length is less than the size allotted for the
      prefix, pad the remaining bytes with zeros. */
    while (actsize < PREFIX_SIZE)
        rec->prefix[actsize++] = 0;
    FNC_LobLoc2Ref(loc, &rec->ref);
}
/***************************************************************
    findnz()    Scan the open stream and return 1 if a nonzero
                byte is found, else return 0.
***************************************************************/
static int
findnz(LOB_CONTEXT_ID id)
{
    FNC_LobLength_t i, actsize;
    BYTE buffer[BUFFER_SIZE];
    while (FNC_LobRead(id, buffer, BUFFER_SIZE, &actsize) == 0)
    {
        for (i = 0; i < actsize; ++i)
            if (buffer[i] != 0)
                return 1;
    }
    return 0;
}
/***************************************************************
    greater()    Compare 2 byte strings and return 1 if a > b,
                -1 if a < b, else return 0.
***************************************************************/
static int
greater(BYTE* a, BYTE* b, int length)
{
    for (; length > 0; ++a, ++b, --length)
    {
        if ( *a > *b)
            return 1;
        else if (*a < *b)
            return -1;
    }
    return 0;
}
/***************************************************************
    rest_greater()  Compare the rest of 2 open streams (a, b) and
                    return 1 if a > b, else return 0.
***************************************************************/
static int
rest_greater(LOB_CONTEXT_ID a, LOB_CONTEXT_ID b)
{
    FNC_LobLength_t i, actsizea, actsizeb;
    BYTE bufa[BUFFER_SIZE/2], bufb[BUFFER_SIZE/2];
    while (FNC_LobRead(a, bufa, sizeof(bufa), &actsizea) == 0)
    {
        if (FNC_LobRead(b, bufb, actsizea, &actsizeb) == 0)
        {
            int cmpres = greater(bufa, bufb, actsizeb);
            if (cmpres != 0)
                return cmpres;
            if (actsizea > actsizeb)
            {
                /* exhausted b before a */
                for (i = actsizeb; i < actsizea; ++i)
                    if (bufa[i] != 0)
                        return 1;
                return findnz(a);
            }
        }
        else
        {
            /* b exhausted; then a > b iff the rest of a contains
               any nonzero byte */
            return findnz(a);
        }
    }
    /* Reached the end of a without exhausting b; ergo a >= b */
    return 0;
}
/**********************************************************************
    greater_obj()   Compare 2 objects (a, b) using cached prefix
                    strings when possible, or by reading whole objects
                    when necessary. Return 1 if a > b, else return 0.
**********************************************************************/
static int
greater_obj(intrec_t* a, intrec_t* b)
{
    LOB_CONTEXT_ID streama, streamb;
    int cmpres = greater(a->prefix, b->prefix, PREFIX_SIZE);
    /* If the comparison was resolved in the prefix, then we
       are done */
    if (cmpres != 0)
        return cmpres;
    if (a->length < PREFIX_SIZE)
        return 0;  /* must be a <= b */
    /* We will have to read the rest of object a */
    FNC_LobOpen(FNC_LobRef2Loc(&a->ref), &streama,
                PREFIX_SIZE, 0);
    if (b->length < PREFIX_SIZE)
    {
        /* a > b iff substr(a, PREFIX_SIZE+1) has any
           nonzero byte */
        cmpres = findnz(streama);
    }
    else
    {
        /* We will have to read the rest of object b also */
        FNC_LobOpen(FNC_LobRef2Loc(&b->ref), &streamb,
                    PREFIX_SIZE, 0);
        /* Compare the rest of the 2 objects */
        cmpres = rest_greater(streama, streamb);
        FNC_LobClose(streamb);
    }
    FNC_LobClose(streama);
    return cmpres;
}
/***************************************************************
    append_lob()  Copy source to dest
***************************************************************/
static void
append_lob(LOB_RESULT_LOCATOR dest, LOB_LOCATOR source )
{
    BYTE buffer[BUFFER_SIZE];
    LOB_CONTEXT_ID id;
    FNC_LobLength_t actlen;
    int trunc_err = 0;
    FNC_LobOpen(source, &id, 0, 0);
    while( FNC_LobRead(id, buffer, BUFFER_SIZE, &actlen) == 0 &&
           !trunc_err)
        trunc_err = FNC_LobAppend(dest, buffer, actlen, &actlen);
    FNC_LobClose(id);
}
/***************************************************************
     Max_Blob()      Main function
***************************************************************/
void Max_Blob(FNC_Phase phase,
              FNC_Context_t*      fctx,
              LOB_LOCATOR*        x,
              LOB_RESULT_LOCATOR* result,
              int*                x_i,
              int*                result_i,
              char                sqlstate[6])
{
    intrec_t detail_rec;
    intrec_t* s1 = (intrec_t*) fctx->interim1;
    intrec_t* s2 = (intrec_t*) fctx->interim2;
    switch (phase)
    {
    case AGR_INIT:
      if ((s1 = (intrec_t*)FNC_DefMem(sizeof(intrec_t))) == NULL)
        {
            /* could not get storage */
            strcpy(sqlstate,"U0001");
            return;
        }
        s1->initflag = 0;
        /* Now fall through to detail phase logic */
 
    case AGR_DETAIL:
        if (*x_i == -1)
            return;
        if (s1->initflag)
        {
            load_rec(&detail_rec, *x);
            if (greater_obj(&detail_rec, s1) == 1)
                *s1 = detail_rec;
        }
        else
        {
            s1->initflag = 1;
            load_rec(s1, *x);
        }
        break;
    case AGR_COMBINE:
        if (greater_obj(s2, s1) == 1)
            *s1 = *s2;
        break;
    case AGR_FINAL:
        if (s1->initflag)
            append_lob(*result, FNC_LobRef2Loc(&s1->ref));
        else
            *result_i = -1;  /* set result to null */
        break;
    case AGR_NODATA:
        *result_i = -1;      /* set result to null */
        break;
    default:
        strcpy(sqlstate, "U0005");
    }
}