Search notes:

tq84-OCI: a simple C library for Oracle's Call Interface

Source code

tq84_oci.h

#ifdef __GNUC__
#  define _int64 long long
#endif

#ifdef __cplusplus
extern "C" {
#endif

#include <oci.h>

struct  oci_connection {
   /* The environment handle defines a context in which all OCI functions are
      invoked. Each environment handle contains a memory cache, which allows for
      fast memory access. All memory allocation under the environment handle is
      done from this cache. Access to the cache is serialized if multiple
      threads try to allocate memory under the same environment handle. When
      multiple threads share a single environment handle, they may block on
      access to the cache. The environment handle is passed as the parent
      parameter to the OCIHandleAlloc() call to allocate all other handle types.
      Bind and define handles are allocated implicitly.
   */
   OCIEnv*       env;

  /* The error handle is passed as a parameter to most OCI calls. The error
     handle maintains information about errors that occur during an OCI
     operation. If an error occurs in a call, the error handle can be passed to
     OCIErrorGet() to obtain additional information about the error that
     occurred. Allocating the error handle is one of the first steps in an OCI
     application because most OCI calls require an error handle as one of its
     parameters. */
   OCIError*     err;

   OCIServer*    srv;
   OCISvcCtx*    svc;
   OCISession*   ses;
};

struct oci_description {
  text  col_name[31];
  ub2   col_type;
};

void checkerr(OCIError* err, sword status, char errbuf[512]);

void parse_connect_string (
   char* connect_str,  /* in   */
   text  username[31], /* out  */
   text  password[31], /* out  */
   text  dbname  [31]  /* out  */
);

int oci_describe(
           OCIStmt*            sh,
/*         char*               errmsg,*/
    struct oci_connection*     conn,
    struct oci_description*    descr,
           int                 pos);

int oci_connect(
          text            username[30],
          text            password[30],
          text            dbname  [30],
   struct oci_connection* connection,
   char   errmsg  [512]
);


int oci_parse_and_execute(
         char*           stmt,
         char            errmsg[512],
  struct oci_connection* conn
);
int oci_execute0(
           OCIStmt*        sh, 
           char*           errmsg, 
    struct oci_connection* conn);

OCIStmt* oci_parse(
         char*           stmt,
         char            errmsg[512],
  struct oci_connection* conn );


int oci_execute(
           OCIStmt*        sh, 
           char*           errmsg, 
    struct oci_connection* conn,
           int nof_binds, 
    ...);

int oci_fetch(
           OCIStmt*        sh,
           char*           errmsg,
    struct oci_connection* conn);

int oci_define(
           OCIStmt*        sh, 
           char*           errmsg, 
    struct oci_connection* conn,
           int             nof_defines, 
    ...);

int oci_commit(struct oci_connection* conn, char* errmsg);

#ifdef __cplusplus
}
#endif
Github repository tq84-OCI, path: /tq84_oci.h

tq84_oci.c

#include <string.h>
#include <stdio.h>

#include "tq84_oci.h"

static int oci_env_created = 0;

