How to store and retrieve error message in an array?

Hello Experts,

I am working on a program that is not working properly and looking for some ideas:

My program does the following:
- Make a call from main to runsql( ) passing enum constants as parameters.
- Makes func( ) calls using Oracle API to setup environment and login to the database.

I am trying to accomplish the following and need suggestions / ideas:
- Add a routine to handle error messages if occurred during the OCI API calls to the database.
- Store the OCI error message is a char array from OCI function call.
- Link the error text that occur in runSql( ) to main.
- Print the  contents of char array in main( ) to either stdout or to a file.

Thanks!!

Here is the code:

/******************************************************************************************
This program uses calls to the database using OCI API and performs the following tasks:
  * Logs into the database.
  * Executes a sql statement.
  * Performs OCI API cleanup.
*******************************************************************************************/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<oci.h>

#define SUCCESS 0
#define ERROR 1
#define SQL1 "select username,user_id from dba_users"

/* Constants defined */
typedef enum oci {RUNSQL1=1,CLEANOCI,OCIERROR} ociprogram;

/* Function prototypes */
int runSql(ociprogram, char *);

int main()
{
      runSql(RUNSQL1, SQL1);      /* Run SQL1 */

      return 0;
}
/**************************************************************************************
/* DO strcmp on strcmp(SQL1,sqlst) if zero then proceed .. else .. goto next block
***************************************************************************************/
int runSql(ociprogram value, char *sqlstatement)
{

      /* OCI Handles */
       static OCIEnv     *p_env;
       static OCISvcCtx  *p_svc;
       static OCIError   *p_err;
       static OCIStmt    *stmt1;      /* Sql handle for statement #1 */
       static OCIDefine  *p_dfn = (OCIDefine *) 0;
       static OCIDefine  *ptr_dfn = (OCIDefine *) 0;

        /* Local variables to runSql() */
       char *username = (text *) "zahmo01";
       char *password = (text *) "zahmo01";
       char *dbstring = (text *) "oracle92.cai.com";

        /*Local variables that hold the return from the sql statements from OCI Functions */
        static int initial_oci=0;                   /* Variable to control execution of OCI Initialization Env */
        static char ocistatus[512];            /* OCI message - placeholder */
        

if(initial_oci == 0)
  {

/********************************************************************************
The section below makes calls to OCI functions and perform OCI environment setup
before sql statements are executed.
*********************************************************************************/

/* Initialize OCI */
if((ocistatus = OCIInitialize((ub4) OCI_DEFAULT, (dvoid *)0,(dvoid * (*)(dvoid *, size_t)) 0,(dvoid * (*)(dvoid *, dvoid *, size_t))0,(void (*)(dvoid *, dvoid *)) 0 )) != SUCCESS)
      {
               return(ERROR);
      }

/* Initialize evironment */
if((ocistatus = OCIEnvInit( (OCIEnv **) &p_env, OCI_DEFAULT, (size_t) 0, (dvoid **) 0 )) != SUCCESS)
    {
               return(ERROR);
      }
/* Initialize handles */
if((ocistatus = OCIHandleAlloc( (dvoid *) p_env, (dvoid **) &p_err, OCI_HTYPE_ERROR,(size_t) 0, (dvoid **) 0)) != SUCCESS)
    {
                return(ERROR);
   }

if((ocistatus = OCIHandleAlloc( (dvoid *) p_env, (dvoid **) &p_svc, OCI_HTYPE_SVCCTX,(size_t) 0, (dvoid **) 0)) != SUCCESS)
      {
               return(ERROR);
      }

/* Connect to database server */
if((ocistatus = OCILogon(p_env, p_err, &p_svc, username,strlen(username),password, strlen(password), dbstring, strlen(dbstring))) != SUCCESS)
    {
                return(ERROR);
   }

if(ocistatus == SUCCESS)
        printf("OCI Env. initialized!\nConnected to the database as zahmo01/zahmo01@oracle92.cai.com\n");

    initial_oci = 1;   /* Increasing the value of static variable */

       return 0;
}
LVL 11
mohammadzahidAsked:
Who is Participating?
 
sunnycoderCommented:
which platform? If Linux or a nix, #include <errno.h> and use perror()

I am trying to accomplish the following and need suggestions / ideas:
>- Add a routine to handle error messages if occurred during the OCI API calls to the database.
>- Store the OCI error message is a char array from OCI function call.
>- Link the error text that occur in runSql( ) to main.
>- Print the  contents of char array in main( ) to either stdout or to a file.

Declare a function like perror which accepts a char * as argument.

In a header file declare a global variable, error_number. Also define various error types and messages in that header file. Something like

enum err_code {
           INVALID_HANDLE,
           INVALID_PARAMETER,
           ...
};

enum err_code error_number;
         
struct error_struct {
       enum err_code code;
       char * message;
};


struct error_struct err_message [128] =  {  {  INVALID_HANDLE, "Invalid file or record handle" },
                                                                 ....
                                                             };

void error_handler (char * p )
{
            /* Get currently set error_numer *
             * Get corresponding error message from err_message *
             * display strcat ( p, corresponding_error_message */
}

Any function that encounters an error only needs to update the global variable error_number and return an marker negative value (say -1) to tell the calling function that there has been an error. The calling function can then do the error handling or just print the error message using error_handler and then exit.

Note that you do not have to search through the entire array to find corresponding error message. If you store the error messages in the array in the same order as the enums, then corresponding message will be
err_message[error_numer].message
0
 
mohammadzahidAuthor Commented:
Please note that all OCI function call (ORACLE API) return sword (signed int) value.

 
0
 
teratomaCommented:
It seems ocistatus is already a static array.  Assuming this is where you want to put the error message, you only need to return a pointer to this array to the caller.  Since you're not using the int return type of runSql, why not return the pointer instead?  Of course, you can't assign things to an array with '=' so you'll have to use strcpy or something instead, at whatever point you have a textual error message.  Alternatively, you can return a more precise error code and have main() figure out what text should go with it.
0
Ultimate Tool Kit for Technology Solution Provider

Broken down into practical pointers and step-by-step instructions, the IT Service Excellence Tool Kit delivers expert advice for technology solution providers. Get your free copy now.

 
Santino_kCommented:
If all OCI calls return you is SWORD then why not just declare a variable
SWORD ociStatus;
instead of character Array because from your code i don't find any place where you are using an indexed array location to store your return type.

You can't directly use '=' to assign value to a character array.

I would say -
Convert
int runSql(ociprogram value, char *sqlstatement)
to
SWORD runSql(ociprogram value, char *sqlstatement)

use a variable SWORD ociStatus; in your function runSQL

for every OCI call use following method of returning instead of return ERROR;
if( ociStatus= OCIInitialize(...) )
{
  return ociStatus;
}

in Main
main()
{
 SWORD returnCode;
 returnCode =   runSql(RUNSQL1, SQL1);      
 
 ErrorHandler(returnCode);

return 0;
 }

ErrorHandler(SWORD errCode)
{
 // your error handing code goes here
 switch(errCode)
 {
   case :
   case :
   etc
 }
}

Hope this helps
0
 
mohammadzahidAuthor Commented:
Sunnycoder... I am unfortunately using Windows XP professional && Visual Studio .NET 2003 with all the bells and whistles from Microsoft applied :-).

