2 * sql_oracle.c Oracle (OCI) routines for rlm_sql
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * Copyright 2000 The FreeRADIUS server project
19 * Copyright 2000 David Kerry <davidk@snti.com>
33 typedef struct rlm_sql_oracle_sock {
43 } rlm_sql_oracle_sock;
45 #define MAX_DATASTR_LEN 64
48 /*************************************************************************
52 * Purpose: database specific error. Returns error associated with
55 *************************************************************************/
56 static char *sql_error(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
58 static char msgbuf[512];
60 rlm_sql_oracle_sock *oracle_sock = sqlsocket->conn;
62 if (!oracle_sock) return "rlm_sql_oracle: no connection to db";
64 memset((void *) msgbuf, (int)'\0', sizeof(msgbuf));
66 OCIErrorGet((dvoid *) oracle_sock->errHandle, (ub4) 1, (text *) NULL,
67 &errcode, msgbuf, (ub4) sizeof(msgbuf), (ub4) OCI_HTYPE_ERROR);
77 /*************************************************************************
81 * Purpose: database specific close. Closes an open database
82 * connection and cleans up any open handles.
84 *************************************************************************/
85 static int sql_close(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
87 rlm_sql_oracle_sock *oracle_sock = sqlsocket->conn;
89 if (oracle_sock->conn) {
90 OCILogoff (oracle_sock->conn, oracle_sock->errHandle);
93 if (oracle_sock->queryHandle) {
94 OCIHandleFree((dvoid *)oracle_sock->queryHandle, (ub4) OCI_HTYPE_STMT);
96 if (oracle_sock->errHandle) {
97 OCIHandleFree((dvoid *)oracle_sock->errHandle, (ub4) OCI_HTYPE_ERROR);
99 if (oracle_sock->env) {
100 OCIHandleFree((dvoid *)oracle_sock->env, (ub4) OCI_HTYPE_ENV);
103 oracle_sock->conn = NULL;
105 sqlsocket->conn = NULL;
111 /*************************************************************************
113 * Function: sql_init_socket
115 * Purpose: Establish connection to the db
117 *************************************************************************/
118 static int sql_init_socket(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
120 rlm_sql_oracle_sock *oracle_sock;
122 if (!sqlsocket->conn) {
123 sqlsocket->conn = (rlm_sql_oracle_sock *)rad_malloc(sizeof(rlm_sql_oracle_sock));
124 if (!sqlsocket->conn) {
128 memset(sqlsocket->conn,0,sizeof(rlm_sql_oracle_sock));
130 oracle_sock = sqlsocket->conn;
132 if (OCIEnvCreate(&oracle_sock->env, OCI_DEFAULT|OCI_THREADED, (dvoid *)0,
133 (dvoid * (*)(dvoid *, size_t)) 0,
134 (dvoid * (*)(dvoid *, dvoid *, size_t))0,
135 (void (*)(dvoid *, dvoid *)) 0,
137 radlog(L_ERR,"rlm_sql_oracle: Couldn't init Oracle OCI environment (OCIEnvCreate())");
141 if (OCIHandleAlloc((dvoid *) oracle_sock->env, (dvoid **) &oracle_sock->errHandle,
142 (ub4) OCI_HTYPE_ERROR, (size_t) 0, (dvoid **) 0))
144 radlog(L_ERR,"rlm_sql_oracle: Couldn't init Oracle ERROR handle (OCIHandleAlloc())");
148 /* Allocate handles for select and update queries */
149 if (OCIHandleAlloc((dvoid *)oracle_sock->env, (dvoid **) &oracle_sock->queryHandle,
150 (ub4)OCI_HTYPE_STMT, (CONST size_t) 0, (dvoid **) 0))
152 radlog(L_ERR,"rlm_sql_oracle: Couldn't init Oracle query handles: %s",
153 sql_error(sqlsocket, config));
158 if (OCILogon(oracle_sock->env, oracle_sock->errHandle, &oracle_sock->conn,
159 config->sql_login, strlen(config->sql_login),
160 config->sql_password, strlen(config->sql_password),
161 config->sql_db, strlen(config->sql_db)))
163 radlog(L_ERR,"rlm_sql_oracle: Oracle logon failed: '%s'", sql_error(sqlsocket, config));
164 sql_close(sqlsocket,config);
172 /*************************************************************************
174 * Function: sql_destroy_socket
176 * Purpose: Free socket and private connection data
178 *************************************************************************/
179 static int sql_destroy_socket(SQLSOCK *sqlsocket, SQL_CONFIG *config)
181 free(sqlsocket->conn);
182 sqlsocket->conn = NULL;
186 /*************************************************************************
188 * Function: sql_num_fields
190 * Purpose: database specific num_fields function. Returns number
191 * of columns from query
193 *************************************************************************/
194 static int sql_num_fields(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
197 rlm_sql_oracle_sock *oracle_sock = sqlsocket->conn;
199 /* get the number of columns in the select list */
200 if (OCIAttrGet ((dvoid *)oracle_sock->queryHandle,
204 (ub4)OCI_ATTR_PARAM_COUNT,
205 oracle_sock->errHandle)) {
206 radlog(L_ERR,"rlm_sql_oracle: Error retrieving column count in sql_num_fields: %s",
207 sql_error(sqlsocket, config));
213 /*************************************************************************
215 * Function: sql_query
217 * Purpose: Issue a non-SELECT query (ie: update/delete/insert) to
220 *************************************************************************/
221 static int sql_query(SQLSOCK *sqlsocket, SQL_CONFIG *config, char *querystr) {
224 rlm_sql_oracle_sock *oracle_sock = sqlsocket->conn;
226 if (config->sqltrace)
228 if (oracle_sock->conn == NULL) {
229 radlog(L_ERR, "rlm_sql_oracle: Socket not connected");
233 if (OCIStmtPrepare (oracle_sock->queryHandle, oracle_sock->errHandle,
234 querystr, strlen(querystr),
235 OCI_NTV_SYNTAX, OCI_DEFAULT)) {
236 radlog(L_ERR,"rlm_sql_oracle: prepare failed in sql_query: %s",sql_error(sqlsocket, config));
240 x = OCIStmtExecute(oracle_sock->conn,
241 oracle_sock->queryHandle,
242 oracle_sock->errHandle,
245 (OCISnapshot *) NULL,
246 (OCISnapshot *) NULL,
249 if ((x != OCI_NO_DATA) && (x != OCI_SUCCESS)) {
250 radlog(L_ERR,"rlm_sql_oracle: execute query failed in sql_query: %s",
251 sql_error(sqlsocket, config));
255 x = OCITransCommit(oracle_sock->conn, oracle_sock->errHandle, (ub4) 0);
256 if (x != OCI_SUCCESS) {
257 radlog(L_ERR,"rlm_sql_oracle: commit failed in sql_query: %s",
258 sql_error(sqlsocket, config));
266 /*************************************************************************
268 * Function: sql_select_query
270 * Purpose: Issue a select query to the database
272 *************************************************************************/
273 static int sql_select_query(SQLSOCK *sqlsocket, SQL_CONFIG *config, char *querystr) {
284 rlm_sql_oracle_sock *oracle_sock = sqlsocket->conn;
286 if (config->sqltrace)
288 if (oracle_sock->conn == NULL) {
289 radlog(L_ERR, "rlm_sql_oracle: Socket not connected");
293 if (OCIStmtPrepare (oracle_sock->queryHandle, oracle_sock->errHandle,
294 querystr, strlen(querystr),
295 OCI_NTV_SYNTAX, OCI_DEFAULT)) {
296 radlog(L_ERR,"rlm_sql_oracle: prepare failed in sql_select_query: %s",sql_error(sqlsocket, config));
300 /* Query only one row by default (for now) */
301 x = OCIStmtExecute(oracle_sock->conn,
302 oracle_sock->queryHandle,
303 oracle_sock->errHandle,
306 (OCISnapshot *) NULL,
307 (OCISnapshot *) NULL,
310 if (x == OCI_NO_DATA) {
311 /* Nothing to fetch */
314 else if (x != OCI_SUCCESS) {
315 radlog(L_ERR,"rlm_sql_oracle: query failed in sql_select_query: %s",sql_error(sqlsocket, config));
320 * Define where the output from fetch calls will go
322 * This is a gross hack, but it works - we convert
323 * all data to strings for ease of use. Fortunately, most
324 * of the data we deal with is already in string format.
326 colcount = sql_num_fields(sqlsocket, config);
328 /* DEBUG2("sql_select_query(): colcount=%d",colcount); */
331 * FIXME: These malloc's can probably go, as the schema
334 rowdata=(char **)rad_malloc(sizeof(char *) * (colcount+1) );
335 memset(rowdata, 0, (sizeof(char *) * (colcount+1) ));
336 indicators = (sb2 *) rad_malloc(sizeof(sb2) * (colcount+1) );
337 memset(indicators, 0, sizeof(sb2) * (colcount+1));
339 for (y=1; y <= colcount; y++) {
340 x=OCIParamGet(oracle_sock->queryHandle, OCI_HTYPE_STMT,
341 oracle_sock->errHandle,
344 if (x != OCI_SUCCESS) {
345 radlog(L_ERR,"rlm_sql_oracle: OCIParamGet() failed in sql_select_query: %s",
346 sql_error(sqlsocket, config));
350 x=OCIAttrGet((dvoid*)param, OCI_DTYPE_PARAM,
351 (dvoid*)&dtype, (ub4*)0, OCI_ATTR_DATA_TYPE,
352 oracle_sock->errHandle);
353 if (x != OCI_SUCCESS) {
354 radlog(L_ERR,"rlm_sql_oracle: OCIAttrGet() failed in sql_select_query: %s",
355 sql_error(sqlsocket, config));
359 dsize=MAX_DATASTR_LEN;
362 * Use the retrieved length of dname to allocate an output
363 * buffer, and then define the output variable (but only
364 * for char/string type columns).
368 case SQLT_AFC: /* ansii fixed char */
371 case SQLT_AFV: /* ansii var char */
373 case SQLT_VCS: /* var char */
374 case SQLT_CHR: /* char */
375 case SQLT_STR: /* string */
376 x=OCIAttrGet((dvoid*)param, (ub4) OCI_DTYPE_PARAM,
377 (dvoid*) &dsize, (ub4 *)0, (ub4) OCI_ATTR_DATA_SIZE,
378 oracle_sock->errHandle);
379 if (x != OCI_SUCCESS) {
380 radlog(L_ERR,"rlm_sql_oracle: OCIAttrGet() failed in sql_select_query: %s",
381 sql_error(sqlsocket, config));
384 rowdata[y-1]=rad_malloc(dsize+1);
393 rowdata[y-1]=rad_malloc(dsize+1);
402 x=OCIDefineByPos(oracle_sock->queryHandle,
404 oracle_sock->errHandle,
406 (ub1 *) rowdata[y-1],
415 * FIXME: memory leaks of indicators & rowdata?
417 if (x != OCI_SUCCESS) {
418 radlog(L_ERR,"rlm_sql_oracle: OCIDefineByPos() failed in sql_select_query: %s",
419 sql_error(sqlsocket, config));
424 oracle_sock->results=rowdata;
425 oracle_sock->indicators=indicators;
431 /*************************************************************************
433 * Function: sql_store_result
435 * Purpose: database specific store_result function. Returns a result
438 *************************************************************************/
439 static int sql_store_result(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
440 /* Not needed for Oracle */
445 /*************************************************************************
447 * Function: sql_num_rows
449 * Purpose: database specific num_rows. Returns number of rows in
452 *************************************************************************/
453 static int sql_num_rows(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
456 rlm_sql_oracle_sock *oracle_sock = sqlsocket->conn;
458 OCIAttrGet((CONST dvoid *)oracle_sock->queryHandle,
463 oracle_sock->errHandle);
469 /*************************************************************************
471 * Function: sql_fetch_row
473 * Purpose: database specific fetch_row. Returns a SQL_ROW struct
474 * with all the data for the query in 'sqlsocket->row'. Returns
475 * 0 on success, -1 on failure, SQL_DOWN if database is down.
477 *************************************************************************/
478 static int sql_fetch_row(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
481 rlm_sql_oracle_sock *oracle_sock = sqlsocket->conn;
483 if (oracle_sock->conn == NULL) {
484 radlog(L_ERR, "rlm_sql_oracle: Socket not connected");
488 sqlsocket->row = NULL;
490 x=OCIStmtFetch(oracle_sock->queryHandle,
491 oracle_sock->errHandle,
495 if (x == OCI_NO_DATA) {
498 else if (x != OCI_SUCCESS) {
499 /* XXX Check if x suggests we should return SQL_DOWN */
500 radlog(L_ERR,"rlm_sql_oracle: fetch failed in sql_fetch_row: %s",
501 sql_error(sqlsocket, config));
505 sqlsocket->row = oracle_sock->results;
511 /*************************************************************************
513 * Function: sql_free_result
515 * Purpose: database specific free_result. Frees memory allocated
518 *************************************************************************/
519 static int sql_free_result(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
524 rlm_sql_oracle_sock *oracle_sock = sqlsocket->conn;
526 /* Cancel the cursor first */
527 x=OCIStmtFetch(oracle_sock->queryHandle,
528 oracle_sock->errHandle,
533 num_fields = sql_num_fields(sqlsocket, config);
534 if (num_fields >= 0) {
535 for(x=0; x < num_fields; x++) {
536 free(oracle_sock->results[x]);
538 free(oracle_sock->results);
539 free(oracle_sock->indicators);
541 oracle_sock->results=NULL;
547 /*************************************************************************
549 * Function: sql_finish_query
551 * Purpose: End the query, such as freeing memory
553 *************************************************************************/
554 static int sql_finish_query(SQLSOCK *sqlsocket, SQL_CONFIG *config)
561 /*************************************************************************
563 * Function: sql_finish_select_query
565 * Purpose: End the select query, such as freeing memory or result
567 *************************************************************************/
568 static int sql_finish_select_query(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
571 rlm_sql_oracle_sock *oracle_sock = sqlsocket->conn;
573 if (oracle_sock->results) {
574 while(oracle_sock->results[x]) free(oracle_sock->results[x++]);
575 free(oracle_sock->results);
576 free(oracle_sock->indicators);
577 oracle_sock->results=NULL;
584 /*************************************************************************
586 * Function: sql_affected_rows
588 * Purpose: Return the number of rows affected by the query (update,
591 *************************************************************************/
592 static int sql_affected_rows(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
594 return sql_num_rows(sqlsocket, config);
598 /* Exported to rlm_sql */
599 rlm_sql_module_t rlm_sql_oracle = {
613 sql_finish_select_query,