int oci_connect(
            text            username[31],
            text            password[31],
            text            dbname  [31],
     struct oci_connection* conn,
            char errmsg[512]
     ) {

    sword r;

    if (!oci_env_created) {
      r=OCIEnvCreate( &conn->env, 
            OCI_DEFAULT |
            OCI_THREADED
          //OCI_OBJECT
          //OCI_EVENTS
          //OCI_NO_UCB 
          //OCI_ENV_NO_MUTEX
          //OCI_NEW_LENGTH_SEMANTICS 
          , 0, 0, 0, 0, 0, 0); 

      if (r != OCI_SUCCESS) {
        strcpy((char*) errmsg, "Couldn't create environment (OCIEnvCreate");
        goto clean_up;
      }
      oci_env_created = 1;
    }

    OCIHandleAlloc(conn->env, (dvoid**)&conn->err, OCI_HTYPE_ERROR,   0, 0);
    OCIHandleAlloc(conn->env, (dvoid**)&conn->srv, OCI_HTYPE_SERVER,  0, 0);
    OCIHandleAlloc(conn->env, (dvoid**)&conn->svc, OCI_HTYPE_SVCCTX,  0, 0);
    OCIHandleAlloc(conn->env, (dvoid**)&conn->ses, OCI_HTYPE_SESSION, 0, 0);

//    r = OCILogon(conn->env, conn->err, &conn->svc, 
//        username, strlen((const char*) username),
//        password, strlen((const char*) password),
//        dbname  , strlen((const char*) dbname  ));


    r=OCIServerAttach(conn->srv, conn->err, (text*) dbname, strlen((const char*)dbname), (ub4) OCI_DEFAULT);

    if (r != OCI_SUCCESS) {
       checkerr(conn->err, r, errmsg);
       goto clean_up;
    }

    OCIAttrSet(conn->svc, OCI_HTYPE_SVCCTX, conn->srv, 0, OCI_ATTR_SERVER,  conn->err);

    OCIAttrSet(conn->ses, OCI_HTYPE_SESSION, username, strlen((const char*)username), OCI_ATTR_USERNAME, conn->err); 
    OCIAttrSet(conn->ses, OCI_HTYPE_SESSION, password, strlen((const char*)password), OCI_ATTR_PASSWORD, conn->err); 

    if ( (r=OCIAttrSet((dvoid *) conn->svc, (ub4) OCI_HTYPE_SVCCTX, (dvoid *) conn->ses, (ub4) 0, (ub4) OCI_ATTR_SESSION, conn->err)) ) {
      checkerr(conn->err, r,errmsg);
      goto clean_up;
    }

    r=OCISessionBegin (conn->svc, conn->err, conn->ses, OCI_CRED_RDBMS, OCI_DEFAULT);
    if (r != OCI_SUCCESS) {
      checkerr(conn->err, r,errmsg);
      goto clean_up;
    }

    return 1;

clean_up:

//strcpy(errmsg,(const char*) errbuf);
    return 0;
}
    

void checkerr(OCIError* err, sword status, char errbuf[512]) {
    sb4 errcode;

    switch (status) {
    case OCI_SUCCESS:
      strcpy(errbuf, "No error");
      break;

    case OCI_SUCCESS_WITH_INFO:
      strcpy(errbuf, "OCI_SUCCESS_WITH_INFO");
      break;

    case OCI_NEED_DATA:
      strcpy(errbuf, "OCI_NEED_DATA");
      break;

    case OCI_NO_DATA:
      strcpy(errbuf, "OCI_NO_DATA");
      break;

    case OCI_ERROR:
      OCIErrorGet (err, (ub4) 1, (text*) NULL, &errcode, (text*) errbuf, (ub4) 512 , (ub4) OCI_HTYPE_ERROR);
      break;

    case OCI_INVALID_HANDLE:
      strcpy(errbuf, "OCI_INVALID_HANDLE");
      break;

    case OCI_STILL_EXECUTING:
      strcpy(errbuf, "OCI_STILL_EXECUTING");
      break;

    case OCI_CONTINUE:
      strcpy(errbuf, "OCI_CONTINUE");
      break;

    default:
      strcpy(errbuf, "Unknown error");
      break;
    }
}

void parse_connect_string(
     char* connect_str,  /* in   */
     text  username[31], /* out  */
     text  password[31], /* out  */
     text  dbname  [31]  /* out  */
) {

    username[0] = 0;
    password[0] = 0;
    dbname  [0] = 0;

    text* to=username;

    while (*connect_str) {
      if (*connect_str == '/') {
        *to=0;
        to=password;
        connect_str++;
        continue;
      }
      if (*connect_str == '@') {
        *to=0;
        to=dbname;
        connect_str++;
        continue;
      }
      *to=*connect_str;
      to++;
      connect_str++;
    }
    *to=0;
}

