[rtg] Oracle driver

Leech, Jonathan jleech at virtela.net
Tue Jun 6 18:35:53 EDT 2006


Here is the working code for an Oracle database, using OCI.  It creates a connection pool with the same number of connections as RTG threads, but can be easily modified to use fewer connections.

librtgoci.c
----------------------
/*
 * RTG Oracle OCI database driver
 */

#include "rtg.h"
#include <oci.h>
#include <sys/param.h>

// thread-specific global variable
pthread_key_t key;

// only call the thread-specific variable setup once 
pthread_once_t once = PTHREAD_ONCE_INIT;

// holds the config info for all the threads
config_t *set;

// Oracle handles
static OCIError   *errhp;
static OCIEnv     *envhp;
static OCICPool   *poolhp;

// stores the Oracle connection pool name and length
static OraText *poolName;
static sb4 poolNameLen;

/* Max,Min, and increment connections */
static ub4 conMin = 1;
static ub4 conIncr = 1;

// log any Oracle errors
void checkerr(errhp, status)
OCIError *errhp;
sword status;
{
    text errbuf[512];
    sb4 errcode = 0;
 
    switch (status)
    {
    case OCI_SUCCESS:
      break;
    case OCI_SUCCESS_WITH_INFO:
      debug(LOW, "Error - OCI_SUCCESS_WITH_INFO\n");
      break;
    case OCI_NEED_DATA:
      debug(LOW, "Error - OCI_NEED_DATA\n");
      break;
    case OCI_NO_DATA:
      debug(LOW, "Error - OCI_NODATA\n");
      break;
    case OCI_ERROR:
      (void) OCIErrorGet((dvoid *)errhp, (ub4) 1, (text *) NULL, &errcode,
                          errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR);
      debug(LOW, "Error - %.*s\n", 512, errbuf);
      break;
    case OCI_INVALID_HANDLE:
      debug(LOW, "Error - OCI_INVALID_HANDLE\n");
      break;
    case OCI_STILL_EXECUTING:
      debug(LOW, "Error - OCI_STILL_EXECUTE\n");
      break;
    case OCI_CONTINUE:
      debug(LOW, "Error - OCI_CONTINUE\n");
      break;
    default:
      break;
    }
}

/* variable cleanup function */
void killkey(void *target) {
   free(target);
   
   // destroy the connection pool
   checkerr(errhp, (sword)OCIConnectionPoolDestroy(poolhp, errhp, OCI_DEFAULT));
   checkerr(errhp, OCIHandleFree((dvoid *)poolhp, OCI_HTYPE_CPOOL));
   checkerr(errhp, OCIHandleFree((dvoid *)errhp, OCI_HTYPE_ERROR));
}

/* called when library loads */
void __attribute__ ((constructor)) dl_init(void) {
}

/* this gets called once */
void my_makekey() {
   /* this shouldn't fail, and we're too early on to report errors */
   pthread_key_create(&key, killkey);

   // create the connection pool
   OCIEnvCreate (&envhp, OCI_THREADED, (dvoid *)0, NULL, NULL, NULL, 0, (dvoid *)0);

   (void)OCIHandleAlloc((dvoid *)envhp, (dvoid**)&errhp, OCI_HTYPE_ERROR, (size_t)0, (dvoid **) 0);

   (void)OCIHandleAlloc((dvoid *) envhp, (dvoid **) &poolhp, OCI_HTYPE_CPOOL, (size_t) 0, (dvoid **) 0);

   checkerr(errhp, OCIConnectionPoolCreate(envhp,
      errhp, poolhp, &poolName, &poolNameLen,
      set->dbdb, (sb4)strlen((const signed char *)set->dbdb),
      conMin, set->threads, conIncr,
      set->dbuser, (sb4)strlen((const signed char *)set->dbuser),
      set->dbpass, (sb4)strlen((const signed char *)set->dbpass),
      OCI_DEFAULT)
   );
   OCIThreadProcessInit();
   checkerr(errhp, OCIThreadInit(envhp, errhp));
}

int __db_test() {
   return TRUE;
}

/*
 * check the status of the connection
 * we don't try and reconnect because this is sometimes used to confirm a disconnect
 */
int __db_status() {
   sword lstat = OCI_SUCCESS;
   char buf[100];

   OCISvcCtx *svchp = pthread_getspecific(key);
   checkerr(errhp, lstat = OCIServerVersion(svchp, errhp, buf, 100, OCI_HTYPE_SVCCTX));
   if (lstat == OCI_SUCCESS) {
      return TRUE;
   } else {
      return FALSE;
   }
}

int __db_connect(config_t *config) {
   // initialize the key and connection pool once
   set = config;
   pthread_once(&once, my_makekey);

   // connect to Oracle
   OCISvcCtx *svchp = (OCISvcCtx *)0;
   checkerr(errhp, OCILogon2(envhp, errhp, &svchp,
      (CONST OraText *)config->dbuser, (ub4)strlen((const signed char *)config->dbuser),
      (CONST OraText *)config->dbpass, (ub4)strlen((const signed char *)config->dbpass),
      (CONST OraText *)poolName, (ub4)poolNameLen, OCI_CPOOL)
   );

   // store the Oracle session in thread-specific storage
   pthread_setspecific(key, svchp);

   return __db_status();
}

int __db_disconnect() {
   OCISvcCtx *svchp = pthread_getspecific(key);
   checkerr(errhp, OCILogoff((dvoid *) svchp, errhp));
   return TRUE;
}

int __db_insert(char *table, int iid, unsigned long long insert_val, double insert_rate) {
   char *query;
   OCISvcCtx *svchp = pthread_getspecific(key);
   OCIStmt *stmthp = (OCIStmt *)0;
   sword lstat;

   asprintf(&query, "INSERT INTO %s (id,dtime,counter) VALUES (%i,sysdate,%llu)", table, iid, insert_val);

   debug(HIGH, "Query = \"%s\"\n", query);

   OCIHandleAlloc(envhp, (dvoid **)&stmthp, OCI_HTYPE_STMT, (size_t)0, (dvoid **)0);

   checkerr(errhp, lstat = OCIStmtPrepare (stmthp, errhp, (CONST OraText *)query, (ub4)strlen((const signed char *)query), OCI_NTV_SYNTAX, OCI_DEFAULT));

   checkerr(errhp, lstat = OCIStmtExecute (svchp, stmthp, errhp, (ub4)1, (ub4)0, (OCISnapshot *)0, (OCISnapshot *)0, OCI_DEFAULT));

   checkerr(errhp, lstat = OCITransCommit(svchp, errhp, (ub4)0));

   checkerr(errhp, lstat = OCIHandleFree((dvoid *)stmthp, OCI_HTYPE_STMT));

   free(query);

   if (lstat == OCI_SUCCESS) {
      return TRUE;
   } else {
      return FALSE;
   }
}
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://gizmo.fireflynetworks.com/pipermail/rtg/attachments/20060606/1e9ca25f/attachment.htm


More information about the RTG mailing list