Optim Data Privacy Providers  11.3.0
 All Data Structures Files Functions Variables Macros Groups Pages
Error Recording and Error Messages

ODPP provides formatted error messages for ODPP error codes. ODPP errors are recorded by the service providers and presented to the user by means of Provider_GetErrorCount(), Provider_GetError(), Provider_GetFormattedErrorMsg() and Provider_TermErrors() APIs. The error messages are stored in an XML file. This file is used by the framework to return the error messages. Applications do not need to use this XML file directly. For additional details about this feature, refer to the APIs, above.

Error codes returned from Provider_FrmwInit() may be reported using the Provider_GetFmtErrMsgEarly() function.

Errors not captured by Error Recording

The following errors will not be captured by the Error Capture:

Token IDs (file ODPPTokIdsH.h)

Token Ids are used to represent the various tokens captured during Error Recording. This gives an opportunity to the caller to get an understanding of why the error happened. Token IDs are numeric values declared using an enum DP_ETOKENID. Token IDs start with a value of 1 and are named as ODPP_TOKID_<token identifier>, <token identifier> is declared in ODPPTokIdsH.h.

For example:

Printing Formatted Errors Messages

int PrintErrors(int iSvcToken)
{
RETVAL retVal; // return code
int iErrAreaLen; // Length of error control block storage area
short sErrCnt = 0; // Error count
short i = 0; // Counter
DP_ERR_MSG ErrMsg; // Error message definition
DP_ECB *pEcb = NULL; // Pointer to DP_ECB structure
#ifndef USE_ODPP_MBCS_CHAR_CALLS
ODPP_WCHAR ErrMsgSrc[ODPP_MAX_ERR_MSG_SRC_LENGTH + 1]; // To hold source of formatted error message in wide character(Unicode) format
ODPP_WCHAR ErrMsgText[ODPP_MAX_ERR_MSG_TEXT_LENGTH + 1]; // To hold formatted error message text in wide character(Unicode) format
ODPP_WCHAR ErrMsgBody[ODPP_MAX_ERR_MSG_BODY_LENGTH + 1]; // To hold formatted error message body in wide character( Unicode) format
#else
char ErrMsgSrc[ODPP_MAX_ERR_MSG_SRC_LENGTH + 1]; // To hold source of formatted error message in mixed character(MBCS/SBCS) format
char ErrMsgText[ODPP_MAX_ERR_MSG_TEXT_LENGTH + 1]; // To hold formatted error message text in mixed character (MBCS/SBCS) format
char ErrMsgBody[ODPP_MAX_ERR_MSG_BODY_LENGTH + 1]; // To hold formatted error message body in mixed character (MBCS/SBCS) format
#endif
// Clear the DP_ERR_MSG structure memory
memset(&ErrMsg, 0, sizeof(DP_ERR_MSG));
// Initialize the DP_ERR_MSG structure
// Retrieve the number of errors that have occurred and the size of the ECB storage area
retVal = Provider_GetErrorCount(iSvcToken, &sErrCnt, &iErrAreaLen);
if(ODPPSUCCESS != retVal)
{
printf("Failed to get the Error Count, Err=%#x", retVal);
return retVal;
}
if(sErrCnt <= 0)
{
printf("\nNo Error Detected\n");
return ODPPSUCCESS;
}
printf("\nTotal Error Count = %d\n", sErrCnt);
// Now set the required fields of DP_ERR_MSG
// Language to use to return the error message. Currently not used and zero must be supplied.
ErrMsg.iLanguage = 0;
// Allocate the ODPP error control block
pEcb = (DP_ECB*)malloc(iErrAreaLen);
if(NULL == pEcb)
{
printf("Error Block Malloc failed\n");
goto OnErrorClean;
}
// Clear the error control block
memset(pEcb, 0, iErrAreaLen);
// Initialize the DP_ECB structure
// Allocate ODPP error message block
#ifndef USE_ODPP_MBCS_CHAR_CALLS
// For wide character (Unicode) format
// Set the subtype of DP_ERR_MSG to 'W' to retrieve formatted error message in wide character(Unicode) format
ErrMsg.cSubType = 'W';
// Allocate memory for error message block
ErrMsg.EM.pWC = (DPEM_WC_SS *) malloc(sizeof(DPEM_WC_SS));
if(NULL == ErrMsg.EM.pWC)
{
printf("\nMem Alloc failed for DPEM_WC_SS \n");
goto OnErrorClean;
}
// Clear the DPEM_WC_SS structure
memset(ErrMsg.EM.pWC, 0, sizeof(DPEM_WC_SS));
// pMsgSrc will hold the source of the error message in wide character (Unicode) format
ErrMsg.EM.pWC->pMsgSrc = &ErrMsgSrc[0];
// Set the size of the buffer ErrMsgSrc, in bytes
ErrMsg.EM.pWC->iMsgSrcBytes = sizeof(ErrMsgSrc);
// pMsg will hold the error message text in wide character (Unicode) format
ErrMsg.EM.pWC->pMsg = &ErrMsgText[0];
// Set the size of the buffer ErrMsgText, in bytes
ErrMsg.EM.pWC->iMsgBytes = sizeof(ErrMsgText);
// pMsgBody will hold the erroe message description in details in wide character (Unicode) format
ErrMsg.EM.pWC->pMsgBody = &ErrMsgBody[0];
// Set the size of the buffer ErrMsgBody, in bytes
ErrMsg.EM.pWC->iMsgBodyBytes = sizeof(ErrMsgBody);
#else
// For mixed character (MBCS/SBCS) format
// Set the subtype of DP_ERR_MSG to 'M' to retrieve formatted error message in mixed character(MBCS/SBCS) format
ErrMsg.cSubType = 'M';
// Allocate memory for error message block
ErrMsg.EM.pMC = (DPEM_MC_SS *) malloc(sizeof(DPEM_MC_SS));
if(NULL == ErrMsg.EM.pMC)
{
printf("\nMem Alloc failed for DPEM_MC_SS \n");
goto OnErrorClean;
}
// Clear the DPEM_MC_SS structure
memset(ErrMsg.EM.pMC, 0, sizeof(DPEM_MC_SS));
// pMsgSrc will hold the source of the error message in wide character (Unicode) format
ErrMsg.EM.pMC->pMsgSrc = &ErrMsgSrc[0];
// Set the size of the buffer ErrMsgSrc, in bytes
ErrMsg.EM.pMC->iMsgSrcBytes = sizeof(ErrMsgSrc);
// pMsg will hold the error message text in wide character (Unicode) format
ErrMsg.EM.pMC->pMsg = &ErrMsgText[0];
// Set the size of the buffer ErrMsgText, in bytes
ErrMsg.EM.pMC->iMsgBytes = sizeof(ErrMsgText);
// pMsgBody will hold the erroe message description in details in wide character (Unicode) format
ErrMsg.EM.pMC->pMsgBody = &ErrMsgBody[0];
// Set the size of the buffer ErrMsgBody, in bytes
ErrMsg.EM.pMC->iMsgBodyBytes = sizeof(ErrMsgBody);
// For system default codepage
ErrMsg.EM.pMC->iEMCodePage = -1;
// DBMS type
ErrMsg.EM.pMC->cEMDBMSType = RDB_NONE;
#endif
// Loop through number of error count and print the formatted error messages
for ( short i = 0; i < sErrCnt; i++ )
{
// call this function to get the oldest ECB
retVal = Provider_GetError(iSvcToken, pEcb);
printf("\nRow Number: %d\n",(int)pEcb->iRowNum);
printf("Error Code: %d\t",pEcb->iErrCode);
printf("Token Count: %d\t\n",pEcb->sNumTokens);
// Clear the error message source, text and body buffers
memset(ErrMsgSrc,'\0',sizeof(ErrMsgSrc));
memset(ErrMsgText,'\0',sizeof(ErrMsgText));
memset(ErrMsgBody,'\0',sizeof(ErrMsgBody));
// Assign the error code to DP_ERR_MSG member
ErrMsg.iErrNum = pEcb->iErrCode;
// Assign the error control block populated in call to Provider_GetError()
ErrMsg.pECB = pEcb;
// Retrieve the number of errors that have occurred and the size of the ECB storage area
retVal = Provider_GetFormattedErrorMsg(&ErrMsg);
if(retVal != ODPPSUCCESS)
{
printf("Error Code not found, Err = %#x\n",retVal);
continue;
}
#ifndef USE_ODPP_MBCS_CHAR_CALLS
printf("Error Message Source:%ws\n",ErrMsgSrc);
printf("Error Message Text: %ws \n",ErrMsgText);
printf("Error Message Body: \n%ws\n",ErrMsgBody);
#else
printf("Error Message Source:%s\n",ErrMsgSrc);
printf("Error Message Text: %s \n",ErrMsgText);
printf("Error Message Body: \n %s\n",ErrMsgBody);
#endif
}
// Release all ECB storage areas from errors not retrieved
retVal = Provider_TermErrors(iSvcToken);
if(retVal != ODPPSUCCESS)
{
printf("Provider_TermErrors failed, Err = %#x\n",retVal);
return retVal;
}

Free the memory allocated.

OnErrorClean:
if(NULL != pEcb)
free(pEcb);
#ifndef USE_ODPP_MBCS_CHAR_CALLS
if(NULL != ErrMsg.EM.pWC)
free(ErrMsg.EM.pWC);
#else
if(NULL != ErrMsg.EM.pMC)
free(ErrMsg.EM.pMC);
#endif
return retVal;

Reporting Error and Informational Messages

During row processing, if an error occurs, an error control block (ECB) structure is created and held in memory until the error is reported using the Error Reporting API. An ECB holds the error code, row number and related tokens, if any, for a single error. Informational errors such as ODPP_COL_INFO_SRC_NULL_DST_SETTONULL also result in an ECB structure getting created.

Some applications like Optim LUA / Optim Column Map Exits call Provider_Service() one row at a time while other applications may call Provider_Service() sending a batch of rows. When sending a batch of rows where the data set is large, say 1 million rows, it is recommended to divide the set into smaller batches of a thousand or a few thousand rows each (depending on the memory available to the process) and call Provider_Service() sending a batch of rows at a time. If 1 million rows are sent together and if all the source values are NULL the process might run out of memory since 1 million ECB structures are held in memory until the errors are reported or until the ODPP framework is terminated. Whereas if 1000 rows are sent at a time if all the source values are NULL, 1000 ECBs will be held in memory and can be reported when Provider_Service() returns ensuring the process does not run out of memory.

// Note: This example makes the assumption that the RowSet consists of a single row.
// Declare the variables
DP_ROWSET_DEF *pRowSet = NULL;
DP_FIELD_DATA_DEF *pData = NULL;
char bODPPInfoCode = FALSE;
RETVAL retVal = ODPPSUCCESS;
int i;
// Call the Provider_Service method
retVal = Provider_Service(iSvcToken, sMethod, NULL, pRowSet);
// Check for an informational error
if(pRowSet->pRowDefine->bHasError == FALSE)
{
pData = pRowSet->pRowDefine->pFldDataDefine;
// Loop through all the fields checking the iErrorCode member of each data field
for(i = 0; i < pRowSet->pRowDefine->sCount; i++)
{
if(pData->iErrorCode != 0)
{
bODPPInfoCode = TRUE;
}
pData = pData->pNext;
}
}
// Report the error or informational message
if(( ODPPSUCCESS != retVal ) ||
( pRowSet->pRowDefine->bHasError == TRUE ) ||
( bODPPInfoCode == TRUE ))
{
retVal = PrintErrors(iSvcToken);
}