#define SQL_TEXT Latin_Text #include <sqltypes_td.h> #include <stdio.h> #include <string.h> /* definition of the scratch pad */ #define FALSE 0 #define TRUE 1 #define MAX_OUT_PARAMS 4 typedef struct { int indicator; char dtype[5]; void *value; } column_info; typedef struct { int done; VARCHAR_LATIN *Tscan; column_info cols[MAX_OUT_PARAMS]; } gen_ctx; /*****************************************************************/ /* A simple function to scan the next break in the text based on */ /* the delimiter passed in. */ /*****************************************************************/ static VARCHAR_LATIN * next(VARCHAR_LATIN find,VARCHAR_LATIN *data) { while(*data!='\0') { if(*data==find) break; data++; } return data; } /******************************************************************/ /* Obtain all result column definitions for a table function with */ /* variable output columns. */ /******************************************************************/ static int CheckColDef(gen_ctx *info,FNC_ColumnDef_t *col_def, VARCHAR_LATIN *Text, void *col1,void *col2,void *col3,void *col4, int col1_i,int col2_i,int col3_i, int col4_i) { int j; int i; VARCHAR_LATIN *TScan=Text ; info->Tscan=TScan; // Prepare output datatype string format for sscanf for(j=0;j<col_def->num_columns;j++) { switch(col_def->column_types[j].datatype) { case DATE_DT: case INTEGER_DT: case BYTEINT_DT: case SMALLINT_DT: strcpy(info->cols[j].dtype,"%d"); break; case CHAR_DT: strcpy(info->cols[j].dtype,"%c"); break; case VARCHAR_DT: strcpy(info->cols[j].dtype,"%s"); break; default: return -1; } } info->cols[0].indicator=col1_i; info->cols[1].indicator=col2_i; info->cols[2].indicator=col3_i; info->cols[3].indicator=col4_i; info->cols[0].value=col1; info->cols[1].value=col2; info->cols[2].value=col3; info->cols[3].value=col4; /* find all output columns that specified in sel stmt */ for(i=0;i<col_def->num_columns;i++) { if(info->cols[i].indicator==0) { sscanf((char *)info->Tscan,info->cols[i].dtype, info->cols[i].value); info->Tscan=next(',',info->Tscan)+1; } } return 0; } /*******************************************************************/ /* This is a simple demo program to show how to utilize the result */ /* returned from FNC_TBlGetColDef(). */ /*******************************************************************/ void get_data (VARCHAR_LATIN *Text, /* input string */ void *col1, /* output parameters */ void *col2, void *col3, void *col4, int *Text_i, /* input parameter indicator */ int *col1_i, /* output indicators for row ...*/ int *col2_i, int *col3_i, int *col4_i, char sqlstate[6], SQL_TEXT fncname[129], SQL_TEXT sfncname[129], SQL_TEXT error_message[257] ) { int status; FNC_ColumnDef_t *The_Columns; FNC_Phase Phase; gen_ctx *LocalGenCtx; /* Definition of result parameters returned from FNC_TblGetColDef */ The_Columns = FNC_TblGetColDef(); /* this will keep the state of which rows have been sent */ /* make sure the function is called in the supported context */ switch (FNC_GetPhase(&Phase)) { /******************************************************/ /* Process the constant expression case. Only one AMP */ /* participates for this example. */ /******************************************************/ case TBL_MODE_CONST: /* Depending on the phase, decide what to do. */ switch(Phase) { case TBL_PRE_INIT: switch (FNC_TblFirstParticipant() ) { case 1: /* participant */ return; case 0: /* not participant */ /* Don't participate. */ if (FNC_TblOptOut()) { strcpy(sqlstate, "U0006"); /* Return error. */ strcpy((char *) error_message,"Opt-out failed."); return; } break; default: /* -1 or other error */ strcpy(sqlstate, "U0007"); strcpy((char *) error_message, "First Participant Logic did not work."); return; } case TBL_INIT: /* Allocate a general scratchpad to retain data */ /* between iterations. */ LocalGenCtx = FNC_TblAllocCtx(sizeof(gen_ctx)); LocalGenCtx->done = FALSE; break; case TBL_BUILD: /* Get the scratchpad. */ LocalGenCtx = FNC_TblGetCtx(); if (LocalGenCtx->done) { /* Have no more data; return no data sqlstate. */ strcpy(sqlstate, "02000"); strcpy((char *) error_message, "EOF"); return; } /* Check and prepare output column datatype */ status = CheckColDef (LocalGenCtx,The_Columns,Text, col1,col2,col3,col4, *col1_i,*col2_i,*col3_i,*col4_i); if (status == -1) { status = FNC_TblAbort(); /* If I was the first then let's report the error. */ strcpy(sqlstate, "U0009"); return; } LocalGenCtx->done = TRUE; break; case TBL_END: case TBL_ABORT: break; } break; /****************************************/ /* Process the varying expression case. */ /****************************************/ case TBL_MODE_VARY: switch(Phase) { case TBL_PRE_INIT: LocalGenCtx = FNC_TblAllocCtx(sizeof(gen_ctx)); if (LocalGenCtx == NULL) { strcpy (sqlstate, "U006"); strcpy ((char *) error_message, "Context Allocation failed."); return; } break; case TBL_INIT: LocalGenCtx = FNC_TblGetCtx(); LocalGenCtx->done = FALSE; break; case TBL_BUILD: LocalGenCtx = FNC_TblGetCtx(); if (LocalGenCtx->done) { /* Have no more data return no data sqlstate */ strcpy(sqlstate, "02000"); strcpy((char *) error_message, "EOF"); return; } status = CheckColDef (LocalGenCtx,The_Columns,Text, col1,col2,col3,col4, *col1_i,*col2_i,*col3_i,*col4_i); if (status == -1) { status = FNC_TblAbort(); /* if I was the first then let's report the error */ strcpy(sqlstate, "U0009"); return; } LocalGenCtx->done = TRUE; break; case TBL_END: case TBL_ABORT: break; } } }