int oci_parse_and_execute(
           char*           stmt,
           char            errmsg[512],
    struct oci_connection* conn
) {
    OCIStmt       *sh;
    sword r;

    if ((r=OCIHandleAlloc((dvoid *) conn->env, (dvoid **) &sh, (ub4) OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0))) {
      checkerr(conn->err, r, errmsg);
      return 0;
    }

    if ((r=OCIStmtPrepare(sh, conn->err, (text*) stmt, (ub4) strlen(stmt), (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT))) {
      checkerr(conn->err, r, errmsg);
      OCIHandleFree((dvoid *) sh, (ub4) OCI_HTYPE_STMT);
      return 0;
    }
    if ((r=OCIStmtExecute(conn->svc, sh, conn->err, (ub4) 1, (ub4) 0, (CONST OCISnapshot *) 0, (OCISnapshot *) 0, (ub4) OCI_DEFAULT))) {
      checkerr(conn->err, r, errmsg);
      OCIHandleFree((dvoid *) sh, (ub4) OCI_HTYPE_STMT);
      return 0;
    }

    OCIHandleFree((dvoid *) sh, (ub4) OCI_HTYPE_STMT);
    return 1;
}

OCIStmt* oci_parse(
           char*           stmt,
           char            errmsg[512],
    struct oci_connection* conn ) {

    OCIStmt* sh;
    sword r;

    if ( (r=OCIHandleAlloc((dvoid*) conn->env, (dvoid **) &sh, (ub4) OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0)) ) {
      checkerr(conn->err, r, errmsg);
      return 0;
    }
    if ((r=OCIStmtPrepare(sh, conn->err, (text*)(void*)stmt, (ub4) strlen((char *) stmt), (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT))) {
      checkerr(conn->err, r, errmsg);
      OCIHandleFree((dvoid*) sh, (ub4) OCI_HTYPE_STMT);
      return 0;
    }

    return sh;
}


int oci_define(
             OCIStmt*        sh, 
             char*           errmsg, 
      struct oci_connection* conn,
             int             nof_defines, 
      ...) {

    OCIDefine *defnp = (OCIDefine *) 0;
    sword      r;
    va_list    defines;
    dvoid*     value_ptr;
    int        sz;
    int        pos;
    ub2        dt_type;

    va_start(defines, nof_defines);
    for (pos=0;pos<nof_defines; pos++) {

      dt_type   = va_arg(defines, int);

      switch (dt_type) {
        case SQLT_INT: 
//      printf("SQLT_INT\n");
          value_ptr=va_arg(defines, dvoid*);
          sz       = sizeof(int); 
          break;
        case SQLT_FLT:  
//      printf("SQLT_FLT\n");
          value_ptr = va_arg(defines, dvoid*);
          sz        = sizeof(double); 
          break;
        case SQLT_CHR:
        case SQLT_STR:
//      printf("SQLT_STR\n");
          value_ptr = va_arg(defines, dvoid*);
          sz        = va_arg(defines, int); // or should this be long?
          break;
        case SQLT_ODT:
//      printf("SQLT_ODT\n");
          value_ptr = va_arg(defines, dvoid*);
          sz        = sizeof(OCIDate);
          break;
        default:
//      "THIS MUST NOT HAPPEN";
          strcpy(errmsg, "adp_oci_error 0001, datatype not yet implemented");
          return 0;
      }

      if ( (r=OCIDefineByPos(
          sh, 
          &defnp, 
          conn->err, 
          pos+1, 
          value_ptr,
          sz,
          dt_type, 
         (dvoid *) 0,  // indp
         (ub2   *) 0,  // rlenp
         (ub2   *) 0,  // rcodep
         OCI_DEFAULT) )) {
           checkerr(conn->err, r, errmsg);
           return 0;
        }
    }
    return 1;
}


int oci_execute(
             OCIStmt*        sh, 
             char*           errmsg, 
      struct oci_connection* conn,
             int             nof_binds, 
      ...) {

    OCIBind       *bndhp = (OCIBind*) 0;
    sword r;
    int   sz;
    int   pos;

    va_list      binds;
    ub2          dt_type;
    dvoid       *value_ptr;
    int          i;
    double       d;

    va_start(binds, nof_binds);

    for (pos=0;pos<nof_binds;pos++) {

      dt_type   = va_arg(binds, int);

      switch (dt_type) {
        case SQLT_INT: 
          i        = va_arg(binds, int);
//      printf("SQLT_INT: %d\n", i);
          sz       = sizeof(int); 
          value_ptr= &i; 
          break;
        case SQLT_FLT:  
          d         = va_arg(binds, double);
//      printf("SQLT_FLT: %f\n", d);
          sz        = sizeof(double); 
          value_ptr = &d; 
          break;
        case SQLT_CHR:
          value_ptr = va_arg(binds, char*);
//      printf("SQLT_CHR: %s\n", (char*) value_ptr);
          sz        = strlen( (char*) value_ptr);
          break;
        case SQLT_ODT:
//      printf("SQLT_ODT\n");
          value_ptr = va_arg(binds, OCIDate*);
          sz        = sizeof(OCIDate);
          break;
      }

      if ((r=OCIBindByPos(sh, &bndhp, conn->err,
                        (ub4) pos+1,             // position
                        value_ptr,               // value pointer
                        sz,                      // size
                        dt_type,
                        (dvoid *) 0,             // indp
                        (ub2   *) 0,             // alenp
                        (ub2   *) 0,             // rcodep
                        (ub4    ) 0,             // maxarr_len
                        (ub4   *) 0,             // curelp
                        (ub4) OCI_DEFAULT))) {

         checkerr(conn->err, r, errmsg);
         return 0;
      }
    }

    if ((r=OCIStmtExecute(
          conn->svc, 
          sh, 
          conn->err, 
    //-------
          (ub4) 1,  // iters
    //    (ub4) 0,  // iters
    //-------
          (ub4) 0, (CONST OCISnapshot *) 0, (OCISnapshot *) 0, (ub4) OCI_DEFAULT))) {
      checkerr(conn->err, r, errmsg);
      OCIHandleFree((dvoid*) sh, (ub4) OCI_HTYPE_STMT);
      return 0;
    }
    return 1;
}

/*
     Todo: Getting the number of columns in the query :
    OCIAttrGet(stmhp, OCI_HTYPE_STMT, &numcols, 0, OCI_ATTR_PARAM_COUNT, errh);
*/

int oci_execute0(
             OCIStmt*        sh, 
             char*           errmsg, 
      struct oci_connection* conn) {
    sword r;
    if ((r=OCIStmtExecute(
          conn->svc, 
          sh, 
          conn->err, 
          (ub4) 0,  // iters
          (ub4) 0, (CONST OCISnapshot *) 0, (OCISnapshot *) 0, (ub4) OCI_DEFAULT))) {
      checkerr(conn->err, r, errmsg);
      OCIHandleFree((dvoid*) sh, (ub4) OCI_HTYPE_STMT);
      return 0;
    }
    return 1;
}

int oci_fetch(
             OCIStmt*        sh,
             char*           errmsg,
      struct oci_connection* conn) {

    sb4 r;

    r = OCIStmtFetch(
          sh, 
          conn->err, 
          (ub4) 1, 
          (ub4) OCI_FETCH_NEXT,
          (ub4) OCI_DEFAULT);

    if (r == OCI_SUCCESS) {
       return 1;
    }
    else if (r == OCI_SUCCESS_WITH_INFO) {
       return 1;
    }
    else {

       if (r != OCI_NO_DATA) {
          checkerr(conn->err, r, errmsg);
          return 0;
       }

       return 0;
    }
}

// Metalink note 125057.1
int oci_describe(
             OCIStmt*            sh,
         /*  char*               errmsg, */
      struct oci_connection*     conn,
      struct oci_description*    descr,
             int                 pos) {


    text*     colName;
    OCIParam* param = 0;
    ub4       len;

    sb4 status;

    status = OCIParamGet(sh, OCI_HTYPE_STMT, conn->err,  (void**)&param, (ub4) pos);

    if (status == OCI_SUCCESS) {
       len = sizeof(sb2);
       OCIAttrGet((dvoid*)param, (ub4) OCI_DTYPE_PARAM, (dvoid*) &(descr->col_type), &len, (ub4) OCI_ATTR_DATA_TYPE, conn->err);
       len = sizeof(sb4);
       OCIAttrGet((dvoid*)param, (ub4) OCI_DTYPE_PARAM, (dvoid**)&colName          , &len, (ub4) OCI_ATTR_NAME     , conn->err);
    // printf("len: %d\n",len);
    // descr->col_name[len]=0;
       memcpy(descr->col_name, colName, len);
       descr->col_name[len]=0;
       return 1;
    }
    else {
       return 0;
    }
}

int oci_commit(struct oci_connection* conn, char* errmsg) {

    sb4 r;

    if ((r=OCITransCommit(conn->svc, conn->err, 0))) {
       checkerr(conn->err, r, errmsg);
       return 0;
    }

    return 1;
}

Github repository tq84-OCI, path: /tq84_oci.c

Create a table

The following program creates a table.
#include <stdio.h>
#include <stdlib.h>

#include "tq84_oci.h"

int main(int argc, char* argv[]) {
         char err_msg   [512];

  struct oci_connection conn;

  if (argc < 2) {
    printf("usage %s username/password[@dbname]\n", argv[0]);
    exit (-1);
  }

  text  username[31];
  text  password[31];
  text  dbname  [31];

  parse_connect_string(argv[1],username, password, dbname);

  if (!oci_connect(username, password, dbname, &conn, err_msg)) {
    printf("Error with oci_connect: %s\n",err_msg);
    goto clean_up;
  }

  if (!oci_parse_and_execute("create table oci_test_table ( "
                             "  number_      number,        "
                             "  number_5_3   number(5,3),   "
                             "  varchar2_20  varchar2(20),  "
                       //    "  blob_        blob,          "
                       //    "  clob_        clob,          "
                             "  date_        date)          ",
                             err_msg, &conn) ) {
    printf(err_msg);
    goto clean_up;
  }

  printf("A table named oci_test_table should now be created\n");

clean_up:

  OCITerminate(OCI_DEFAULT);

  return 0;
}

Github repository tq84-OCI, path: /_test/01_create_table.c

Insert into table

This program inserts a couple of records into the the table.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "tq84_oci.h"

int main(int argc, char* argv[]) {
           char err_msg   [512];

    struct oci_connection conn;
           int            i;
           double         d;
           char*          c;
           OCIStmt*       sh;
           OCIDate        aug_28th_1970_22h23m44s;
           OCIDate        feb_01th_2003_04h05m06s;

    if (argc < 2) {
      printf("usage %s username/password[@dbname]\n", argv[0]);
      exit (-1);
    }

    text  username[30];
    text  password[30];
    text  dbname  [30];

    parse_connect_string(argv[1], username, password, dbname);

    if (!oci_connect(username, password, dbname, &conn, err_msg)) {
      printf(err_msg);
      goto clean_up;
    }

    if (! (sh=oci_parse("insert into oci_test_table (number_, number_5_3, varchar2_20, date_) values (:1, :2, :3, :4)", err_msg, &conn))) {
       printf("could not oci_parse: %s\n", err_msg);
       goto clean_up;
    }

    OCIDateSetTime(&aug_28th_1970_22h23m44s,   22, 23, 44);
    OCIDateSetDate(&aug_28th_1970_22h23m44s, 1970,  8, 28);

    if (!oci_execute(sh, err_msg, &conn, 4,
         SQLT_INT,  1  ,
         SQLT_FLT,  4.8,
         SQLT_CHR, "first",
         SQLT_ODT,  &aug_28th_1970_22h23m44s
         )) {

      printf("could not oci_execute (1): %s\n", err_msg);
      goto clean_up;

    }
    i = 10;
    d = 24.44;
    c = (char*) malloc(21);
    strcpy(c, "second");

    OCIDateSetTime(&feb_01th_2003_04h05m06s,    4,  5,  6);
    OCIDateSetDate(&feb_01th_2003_04h05m06s, 2003,  2,  1);

    if (!oci_execute(sh, err_msg, &conn, 4,

         SQLT_INT, i,
         SQLT_FLT, d,
         SQLT_CHR, c,
         SQLT_ODT, &feb_01th_2003_04h05m06s)) {
         printf("could not oci_execute (2): %s\n", err_msg);
         goto clean_up;

    }
    free(c);

    oci_parse_and_execute("commit",err_msg,&conn);

clean_up:

    OCITerminate(OCI_DEFAULT);

    return 0;
}

Github repository tq84-OCI, path: /_test/02_insert_table.c

Select from the table

This program selects a record from the table and prints its values to the console:
#include <stdio.h>
#include <stdlib.h>

#include "tq84_oci.h"

int main(int argc, char* argv[]) {

    char           err_msg   [512];

    struct oci_connection conn;
           OCIStmt*       sh;

    int         i_out;
    double      d_out;
    char*       c_out;
    OCIDate    dt_out;

    int        day, month, year, hour, minute, second;

    c_out = (char*) malloc(21);

    if (argc < 2) {
      printf("usage %s username/password[@dbname]\n", argv[0]);
      exit (-1);
    }

    text  username[31];
    text  password[31];
    text  dbname  [31];

    parse_connect_string(argv[1],username, password, dbname);

    if (! oci_connect(username, password, dbname,&conn, err_msg)) {
        printf(err_msg);
        goto clean_up;
    }

    if (! (sh=oci_parse("select number_, number_5_3,        varchar2_20, date_ from oci_test_table where "
                        "number_ > :1 or number_5_3 = :2 or varchar2_20 < :3", err_msg, &conn))) {
        printf(err_msg);
        goto clean_up;
    }
    if (! oci_define(sh, err_msg, &conn, 4, SQLT_INT, &i_out, SQLT_FLT, &d_out, SQLT_CHR, c_out, 20, SQLT_ODT, &dt_out)) {
        printf(err_msg);
        goto clean_up;
    }
    if (! oci_execute(sh, err_msg, &conn, 3, SQLT_INT,  5, SQLT_FLT, 4.8, SQLT_CHR, "zzz")) {
        printf(err_msg);
        goto clean_up;
    }

    while (oci_fetch(sh, err_msg,&conn)) {
       OCIDateGetDate(&dt_out, &year, &month , &day   );
       OCIDateGetTime(&dt_out, &hour, &minute, &second);
       printf ("  %d %f %s %02d.%02d.%04d %02d:%02d:%02d\n", i_out, d_out, c_out, day, month, year, hour, minute, second);
    }

clean_up:

    free (c_out);
    OCITerminate(OCI_DEFAULT);

    printf("\n");
    return 0;
}
Github repository tq84-OCI, path: /_test/03_select_table.c

Desribe a select * statement

This program describes a select * statement.
#include <stdio.h>
#include <stdlib.h>

#include "tq84_oci.h"

int main(int argc, char* argv[]) {
           char err_msg   [512];
        // sword          r;
    struct oci_connection conn;
           OCIStmt*       sh;
           int            pos;
    struct oci_description    descr;

 // int numCol;
    if (argc < 2) {
       printf("usage %s username/password[@dbname]\n", argv[0]);
       exit (-1);
    }

    text  username[30];
    text  password[30];
    text  dbname  [30];

    parse_connect_string(argv[1],username, password, dbname);

    if (! oci_connect(username, password, dbname, &conn, err_msg)) {
          printf("Error with oci_connect: %s\n",err_msg);
          goto clean_up;
    }

    if (! (sh=oci_parse("select * from oci_test_table", err_msg, &conn))) {
        printf(err_msg);
        goto clean_up;
    }

    if (! oci_execute0(sh, err_msg, &conn)) {
        printf("after x\n");
        printf(err_msg);
        goto clean_up;
    }

 // OCIAttrGet(sh, OCI_HTYPE_STMT, &numCol, 0, OCI_ATTR_PARAM_COUNT, conn.err);
 // printf("Nof: %d\n", numCol);

    pos = 1;
    while (oci_describe(sh, /*err_msg,*/ &conn, &descr, pos)) {
       printf("%-30s %d:\n", descr.col_name, descr.col_type) ;
       pos++;
    }

clean_up:

    OCITerminate(OCI_DEFAULT);

    return 0;
}
Github repository tq84-OCI, path: /_test/04_describe_table.c

Reading from a (dbms_pipe) Pipe

The following program reads messages from pipes (dbms_pipe) and prints them to the console:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "tq84_oci.h"

int main(int argc, char* argv[]) {

           char           err_msg   [512];
           sword          r;
    struct oci_connection conn;
           OCIStmt*       sh;

    if (argc < 3) {
      printf("usage %s username/password[@dbname] msg_name\n", argv[0]);
      exit (-1);
    }

    text  username[31];
    text  password[31];
    text  dbname  [31];

    int   s;
    char  item    [100];

    strcpy(item,
         "          "
         "          "
         "          "
         "          "
         "          "
         "          "
         "          "
         "          "
         "          ");

    char  stmt          [] =
     "  declare                                    "
     "    s    integer;                            "
     "    item varchar2(200);                      "
     "  begin                                      "
     "    item := '';                              "
     "    s := sys.dbms_pipe.receive_message(:1);  "
     "    if s = 0 then                            "
     "      dbms_pipe.unpack_message(item);        "
     "    end if;                                  "
     "    :2 := s;                                 "
     "    :3 := item;                              "
     "  end;                                       ";


    parse_connect_string(argv[1], username, password, dbname);

    if (!oci_connect(username, password, dbname, &conn, err_msg)) {
      printf(err_msg);
      goto clean_up;
    }

    if (! (sh=oci_parse(stmt, err_msg, &conn )))  {
      printf(err_msg);
      goto clean_up;
    }

    printf("Waiting for messages\n");
    for (;;) {
        if (! (r=oci_execute(sh, err_msg, &conn,
               3,                 //  3  Bind variables used:
                                  // ---------------------
               SQLT_CHR, argv[2], // :1  pipe_name
               SQLT_INT, &s,      // :2  return value of dbms_pipe.receive_message (s)
               SQLT_CHR, item)    // :3  the message received (item)
           )) {

           printf(err_msg);
           break;
        }

        if (s != 0) {
            printf("Abnormal pipe status: %d %s\n\r", s, item);
        }
        else {
            printf("%s\n", item);
        }
    }

clean_up:;
    return 0;
}
Github repository tq84-OCI, path: /_test/read_pipe.c
This SQL-script can be run in SQL*Plus to write messages into pipes.
--
-- Use this script to write the text 'hello world'
-- into a message named 'queue_name'.
-- Then use
--   .\read_pipe.exe user/pw queue_name
--
declare
   status number;
begin
             dbms_pipe.pack_message('hello world');
   status := dbms_pipe.send_message('queue_name');
end;
/
Github repository tq84-OCI, path: /_test/write_into_pipe.sql

Compiling the sources

Generally, a source file can be compiled on Linux with GCC like so:
gcc -I$ORACLE_HOME/rdbms/demo -I$ORACLE_HOME/rdbms/public src.c -o executable  -L$ORACLE_HOME/lib -lclntsh
On Windows with
gcc -I%ORACLE_HOME%/oci/include src.c  %ORACLE_HOME%/bin/oci.dll -o executable.exe

Makefile

I was ableo to compile the sources with the following makefile with GCC on Windows:
CFLAGS=-Wall -Wextra -I. -I.. -I$(ORACLE_HOME)/oci/include
CC=gcc

all: ../tq84_oci.o 01_create_table.exe 02_insert_table.exe 03_select_table.exe 04_describe_table.exe read_pipe.exe

%.exe: %.o ../tq84_oci.o
	gcc $(CFLAGS) -I.. $^ -o $@ $(ORACLE_HOME)/bin/oci.dll

../tq84_oci.o: ../tq84_oci.c
	gcc $(CFLAGS) $^ -c $@
Github repository tq84-OCI, path: /_test/Makefile

Index