Menu

passing OCI_Connection * to a function

2008-05-23
2012-09-26
  • Nobody/Anonymous

    Hi Vincent.

    I craeted a function called Connect2DB()
    its prototype is: extern int Connect2DB(OCI_Connection cn, OCI_Statement st, OCI_Error *err);
    I call this function using Connect2DB(cn,st,err)
    Inside the function cn gets a value, but when returning to the caller program cn equals NULL.

    when I Run the program

    -

    OCI_Error err = NULL;
    OCI_Connection
    cn = NULL;
    OCI_Statement *st = NULL;

    printf("Return Status is: %d\n",Connect2DB(cn,st,err));
    if (cn == NULL) printf("cn After returning from Connect2DB() is NULL\n");
    

    This is the function:

    extern int Connect2DB(OCI_Connection cn, OCI_Statement st, OCI_Error err)
    {
    OCI_Connection
    cn1;

    cn = OCI_ConnectionCreate("XE","system","manager",OCI_SESSION_DEFAULT);
    if (cn == NULL) printf("cn is NULL\n");
    else puts("cn inside Connect2DB() is not NULL");
    if (!cn) return(False);
    st = OCI_StatementCreate(cn);
    return(True);
    

    }

    I get

    -

    cn inside Connect2DB() is not NULL
    Return Status is: 1
    cn After returning from Connect2DB() is NULL

    cn is a pointer, so it should hold the address to a OCI_Connection struct after returning from Connect2DB()
    but is holds NULL instead.
    Any idea why?
    Thanks,

    Gillian

     
    • Nobody/Anonymous

      Hi,
      Sorry for misunderstanding,
      Now it looks like this.

      if (!OCI_Initialize(ErrorHandling,NULL,OCI_ENV_DEFAULT)) return(False);

       
    • Vincent Rogier

      Vincent Rogier - 2008-05-23

      Hi,

      In fact, it's normal that when your function returns, the value of cn is NULL.

      Because the C language only knows one way to pass parameters : by value.

      It means that it's a copy of the pointer 'cn' that is used inside the your function...

      Your orignal pointer is not modified !! Same for 'st' !

      What you should do is to pass the address of your pointers 'cn' and 'st'.

      Like :

      extern int Connect2DB(OCI_Connection cn, OCI_Statement st, OCI_Error *err);

      And call it as :

      Connect2DB(&cn,&st,&err);

      Why do you pass an OCI_Error pointer ?

      Vincent

       
    • Nobody/Anonymous

      Hi,

      Thanks it works.

      The reason I do that is because I want OCILIB to be transparent to the top level program/programers
      Take a look at this code, it works.

      Top level Program:
      / ------------------------------------------------------------------------ *
      * prototypes
      * ------------------------------------------------------------------------
      /

      extern int SelectFromTable(void st, void verr);
      extern int InitConnection(void
      verr);
      extern int Connect2DB(void
      cn, void st, void err);
      extern void err_handler(void
      err, short ExitFlg);
      extern void print_version(void vcn);
      extern void DisconnectDB(void
      cn);

      -

      int mtmain()
      {
      void verr, vcn, *vst;

      if (!InitConnection(&verr)) err_handler(verr,True);
      if (!Connect2DB(&vcn,&vst,&verr)) err_handler(verr,True);
      print_version(vcn);
      if (!SelectFromTable(vst,&verr)) err_handler(verr,False);
      DisconnectDB(vcn);
      CleanAll();
      return EXIT_SUCCESS;
      

      }

      InitConnection Dunction:

      extern int InitConnection(void *verr)
      {
      OCI_Error
      err = NULL;

      err = (OCI_Error ) verr;

      if (!OCI_Initialize(NULL,NULL,OCI_ENV_DEFAULT)) return(False);
      *verr = err;
      return(True);
      

      }

      Connect2DB function:

      extern int Connect2DB(void vcn, void vst, OCI_Error err)
      {
      OCI_Connection
      cn;
      OCI_Statement *st = NULL;

      cn = OCI_ConnectionCreate("XE","system","manager",OCI_SESSION_DEFAULT);
       if (cn == NULL) printf("cn is NULL\n");
      if (!(cn)) return(False);
      

      st = OCI_StatementCreate(cn);
      vcn = (OCI_Connection ) cn;
      vst = (OCI_Statement ) st;
      return(True);
      }

      SelectFromTable Function:

      extern int SelectFromTable(OCI_Statement st, OCI_Error err)
      {
      OCI_Resultset *rs = NULL;

      if (!OCI_ExecuteStmt(st, MT("SELECT name,age FROM persons"))) return(False);
      rs = OCI_GetResultset(st);
      while (OCI_FetchNext(rs))
      {
          print_frmt("Name: %s",OCI_GetString(rs, 1));
          print_frmt(" Age : %i", OCI_GetInt(rs,2));
          print_text("\n");
      

      }
      print_frmt("count : %i\n", OCI_GetRowCount(rs));
      return(True);
      }

      err_handler Function:

      extern void err_handler(OCI_Error *err, short ExitFlg)
      {
      print_text("\n");

      if (OCI_ErrorGetType(err) == OCI_ERR_API)
      {
          const mtext *sql = OCI_GetSql(OCI_ErrorGetStatement(err));
      
          if (sql != NULL)
          {
              print_text("> ERROR - SQL : "); print_mstr(sql);
              print_text("\n");
          }
      }
      
      print_text("> ERROR - MSG : ");
      print_mstr(OCI_ErrorGetString(err));
      print_text("\n");
      nb_err++;
      if (ExitFlg) exit(0);
      

      }

      DisconnectDB Function:

      extern void DisconnectDB(void vcn)
      {
      OCI_Connection
      cn = NULL;

      cn = (OCI_Connection *) vcn;
      printf("Disconnecting ...\n");
      OCI_ConnectionFree(cn);

      }
      As you can see, in the top level program, OCILIB is not declared, and the program is indifferent to OCI.

      Gillian

       
      • Vincent Rogier

        Vincent Rogier - 2008-05-23

        Hi Gillian,

        You're not using the void *err parameter in your functions..

        Anyway ,the only way to get an OCI_Error handle is inside the error handler callback that you cna supply to OCI_Initialize().

        And the OCI_Error handle passed to the callback is avaible only inside the callback. When the callback returns, the error handler is destroyed !

        The mechanisms you're using for error handling cannot work...

         
    • Nobody/Anonymous

      Hi
      Have another question,

      When I run the program from command line (cmd.exe) it works,
      but when I run it from application console (Pelles C interface), it failes right on the first function - InitConnection()
      Any ideas?

      Gillian

       
      • Vincent Rogier

        Vincent Rogier - 2008-05-23

        See my previous answer...

         
    • Nobody/Anonymous

      Sorry I copied the old version of err_handler()
      Now It looks like this:

      include <stdio.h>

      include <stdlib.h>

      include "DBHandle_literals.h"

      include "GlobalDef.h"

      / ------------------------------------------------------------------------ *
      * prototypes
      * ------------------------------------------------------------------------
      /
      extern int SelectFromTable(void st, void verr, char SQLCmd);
      extern int InitConnection(void verr);
      extern int Connect2DB(void vcn, void vst, void
      verr,char DBName, char UserName, char Password);
      extern void ErrorHandling(void
      verr, short ExitFlg);
      extern void print_version(void vcn);
      extern void DisconnectDB(void
      vcn);
      extern void CleanAll(void);

      static char DBName = "XE", UserName = "system", Password = "manager";
      static char
      SQLCmd = "SELECT name,age FROM persons";

      / ------------------------------------------------------------------------ *
      * main
      * ------------------------------------------------------------------------
      /

      int main()
      {
      void verr, vcn, *vst;

      if (!InitConnection(&amp;verr)) ErrorHandling(verr,True);
      if (!Connect2DB(&amp;vcn,&amp;vst,&amp;verr,DBName,UserName,Password)) ErrorHandling(verr,True);
      print_version(vcn);
      if (!SelectFromTable(vst,&amp;verr,SQLCmd)) ErrorHandling(verr,False);
      DisconnectDB(vcn);
      CleanAll();
      
      printf(&quot;\npress any key to exit...&quot;);
      getchar();
      
      return True;
      

      }

      extern void ErrorHandling(void verr, short ExitFlg)
      {
      OCI_Error
      err = NULL;

      err = (OCI_Error *) verr;
      
      if (OCI_ErrorGetType(err) == OCI_ERR_API)
      {
          const mtext *sql = OCI_GetSql(OCI_ErrorGetStatement(err));
      
          if (sql != NULL)
          {
              print_text(&quot;&gt; ERROR - SQL : &quot;); print_mstr(sql);
              print_text(&quot;\n&quot;);
          }
      }
      
      print_text(&quot;&gt; ERROR - MSG : &quot;);
      print_mstr(OCI_ErrorGetString(err));
      print_text(&quot;\n&quot;);
      nb_err++;
      if (ExitFlg) exit(0);
      

      }

      What about the last question I asked?

       
      • Vincent Rogier

        Vincent Rogier - 2008-05-23

        As i said, an OCI_Error handle "lives" the time of the callback.

        If you get back the handle ouside the callback, it will point to already freed memory and leads to a segfault.

        For your last question, is the ocilib dll accessible to your program ? Check the path, the location where you put the dll, ...

        Your actual error handing will fail at the first error raised by ocilib.
        Start by change it first...

         
    • Nobody/Anonymous

      Hi Vincent, Is this a better error handling?
      The error handling is within the function.

      -

      Call to InitConnection()

      -

      InitConnection Function:

      extern void ErrorHandling(OCI_Error *err, short ExitFlg);

      extern int InitConnection()
      {
      OCI_Error *err = NULL;

      if (!OCI_Initialize(NULL,NULL,OCI_ENV_DEFAULT))
         {
           ErrorHandling(err,True);
       return(False);
      };
      return(True);
      

      }

      ErrorHandling Function:

      extern void ErrorHandling(OCI_Error err, short ExitFlg)
      {
      if (OCI_ErrorGetType(err) == OCI_ERR_API)
      {
      const mtext
      sql = OCI_GetSql(OCI_ErrorGetStatement(err));

          if (sql != NULL)
          {
              print_text(&quot;&gt; ERROR - SQL : &quot;); print_mstr(sql);
              print_text(&quot;\n&quot;);
          }
      }
      
      print_text(&quot;&gt; ERROR - MSG : &quot;);
      print_mstr(OCI_ErrorGetString(err));
      print_text(&quot;\n&quot;);
      if (ExitFlg) exit(0);
      

      }

       
      • Vincent Rogier

        Vincent Rogier - 2008-05-23

        Once again, you haven't supplied an error handler to OCI_Initiliaze(). If you do not, you'll never retreive an error handle !!!!

        Take two minutes to look at your own code : in InitConnection(), you're calling ErrorHandling() with a NULL OCi_Error handle...

        What you should do :

        1 - Supply to OCI_Initialize() an error handle (the prototype is in the documentation)
        2 - When an error occurs, you can retreive the error attributes, locally in the handler
        3 - Ouput the error attributes from inside the handler
        4 - if you really want to raise those attributes outside the handler, wnat you can do is
        A - create your own error structure
        B - declare a static error structure variable
        C - copy the OCI_Error handle attributes to your own structure
        D - is a OCILIB function returns FALSE, you can use your static variable to access the error attributes

        Vincent.