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 #include // 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; } }