Solved

How to store and retrieve error message in an array?

Posted on 2004-08-30
12
352 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
  • 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
 
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
What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

 
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

What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

Suggested Solutions

This article will show, step by step, how to integrate R code into a R Sweave document
Does the idea of dealing with bits scare or confuse you? Does it seem like a waste of time in an age where we all have terabytes of storage? If so, you're missing out on one of the core tools in every professional programmer's toolbox. Learn how to …
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…
In this seventh video of the Xpdf series, we discuss and demonstrate the PDFfonts utility, which lists all the fonts used in a PDF file. It does this via a command line interface, making it suitable for use in programs, scripts, batch files — any pl…

705 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

Need Help in Real-Time?

Connect with top rated Experts

20 Experts available now in Live!

Get 1:1 Help Now