Solved

How to store and retrieve error message in an array?

Posted on 2004-08-30
12
358 Views
Last Modified: 2013-11-13
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;
}
0
Comment
Question by:mohammadzahid
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 3
  • 2
  • +2
12 Comments
 
LVL 11

Author Comment

by:mohammadzahid
ID: 11937388
Please note that all OCI function call (ORACLE API) return sword (signed int) value.

 
0
 
LVL 3

Expert Comment

by:teratoma
ID: 11937981
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
 
LVL 3

Expert Comment

by:Santino_k
ID: 11939014
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
Get 15 Days FREE Full-Featured Trial

Benefit from a mission critical IT monitoring with Monitis Premium or get it FREE for your entry level monitoring needs.
-Over 200,000 users
-More than 300,000 websites monitored
-Used in 197 countries
-Recommended by 98% of users

 
LVL 45

Accepted Solution

by:
sunnycoder earned 500 total points
ID: 11939038
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
 
LVL 11

Author Comment

by:mohammadzahid
ID: 11939741
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
 
LVL 7

Expert Comment

by:jacobhoover
ID: 11947523
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
 
LVL 11

Author Comment

by:mohammadzahid
ID: 11947824
Hi jacobhoover,

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

mohammadzahid
0
 
LVL 3

Expert Comment

by:Santino_k
ID: 11960505
If its in C and you wanna use exceptions then try Structured Exception Handling in C
0
 
LVL 7

Expert Comment

by:jacobhoover
ID: 11966627
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
 
LVL 7

Expert Comment

by:jacobhoover
ID: 11966660
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
 
LVL 11

Author Comment

by:mohammadzahid
ID: 11968191
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
 
LVL 45

Expert Comment

by:sunnycoder
ID: 11970394
>- 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

Featured Post

Optimize your web performance

What's in the eBook?
- Full list of reasons for poor performance
- Ultimate measures to speed things up
- Primary web monitoring types
- KPIs you should be monitoring in order to increase your ROI

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Whether you've completed a degree in computer sciences or you're a self-taught programmer, writing your first lines of code in the real world is always a challenge. Here are some of the most common pitfalls for new programmers.
What do responsible coders do? They don't take detrimental shortcuts. They do take reasonable security precautions, create important automation, implement sufficient logging, fix things they break, and care about users.
In this fourth video of the Xpdf series, we discuss and demonstrate the PDFinfo utility, which retrieves the contents of a PDF's Info Dictionary, as well as some other information, including the page count. We show how to isolate the page count in a…
Six Sigma Control Plans

617 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question