Committing part of Oracle patch for David Kerry <davidk@snti.com>.
authorjcarneal <jcarneal>
Mon, 15 Jan 2001 19:09:16 +0000 (19:09 +0000)
committerjcarneal <jcarneal>
Mon, 15 Jan 2001 19:09:16 +0000 (19:09 +0000)
I'm committing only the db_oracle.sql, sql_oracle.c,h files now.
The changes to the rlm_sql module from his patch most likely will
not apply now, so at a later date I (or someone) can add them back
in by hand where applicable.

src/modules/rlm_sql/drivers/rlm_sql_oracle/db_oracle.sql [new file with mode: 0644]
src/modules/rlm_sql/drivers/rlm_sql_oracle/sql_oracle.c [new file with mode: 0644]
src/modules/rlm_sql/drivers/rlm_sql_oracle/sql_oracle.h [new file with mode: 0644]

diff --git a/src/modules/rlm_sql/drivers/rlm_sql_oracle/db_oracle.sql b/src/modules/rlm_sql/drivers/rlm_sql_oracle/db_oracle.sql
new file mode 100644 (file)
index 0000000..57834e5
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * $Id$
+ *
+ * Oracle schema for FreeRADIUS
+ *
+ *
+ * NOTE: Which columns are NULLable??
+ */
+
+/*
+ * Table structure for table 'dictionary'
+ */
+CREATE TABLE dictionary (
+       id              INT PRIMARY KEY,
+       type            VARCHAR(30),
+       attribute       VARCHAR(32),
+       value           VARCHAR(32),
+       format          VARCHAR(20),
+       vendor          VARCHAR(32)
+);
+CREATE SEQUENCE dictionary_seq START WITH 1 INCREMENT BY 1;
+
+/*
+ * Table structure for table 'nas'
+ */
+CREATE TABLE nas (
+       id              INT PRIMARY KEY,
+       nasname         VARCHAR(128),
+       shortname       VARCHAR(32),
+       ipaddr          VARCHAR(15),
+       type            VARCHAR(30),
+       ports           INT,
+       secret          VARCHAR(60),
+       community       VARCHAR(50),
+       snmp            VARCHAR(10)
+);
+CREATE SEQUENCE nas_seq START WITH 1 INCREMENT BY 1;
+
+/*
+ * Table structure for table 'radacct'
+ */
+CREATE TABLE radacct (
+       radacctid               INT PRIMARY KEY,
+       acctsessionid           VARCHAR(32) NOT NULL,
+       acctuniqueid            VARCHAR(32),
+       username                VARCHAR(32) NOT NULL,
+       realm                   VARCHAR(30),
+       nasipaddress            VARCHAR(15) NOT NULL,
+       nasportid               NUMERIC(12),
+       nasporttype             VARCHAR(32),
+       acctstarttime           DATE,
+       acctstoptime            DATE,
+       acctsessiontime         NUMERIC(12),
+       acctauthentic           VARCHAR(32),
+       connectinfo_start       VARCHAR(32),
+       connectinfo_stop        VARCHAR(32),
+       acctinputoctets         NUMERIC(12),
+       acctoutputoctets        NUMERIC(12),
+       calledstationid         VARCHAR(10),
+       callingstationid        VARCHAR(10),
+       acctterminatecause      VARCHAR(32),
+       servicetype             VARCHAR(32),
+       framedprotocol          VARCHAR(32),
+       framedipaddress         VARCHAR(15),
+       acctstartdelay          NUMERIC(12),
+       acctstopdelay           NUMERIC(12)
+);
+CREATE UNIQUE INDEX radacct_idx1
+       ON radacct(acctsessionid,username,acctstarttime,
+               acctstoptime,nasipaddress,framedipaddress);
+
+CREATE SEQUENCE radacct_seq START WITH 1 INCREMENT BY 1;
+
+/* Trigger to emulate a serial # on the primary key */
+CREATE OR REPLACE TRIGGER radacct_serialnumber 
+       BEFORE INSERT OR UPDATE OF radacctid ON radacct
+       FOR EACH ROW
+       BEGIN
+               if ( :new.radacctid = 0 or :new.radacctid is null ) then
+                       SELECT radacct_seq.nextval into :new.radacctid from dual;
+               end if;
+       END;
+/
+
+/*
+ * Table structure for table 'radcheck'
+ */
+CREATE TABLE radcheck (
+       id              INT PRIMARY KEY,
+       username        VARCHAR(30) NOT NULL,
+       attribute       VARCHAR(30),
+       value           VARCHAR(40)
+);
+CREATE SEQUENCE radcheck_seq START WITH 1 INCREMENT BY 1;
+
+/* Trigger to emulate a serial # on the primary key */
+CREATE OR REPLACE TRIGGER radcheck_serialnumber 
+       BEFORE INSERT OR UPDATE OF id ON radcheck
+       FOR EACH ROW
+       BEGIN
+               if ( :new.id = 0 or :new.id is null ) then
+                       SELECT radcheck_seq.nextval into :new.id from dual;
+               end if;
+       END;
+/
+
+/*
+ * Table structure for table 'radgroupcheck'
+ */
+CREATE TABLE radgroupcheck (
+       id              INT PRIMARY KEY,
+       groupname       VARCHAR(20) UNIQUE NOT NULL,
+       attribute       VARCHAR(40),
+       value           VARCHAR(40)
+);
+CREATE SEQUENCE radgroupcheck_seq START WITH 1 INCREMENT BY 1;
+
+/*
+ * Table structure for table 'radgroupreply'
+ */
+CREATE TABLE radgroupreply (
+       id              INT PRIMARY KEY,
+       GroupName       VARCHAR(20) UNIQUE NOT NULL,
+       Attribute       VARCHAR(40),
+       Value           VARCHAR(40)
+);
+CREATE SEQUENCE radgroupreply_seq START WITH 1 INCREMENT BY 1;
+
+/*
+ * Table structure for table 'radreply'
+ */
+CREATE TABLE radreply (
+       id              INT PRIMARY KEY,
+       UserName        VARCHAR(30) NOT NULL,
+       Attribute       VARCHAR(30),
+       Value           VARCHAR(40)
+);
+CREATE INDEX radreply_idx1 ON radreply(UserName);
+CREATE SEQUENCE radreply_seq START WITH 1 INCREMENT BY 1;
+
+/* Trigger to emulate a serial # on the primary key */
+CREATE OR REPLACE TRIGGER radreply_serialnumber 
+       BEFORE INSERT OR UPDATE OF id ON radreply
+       FOR EACH ROW
+       BEGIN
+               if ( :new.id = 0 or :new.id is null ) then
+                       SELECT radreply_seq.nextval into :new.id from dual;
+               end if;
+       END;
+/
+
+/*
+ * Table structure for table 'usergroup'
+ */
+CREATE TABLE usergroup (
+       id              INT PRIMARY KEY,
+       UserName        VARCHAR(30) UNIQUE NOT NULL,
+       GroupName       VARCHAR(30)
+);
+CREATE SEQUENCE usergroup_seq START WITH 1 INCREMENT BY 1;
+
+/*
+ * Table structure for table 'realmgroup'
+ */
+CREATE TABLE realmgroup (
+       id              INT PRIMARY KEY,
+       RealmName       VARCHAR(30) UNIQUE NOT NULL,
+       GroupName       VARCHAR(30)
+);
+CREATE SEQUENCE realmgroup_seq START WITH 1 INCREMENT BY 1;
+
+CREATE TABLE realms (
+       id              INT PRIMARY KEY,
+       realmname       VARCHAR(64),
+       nas             VARCHAR(128),
+       authport        INT,
+       options         VARCHAR(128)
+);
+CREATE SEQUENCE realms_seq START WITH 1 INCREMENT BY 1;
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_oracle/sql_oracle.c b/src/modules/rlm_sql/drivers/rlm_sql_oracle/sql_oracle.c
new file mode 100644 (file)
index 0000000..7c34ebf
--- /dev/null
@@ -0,0 +1,537 @@
+/***************************************************************************
+*  sql_oracle.c                        rlm_sql - FreeRADIUS SQL Module     *
+*                                                                          *
+*      Oracle (OCI) routines for rlm_sql                                   *
+*                                                                          *
+*                                     David Kerry <davidk@snti.com>        *
+***************************************************************************/
+#include <stdio.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include       "radiusd.h"
+#include       "rlm_sql.h"
+
+#define        MAX_DATASTR_LEN 64
+
+/*************************************************************************
+ *
+ *     Function: sql_create_socket
+ *
+ *     Purpose: Establish connection to the db
+ *
+ *************************************************************************/
+SQLSOCK *sql_create_socket(SQL_INST *inst)
+{
+       SQLSOCK *socket;
+
+       if ((socket = malloc(sizeof(SQLSOCK))) == NULL) {
+               radlog(L_CONS|L_ERR, "sql_create_socket: no memory");
+               exit(1);
+       }
+
+       if (OCIEnvCreate(&socket->env, OCI_DEFAULT, (dvoid *)0,
+               (dvoid * (*)(dvoid *, size_t)) 0,
+               (dvoid * (*)(dvoid *, dvoid *, size_t))0, 
+               (void (*)(dvoid *, dvoid *)) 0,
+               0, (dvoid **)0 )) {
+               radlog(L_ERR,"Init: Couldn't init Oracle OCI environment (OCIEnvCreate())");
+               return NULL;
+       }
+
+       if (OCIHandleAlloc((dvoid *) socket->env, (dvoid **) &socket->errHandle,
+               (ub4) OCI_HTYPE_ERROR, (size_t) 0, (dvoid **) 0))
+       {
+               radlog(L_ERR,"Init: Couldn't init Oracle ERROR handle (OCIHandleAlloc())");
+               return NULL;
+       }
+
+       /* Allocate handles for select and update queries */
+       if (OCIHandleAlloc((dvoid *)socket->env, (dvoid **) &socket->queryHandle,
+                               (ub4)OCI_HTYPE_STMT, (CONST size_t) 0, (dvoid **) 0)
+           ||  OCIHandleAlloc((dvoid *)socket->env, (dvoid **) &socket->queryHandle,
+                               (ub4)OCI_HTYPE_STMT, (CONST size_t) 0, (dvoid **) 0))
+       {
+               radlog(L_ERR,"Init: Couldn't init Oracle query handles: %s",
+                       sql_error(socket));
+               return NULL;
+       }
+
+
+       if (OCILogon(socket->env, socket->errHandle, &socket->conn,
+                       inst->config->sql_login, strlen(inst->config->sql_login),
+                       inst->config->sql_password,  strlen(inst->config->sql_password),
+                       inst->config->sql_db, strlen(inst->config->sql_db)))
+       {
+               radlog(L_ERR,"Init: Oracle logon failed: '%s'", sql_error(socket));
+               return NULL;
+       }
+
+       return socket;
+}
+
+/*************************************************************************
+ *
+ *     Function: sql_query
+ *
+ *     Purpose: Issue a non-SELECT query (ie: update/delete/insert) to
+ *               the database.
+ *
+ *************************************************************************/
+int sql_query(SQL_INST *inst, SQLSOCK *socket, char *querystr)
+{
+       int     x;
+
+       if (inst->config->sqltrace)
+               DEBUG(querystr);
+        if (socket->conn == NULL) {
+               radlog(L_ERR, "Socket not connected");
+               return 0;
+       }
+
+       if (OCIStmtPrepare (socket->queryHandle, socket->errHandle,
+                               querystr, strlen(querystr),
+                               OCI_NTV_SYNTAX, OCI_DEFAULT))  {
+               radlog(L_ERR,"sql_query: prepare failed: %s",sql_error(socket));
+               return -1;
+       }
+
+       x = OCIStmtExecute(socket->conn,
+                               socket->queryHandle,
+                               socket->errHandle,
+                               (ub4) 1,
+                               (ub4) 0,
+                               (OCISnapshot *) NULL,
+                               (OCISnapshot *) NULL,
+                               (ub4) OCI_DEFAULT);
+
+       if ((x != OCI_NO_DATA) && (x != OCI_SUCCESS)) {
+               return -1;
+       }
+
+       x = OCITransCommit(socket->conn, socket->errHandle, (ub4) 0);
+       if (x != OCI_SUCCESS)
+               return -1;
+
+       return 0;
+}
+
+
+/*************************************************************************
+ *
+ *     Function: sql_select_query
+ *
+ *     Purpose: Issue a select query to the database
+ *
+ *************************************************************************/
+int sql_select_query(SQL_INST *inst, SQLSOCK *socket, char *querystr)
+{
+       int             x;
+       int             y;
+       int             colcount;
+       OCIParam        *param;
+       OCIDefine       *define;
+       ub2             dtype;
+       ub4             dsize;
+       char            **rowdata=NULL;
+
+       if (inst->config->sqltrace)
+               DEBUG(querystr);
+        if (socket->conn == NULL) {
+               radlog(L_ERR, "Socket not connected");
+               return -1;
+       }
+
+       if (OCIStmtPrepare (socket->queryHandle, socket->errHandle,
+                               querystr, strlen(querystr),
+                               OCI_NTV_SYNTAX, OCI_DEFAULT))  {
+               radlog(L_ERR,"sql_select_query: prepare failed: %s",sql_error(socket));
+               return -1;
+       }
+
+       /* Query only one row by default (for now) */
+       x = OCIStmtExecute(socket->conn,
+                               socket->queryHandle,
+                               socket->errHandle,
+                               (ub4) 0,
+                               (ub4) 0,
+                               (OCISnapshot *) NULL,
+                               (OCISnapshot *) NULL,
+                               (ub4) OCI_DEFAULT);
+
+       if (x == OCI_NO_DATA) {
+               /* Nothing to fetch */
+               return 0;
+       }
+       else if (x != OCI_SUCCESS) {
+               return -1;
+       }
+
+       /*
+        * Define where the output from fetch calls will go
+        *
+        * This is a gross hack, but it works - we convert
+        * all data to strings for ease of use.  Fortunately, most
+        * of the data we deal with is already in string format.
+        */
+       colcount=sql_num_fields(socket);
+
+       /* DEBUG2("sql_select_query(): colcount=%d",colcount); */
+
+       rowdata=(char **)malloc(sizeof(char *) * (colcount+1) );
+       memset(rowdata, 0, (sizeof(char *) * (colcount+1) ));
+
+       for (y=1; y <= colcount; y++) {
+               x=OCIParamGet(socket->queryHandle, OCI_HTYPE_STMT,
+                               socket->errHandle,
+                               (dvoid **)&param,
+                               (ub4) y);
+               if (x != OCI_SUCCESS) {
+                       radlog(L_ERR,"sql_select_query: OCIParamGet() failed: %s",
+                               sql_error(socket));
+                       return -1;
+               }
+
+               x=OCIAttrGet((dvoid*)param, OCI_DTYPE_PARAM, 
+                          (dvoid*)&dtype, (ub4*)0, OCI_ATTR_DATA_TYPE,
+                          socket->errHandle);
+               if (x != OCI_SUCCESS) {
+                       radlog(L_ERR,"sql_select_query: OCIAttrGet() failed: %s",
+                               sql_error(socket));
+                       return -1;
+               }
+
+               dsize=MAX_DATASTR_LEN;
+
+               /*
+                * Use the retrieved length of dname to allocate an output
+                * buffer, and then define the output variable (but only
+                * for char/string type columns).
+                */
+               switch(dtype) {
+               case SQLT_CHR:
+               case SQLT_STR:
+                       x=OCIAttrGet((dvoid*)param, (ub4) OCI_DTYPE_PARAM,
+                                  (dvoid*) &dsize, (ub4 *)0, (ub4) OCI_ATTR_DATA_SIZE,
+                                  socket->errHandle);
+                       if (x != OCI_SUCCESS) {
+                               radlog(L_ERR,"sql_select_query: OCIAttrGet() failed: %s",
+                                       sql_error(socket));
+                               return -1;
+                       }
+                       rowdata[y-1]=malloc(dsize+1);
+                       break;
+               case SQLT_DAT:
+               case SQLT_INT:
+               case SQLT_UIN:
+               case SQLT_FLT:
+               case SQLT_PDN:
+               case SQLT_BIN:
+               case SQLT_NUM:
+                       rowdata[y-1]=malloc(dsize+1);
+                       break;
+               default:
+                       dsize=0;
+                       rowdata[y-1]=NULL;
+                       break;
+               }
+
+               x=OCIDefineByPos(socket->queryHandle,
+                               &define,
+                               socket->errHandle,
+                               y,
+                               (ub1 *) rowdata[y-1],
+                               dsize,
+                               SQLT_STR,
+                               (dvoid *) 0,
+                               (dvoid *) 0,
+                               (dvoid *) 0,
+                               OCI_DEFAULT);
+               if (x != OCI_SUCCESS) {
+                       radlog(L_ERR,"sql_select_query: OCIDefineByPos() failed: %s",
+                               sql_error(socket));
+                       return -1;
+               }
+       }
+
+       rowdata[y-1]=NULL; /* Terminate the array */
+
+       socket->results=rowdata;
+
+       return 1;
+}
+
+
+/*************************************************************************
+ *
+ *     Function: sql_store_result
+ *
+ *     Purpose: database specific store_result function. Returns a result
+ *               set for the query.
+ *
+ *************************************************************************/
+int sql_store_result(SQLSOCK *socket) {
+       /* Not needed for Oracle */
+       return 0;
+}
+
+
+/*************************************************************************
+ *
+ *     Function: sql_num_fields
+ *
+ *     Purpose: database specific num_fields function. Returns number
+ *               of columns from query
+ *
+ *************************************************************************/
+int sql_num_fields(SQLSOCK *socket) {
+
+       ub4             count;
+
+       /* get the number of columns in the select list */ 
+       if (OCIAttrGet ((dvoid *)socket->queryHandle,
+                       (ub4)OCI_HTYPE_STMT,
+                       (dvoid *) &count,
+                       (ub4 *) 0,
+                       (ub4)OCI_ATTR_PARAM_COUNT,
+                       socket->errHandle)) {
+               radlog(L_ERR,"sql_num_fields: error retrieving colun count: %s",
+                       sql_error(socket));
+               return -1;
+       }
+       return count;
+}
+
+/*************************************************************************
+ *
+ *     Function: sql_num_rows
+ *
+ *     Purpose: database specific num_rows. Returns number of rows in
+ *               query
+ *
+ *************************************************************************/
+int sql_num_rows(SQLSOCK *socket) {
+
+       ub4     rows=0;
+
+       OCIAttrGet((CONST dvoid *)socket->queryHandle,
+                       OCI_HTYPE_STMT,
+                       (dvoid *)&rows, 
+                       (ub4 *) sizeof(ub4),
+                       OCI_ATTR_ROW_COUNT,
+                       socket->errHandle);
+
+       return rows;
+}
+
+
+/*************************************************************************
+ *
+ *     Function: sql_fetch_row
+ *
+ *     Purpose: database specific fetch_row. Returns a SQL_ROW struct
+ *               with all the data for the query
+ *
+ *************************************************************************/
+SQL_ROW sql_fetch_row(SQLSOCK *socket)
+{
+       int     x;
+
+       x=OCIStmtFetch(socket->queryHandle,
+                       socket->errHandle,
+                       1,
+                       OCI_FETCH_NEXT,
+                       OCI_DEFAULT);
+       if (x == OCI_NO_DATA) {
+               return NULL;
+       }
+       else if (x != OCI_SUCCESS) {
+               radlog(L_ERR,"sql_fetch_row: fetch failed: %s",
+                               sql_error(socket));
+               return NULL;
+       }
+
+       return socket->results;
+}
+
+
+
+/*************************************************************************
+ *
+ *     Function: sql_free_result
+ *
+ *     Purpose: database specific free_result. Frees memory allocated
+ *               for a result set
+ *
+ *************************************************************************/
+void sql_free_result(SQLSOCK *socket) {
+       /* Nothing to do here for Oracle */
+}
+
+
+
+/*************************************************************************
+ *
+ *     Function: sql_error
+ *
+ *     Purpose: database specific error. Returns error associated with
+ *               connection
+ *
+ *************************************************************************/
+char *sql_error(SQLSOCK *socket)
+{
+       static char     msgbuf[512];
+       int             errcode = 0;
+       memset((void *) msgbuf, (int)'\0', sizeof(msgbuf));
+
+       OCIErrorGet((dvoid *) socket->errHandle, (ub4) 1, (text *) NULL,
+               &errcode, msgbuf, (ub4) sizeof(msgbuf), (ub4) OCI_HTYPE_ERROR);
+       if (errcode) {
+               return msgbuf;
+       }
+       else {
+               return NULL;
+       }
+}
+
+
+/*************************************************************************
+ *
+ *     Function: sql_close
+ *
+ *     Purpose: database specific close. Closes an open database
+ *               connection and cleans up any open handles.
+ *
+ *************************************************************************/
+void sql_close(SQLSOCK *socket)
+{
+
+       if (socket->conn) {
+               OCILogoff (socket->conn, socket->errHandle);
+       }
+
+       if (socket->queryHandle) {
+               OCIHandleFree((dvoid *)socket->queryHandle, (ub4) OCI_HTYPE_STMT);
+       }
+       if (socket->errHandle) {
+               OCIHandleFree((dvoid *)socket->errHandle, (ub4) OCI_HTYPE_ERROR);
+       }
+       if (socket->env) {
+               OCIHandleFree((dvoid *)socket->env, (ub4) OCI_HTYPE_ENV);
+       }
+
+       socket->conn = NULL;
+}
+
+
+/*************************************************************************
+ *
+ *     Function: sql_finish_query
+ *
+ *     Purpose: End the query, such as freeing memory
+ *
+ *************************************************************************/
+void sql_finish_query(SQLSOCK *socket)
+{
+       /* Nothing to do here for Oracle */
+}
+
+
+
+/*************************************************************************
+ *
+ *     Function: sql_finish_select_query
+ *
+ *     Purpose: End the select query, such as freeing memory or result
+ *
+ *************************************************************************/
+void sql_finish_select_query(SQLSOCK *socket)
+{
+       int     x=0;
+
+       if (socket->results) {
+               while(socket->results[x]) free(socket->results[x++]);
+               free(socket->results);
+               socket->results=NULL;
+       }
+
+}
+
+
+/*************************************************************************
+ *
+ *     Function: sql_affected_rows
+ *
+ *     Purpose: Return the number of rows affected by the query (update,
+ *               or insert)
+ *
+ *************************************************************************/
+int sql_affected_rows(SQLSOCK *socket) {
+       return sql_num_rows(socket);
+}
+
+
+/*************************************************************************
+ *
+ *      Function: sql_escape_string
+ *
+ *      Purpose: Esacpe "'" and any other wierd charactors
+ *
+ *************************************************************************/
+int sql_escape_string(char *to, char *from, int length)
+{
+       int x;
+       int y;
+
+       for(x=0, y=0; x < length; x++) {
+               if (from[x] == '\'') {
+                       to[y++]='\'';
+               }
+               to[y++]=from[x];
+       }
+       to[y]=0;
+
+       return 1;
+}
+
+/*************************************************************************
+ *
+ *      Function: check_error
+ *
+ *      Purpose: Check query return value for potential errors
+ *
+ *************************************************************************/
+static void checkerr(SQLSOCK *socket, sword status)
+{
+       switch (status) {
+       case OCI_SUCCESS: break;
+       case OCI_SUCCESS_WITH_INFO:
+               printf("status = OCI_SUCCESS_WITH_INFO\n");
+               printf("OCI err: %s\n",sql_error(socket));
+               break;
+       case OCI_NEED_DATA:
+               printf("status = OCI_NEED_DATA\n");
+               break;
+       case OCI_NO_DATA:
+               printf("status = OCI_NO_DATA\n");
+               break;
+       case OCI_ERROR:
+               printf("status = OCI_ERROR\n");
+               printf("OCI err: %s\n",sql_error(socket));
+               break;
+       case OCI_INVALID_HANDLE:
+               printf("status = OCI_INVALID_HANDLE\n");
+               break;
+       case OCI_STILL_EXECUTING:
+               printf("status = OCI_STILL_EXECUTE\n");
+               break;
+       case OCI_CONTINUE:
+               printf("status = OCI_CONTINUE\n");
+               break;
+       default:
+               break;
+       }
+}
+
diff --git a/src/modules/rlm_sql/drivers/rlm_sql_oracle/sql_oracle.h b/src/modules/rlm_sql/drivers/rlm_sql_oracle/sql_oracle.h
new file mode 100644 (file)
index 0000000..3090ba4
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * $Id$
+ *
+ * Oracle 8i OCI interface abstraction definitions and structures.
+ */
+#ifndef SQL_ORACLE_H
+#define SQL_ORACLE_H
+
+#include "conf.h"
+#include <oci.h>
+
+typedef char** SQL_ROW;
+
+typedef struct {
+       OCIEnv          *env;
+       OCIError        *errHandle;
+       OCISvcCtx       *conn;
+       OCIStmt         *queryHandle;
+       char            **results;
+       int             id;
+       int             in_use;
+       struct timeval  tv;
+} SQLSOCK;
+typedef struct sql_config {
+       char    *sql_server;
+       char    *sql_login;
+       char    *sql_password;
+       char    *sql_db;
+       char    *sql_acct_table;
+       char    *sql_authcheck_table;
+       char    *sql_authreply_table;
+       char    *sql_groupcheck_table;
+       char    *sql_groupreply_table;
+       char    *sql_usergroup_table;
+       char    *sql_realm_table;
+       char    *sql_realmgroup_table;
+       char    *sql_nas_table;
+       char    *sql_dict_table;
+       int     sensitiveusername;
+       int     sqltrace;
+       char    *tracefile;
+       int     deletestalesessions;
+       int     num_sql_socks;
+} SQL_CONFIG;
+
+typedef struct sql {
+       SQL_CONFIG *config;
+       SQLSOCK *socks[MAX_SQL_SOCKS];
+#if HAVE_PTHREAD_H
+       pthread_mutex_t sqlsock_mutex;
+#endif
+} SQL_INST;
+SQLSOCK *sql_create_socket(SQL_INST *inst);
+int     sql_checksocket(const char *facility);
+int     sql_query(SQL_INST *inst, SQLSOCK * socket, char *querystr);
+int     sql_select_query(SQL_INST *inst, SQLSOCK * socket, char *querystr);
+int     sql_store_result(SQLSOCK * socket);
+int     sql_num_fields(SQLSOCK * socket);
+int     sql_num_rows(SQLSOCK * socket);
+SQL_ROW sql_fetch_row(SQLSOCK * socket);
+void    sql_free_result(SQLSOCK * socket);
+char   *sql_error(SQLSOCK * socket);
+void    sql_close(SQLSOCK * socket);
+void    sql_finish_query(SQLSOCK * socket);
+void    sql_finish_select_query(SQLSOCK * socket);
+int     sql_affected_rows(SQLSOCK * socket);
+int     sql_escape_string(char *to, char *from, int length);
+
+#endif /* SQL_ORACLE_H */