#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"); } }