Thanks sunnycoder and the other experts for the response. I will be trying your suggestions tomorrow as it is past 1:00AM in Vancouver, Canada and my notebook is begging me for some rest.

I will talk to you guys tomorrow.

Thanks again!

0
 
jacobhooverCommented:
There are plenty of suggestions all ready but why not use exceptions... as in.
  throw ocistatus;
instead of
  return(ERROR);

Then in main use:
try
{
  runSql(RUNSQL1, SQL1);
}
catch (SWORD ocistatus)
{
  /* DECODE THE ERROR NUMBER HERE FOR THE GIVEN OCI ERROR */
}
0
 
mohammadzahidAuthor Commented:
Hi jacobhoover,

I would love to use exceptions but I am writing this program in C.

mohammadzahid
0
 
Santino_kCommented:
If its in C and you wanna use exceptions then try Structured Exception Handling in C
0
 
jacobhooverCommented:
Well,
  then why not just return ocistatus on an error.  There is always a numeric value other than zero for the ocistatus if an error occurs.  You can then use this in the calling function to evaluate and display an error message.

Also, don't forget to do proper cleanup such as:
if((ocistatus = OCIHandleAlloc( (dvoid *) p_env, (dvoid **) &p_svc, OCI_HTYPE_SVCCTX,(size_t) 0, (dvoid **) 0)) != SUCCESS)
     {
/* NEED TO USE OCIHandleFree HERE ON PREVIOUS HANDLE*/
             return(ERROR);
     }

I am unsure if there are Destructor/Deallocation routines for the other calls, but I would assume they do exist.

Jake
0
 
jacobhooverCommented:
You may also want to look at examples like:

http://www.lc.leidenuniv.nl/awcourse/oracle/appdev.920/a96584/oci16m97.htm

<EXAMPLE INCLUDED INCASE LINK GETS BROKEN>

static void checkerr(errhp, status)
OCIError *errhp;
sword status;
{ text errbuf[512];
  ub4 buflen;
  ub4 errcode;
switch (status)
{ case OCI_SUCCESS:
    break;
  case OCI_SUCCESS_WITH_INFO:
    printf("ErrorOCI_SUCCESS_WITH_INFO\n");
    break;
  case OCI_NEED_DATA:
    printf("ErrorOCI_NEED_DATA\n");
    break;
  case OCI_NO_DATA:
    printf("ErrorOCI_NO_DATA\n");
    break;
  case OCI_ERROR:
    OCIErrorGet ((dvoid *) errhp, (ub4) 1, (text *) NULL, &errcode,
            errbuf, (ub4) sizeof(errbuf), (ub4) OCI_HTYPE_ERROR);
    printf("Error%s\n", errbuf);
    break;
  case OCI_INVALID_HANDLE:
    printf("ErrorOCI_INVALID_HANDLE\n");
    break;
  case OCI_STILL_EXECUTING:
    printf("ErrorOCI_STILL_EXECUTE\n");
    break;
  case OCI_CONTINUE:
    printf("ErrorOCI_CONTINUE\n");
    break;
  default:
    break;
  }
}

I guess the ultimate question is what do you intend upon doing with the error?  Will you be displaying it to the end user?  Will you attempt to continue on with the next statment?

Jake.. Again..
0
 
mohammadzahidAuthor Commented:
Thanks Jacobhoover.  

I have checkerr( ) in my code that I want to replace by following if OCI error occur.

- Give control to user if error occur from OCI
- Direct the error number back to main( )
- Print the error message with description either to a file or to the stdout.  
- Prompt to if continue or exit the program from main ( ).  If yes, then make call to runsql( ).









0
 
sunnycoderCommented:
>- Give control to user if error occur from OCI
The control can be returned in a limited way, say a menu of options like abort, run a command, continue, recover etc

>- Direct the error number back to main( )
Are OCI and your C program different processes? If yes then you need some IPC otherwise you can pass values by storing them in global variables or calling functions with parameters

>- Print the error message with description either to a file or to the stdout.  
this is a simple fputs() statement

>- Prompt to if continue or exit the program from main ( ).  If yes, then make call to runsql( ).
I guess this and 1 are inter-related ... A simple sequence of printfs, scanf and if else is all that will be required here
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.