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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 * Copyright 2000,2006 The FreeRADIUS server project
19 * Copyright 2000 David Kerry <davidk@snti.com>
22 #include <freeradius-devel/ident.h>
25 #include <freeradius-devel/radiusd.h>
32 typedef struct rlm_sql_oracle_sock {
42 } rlm_sql_oracle_sock;
44 #define MAX_DATASTR_LEN 64
47 /*************************************************************************
51 * Purpose: database specific error. Returns error associated with
54 *************************************************************************/
55 static const char *sql_error(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
57 static char msgbuf[512];
59 rlm_sql_oracle_sock *oracle_sock = sqlsocket->conn;
61 if (!oracle_sock) return "rlm_sql_oracle: no connection to db";
63 memset((void *) msgbuf, (int)'\0', sizeof(msgbuf));
65 OCIErrorGet((dvoid *) oracle_sock->errHandle, (ub4) 1, (text *) NULL,
66 &errcode, msgbuf, (ub4) sizeof(msgbuf), (ub4) OCI_HTYPE_ERROR);
75 /*************************************************************************
77 * Function: sql_check_error
79 * Purpose: check the error to see if the server is down
81 *************************************************************************/
82 static int sql_check_error(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
84 if (strstr(sql_error(sqlsocket, config), "ORA-03113") ||
85 strstr(sql_error(sqlsocket, config), "ORA-03114")) {
86 radlog(L_ERR,"rlm_sql_oracle: OCI_SERVER_NOT_CONNECTED");
90 radlog(L_ERR,"rlm_sql_oracle: OCI_SERVER_NORMAL");
95 /*************************************************************************
99 * Purpose: database specific close. Closes an open database
100 * connection and cleans up any open handles.
102 *************************************************************************/
103 static int sql_close(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
105 rlm_sql_oracle_sock *oracle_sock = sqlsocket->conn;
107 if (oracle_sock->conn) {
108 OCILogoff (oracle_sock->conn, oracle_sock->errHandle);
111 if (oracle_sock->queryHandle) {
112 OCIHandleFree((dvoid *)oracle_sock->queryHandle, (ub4) OCI_HTYPE_STMT);
114 if (oracle_sock->errHandle) {
115 OCIHandleFree((dvoid *)oracle_sock->errHandle, (ub4) OCI_HTYPE_ERROR);
117 if (oracle_sock->env) {
118 OCIHandleFree((dvoid *)oracle_sock->env, (ub4) OCI_HTYPE_ENV);
121 oracle_sock->conn = NULL;
123 sqlsocket->conn = NULL;
129 /*************************************************************************
131 * Function: sql_init_socket
133 * Purpose: Establish connection to the db
135 *************************************************************************/
136 static int sql_init_socket(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
138 rlm_sql_oracle_sock *oracle_sock;
140 if (!sqlsocket->conn) {
141 sqlsocket->conn = (rlm_sql_oracle_sock *)rad_malloc(sizeof(rlm_sql_oracle_sock));
142 if (!sqlsocket->conn) {
146 memset(sqlsocket->conn,0,sizeof(rlm_sql_oracle_sock));
148 oracle_sock = sqlsocket->conn;
150 if (OCIEnvCreate(&oracle_sock->env, OCI_DEFAULT|OCI_THREADED, (dvoid *)0,
151 (dvoid * (*)(dvoid *, size_t)) 0,
152 (dvoid * (*)(dvoid *, dvoid *, size_t))0,
153 (void (*)(dvoid *, dvoid *)) 0,
155 radlog(L_ERR,"rlm_sql_oracle: Couldn't init Oracle OCI environment (OCIEnvCreate())");
159 if (OCIHandleAlloc((dvoid *) oracle_sock->env, (dvoid **) &oracle_sock->errHandle,
160 (ub4) OCI_HTYPE_ERROR, (size_t) 0, (dvoid **) 0))
162 radlog(L_ERR,"rlm_sql_oracle: Couldn't init Oracle ERROR handle (OCIHandleAlloc())");
166 /* Allocate handles for select and update queries */
167 if (OCIHandleAlloc((dvoid *)oracle_sock->env, (dvoid **) &oracle_sock->queryHandle,
168 (ub4)OCI_HTYPE_STMT, (CONST size_t) 0, (dvoid **) 0))
170 radlog(L_ERR,"rlm_sql_oracle: Couldn't init Oracle query handles: %s",
171 sql_error(sqlsocket, config));
176 if (OCILogon(oracle_sock->env, oracle_sock->errHandle, &oracle_sock->conn,
177 config->sql_login, strlen(config->sql_login),
178 config->sql_password, strlen(config->sql_password),
179 config->sql_db, strlen(config->sql_db)))
181 radlog(L_ERR,"rlm_sql_oracle: Oracle logon failed: '%s'", sql_error(sqlsocket, config));
182 sql_close(sqlsocket,config);
190 /*************************************************************************
192 * Function: sql_destroy_socket
194 * Purpose: Free socket and private connection data
196 *************************************************************************/
197 static int sql_destroy_socket(SQLSOCK *sqlsocket, SQL_CONFIG *config)
199 free(sqlsocket->conn);
200 sqlsocket->conn = NULL;
204 /*************************************************************************
206 * Function: sql_num_fields
208 * Purpose: database specific num_fields function. Returns number
209 * of columns from query
211 *************************************************************************/
212 static int sql_num_fields(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
215 rlm_sql_oracle_sock *oracle_sock = sqlsocket->conn;
217 /* get the number of columns in the select list */
218 if (OCIAttrGet ((dvoid *)oracle_sock->queryHandle,
222 (ub4)OCI_ATTR_PARAM_COUNT,
223 oracle_sock->errHandle)) {
224 radlog(L_ERR,"rlm_sql_oracle: Error retrieving column count in sql_num_fields: %s",
225 sql_error(sqlsocket, config));
231 /*************************************************************************
233 * Function: sql_query
235 * Purpose: Issue a non-SELECT query (ie: update/delete/insert) to
238 *************************************************************************/
239 static int sql_query(SQLSOCK *sqlsocket, SQL_CONFIG *config, char *querystr) {
242 rlm_sql_oracle_sock *oracle_sock = sqlsocket->conn;
244 if (config->sqltrace)
246 if (oracle_sock->conn == NULL) {
247 radlog(L_ERR, "rlm_sql_oracle: Socket not connected");
251 if (OCIStmtPrepare (oracle_sock->queryHandle, oracle_sock->errHandle,
252 querystr, strlen(querystr),
253 OCI_NTV_SYNTAX, OCI_DEFAULT)) {
254 radlog(L_ERR,"rlm_sql_oracle: prepare failed in sql_query: %s",sql_error(sqlsocket, config));
258 x = OCIStmtExecute(oracle_sock->conn,
259 oracle_sock->queryHandle,
260 oracle_sock->errHandle,
263 (OCISnapshot *) NULL,
264 (OCISnapshot *) NULL,
265 (ub4) OCI_COMMIT_ON_SUCCESS);
267 if (x == OCI_SUCCESS) {
271 if (x == OCI_ERROR) {
272 radlog(L_ERR,"rlm_sql_oracle: execute query failed in sql_query: %s",
273 sql_error(sqlsocket, config));
274 return sql_check_error(sqlsocket, config);
282 /*************************************************************************
284 * Function: sql_select_query
286 * Purpose: Issue a select query to the database
288 *************************************************************************/
289 static int sql_select_query(SQLSOCK *sqlsocket, SQL_CONFIG *config, char *querystr) {
300 rlm_sql_oracle_sock *oracle_sock = sqlsocket->conn;
302 if (config->sqltrace)
304 if (oracle_sock->conn == NULL) {
305 radlog(L_ERR, "rlm_sql_oracle: Socket not connected");
309 if (OCIStmtPrepare (oracle_sock->queryHandle, oracle_sock->errHandle,
310 querystr, strlen(querystr),
311 OCI_NTV_SYNTAX, OCI_DEFAULT)) {
312 radlog(L_ERR,"rlm_sql_oracle: prepare failed in sql_select_query: %s",sql_error(sqlsocket, config));
316 /* Query only one row by default (for now) */
317 x = OCIStmtExecute(oracle_sock->conn,
318 oracle_sock->queryHandle,
319 oracle_sock->errHandle,
322 (OCISnapshot *) NULL,
323 (OCISnapshot *) NULL,
326 if (x == OCI_NO_DATA) {
327 /* Nothing to fetch */
331 if (x != OCI_SUCCESS) {
332 radlog(L_ERR,"rlm_sql_oracle: query failed in sql_select_query: %s",
333 sql_error(sqlsocket, config));
334 return sql_check_error(sqlsocket, config);
338 * Define where the output from fetch calls will go
340 * This is a gross hack, but it works - we convert
341 * all data to strings for ease of use. Fortunately, most
342 * of the data we deal with is already in string format.
344 colcount = sql_num_fields(sqlsocket, config);
346 /* DEBUG2("sql_select_query(): colcount=%d",colcount); */
349 * FIXME: These malloc's can probably go, as the schema
352 rowdata=(char **)rad_malloc(sizeof(char *) * (colcount+1) );
353 memset(rowdata, 0, (sizeof(char *) * (colcount+1) ));
354 indicators = (sb2 *) rad_malloc(sizeof(sb2) * (colcount+1) );
355 memset(indicators, 0, sizeof(sb2) * (colcount+1));
357 for (y=1; y <= colcount; y++) {
358 x=OCIParamGet(oracle_sock->queryHandle, OCI_HTYPE_STMT,
359 oracle_sock->errHandle,
362 if (x != OCI_SUCCESS) {
363 radlog(L_ERR,"rlm_sql_oracle: OCIParamGet() failed in sql_select_query: %s",
364 sql_error(sqlsocket, config));
368 x=OCIAttrGet((dvoid*)param, OCI_DTYPE_PARAM,
369 (dvoid*)&dtype, (ub4*)0, OCI_ATTR_DATA_TYPE,
370 oracle_sock->errHandle);
371 if (x != OCI_SUCCESS) {
372 radlog(L_ERR,"rlm_sql_oracle: OCIAttrGet() failed in sql_select_query: %s",
373 sql_error(sqlsocket, config));
377 dsize=MAX_DATASTR_LEN;
380 * Use the retrieved length of dname to allocate an output
381 * buffer, and then define the output variable (but only
382 * for char/string type columns).
386 case SQLT_AFC: /* ansii fixed char */
389 case SQLT_AFV: /* ansii var char */
391 case SQLT_VCS: /* var char */
392 case SQLT_CHR: /* char */
393 case SQLT_STR: /* string */
394 x=OCIAttrGet((dvoid*)param, (ub4) OCI_DTYPE_PARAM,
395 (dvoid*) &dsize, (ub4 *)0, (ub4) OCI_ATTR_DATA_SIZE,
396 oracle_sock->errHandle);
397 if (x != OCI_SUCCESS) {
398 radlog(L_ERR,"rlm_sql_oracle: OCIAttrGet() failed in sql_select_query: %s",
399 sql_error(sqlsocket, config));
402 rowdata[y-1]=rad_malloc(dsize+1);
411 rowdata[y-1]=rad_malloc(dsize+1);
420 x=OCIDefineByPos(oracle_sock->queryHandle,
422 oracle_sock->errHandle,
424 (ub1 *) rowdata[y-1],
433 * FIXME: memory leaks of indicators & rowdata?
435 if (x != OCI_SUCCESS) {
436 radlog(L_ERR,"rlm_sql_oracle: OCIDefineByPos() failed in sql_select_query: %s",
437 sql_error(sqlsocket, config));
442 oracle_sock->results=rowdata;
443 oracle_sock->indicators=indicators;
449 /*************************************************************************
451 * Function: sql_store_result
453 * Purpose: database specific store_result function. Returns a result
456 *************************************************************************/
457 static int sql_store_result(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
458 /* Not needed for Oracle */
463 /*************************************************************************
465 * Function: sql_num_rows
467 * Purpose: database specific num_rows. Returns number of rows in
470 *************************************************************************/
471 static int sql_num_rows(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
474 rlm_sql_oracle_sock *oracle_sock = sqlsocket->conn;
476 OCIAttrGet((CONST dvoid *)oracle_sock->queryHandle,
481 oracle_sock->errHandle);
487 /*************************************************************************
489 * Function: sql_fetch_row
491 * Purpose: database specific fetch_row. Returns a SQL_ROW struct
492 * with all the data for the query in 'sqlsocket->row'. Returns
493 * 0 on success, -1 on failure, SQL_DOWN if database is down.
495 *************************************************************************/
496 static int sql_fetch_row(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
499 rlm_sql_oracle_sock *oracle_sock = sqlsocket->conn;
501 if (oracle_sock->conn == NULL) {
502 radlog(L_ERR, "rlm_sql_oracle: Socket not connected");
506 sqlsocket->row = NULL;
508 x=OCIStmtFetch(oracle_sock->queryHandle,
509 oracle_sock->errHandle,
514 if (x == OCI_SUCCESS) {
515 sqlsocket->row = oracle_sock->results;
519 if (x == OCI_ERROR) {
520 radlog(L_ERR,"rlm_sql_oracle: fetch failed in sql_fetch_row: %s",
521 sql_error(sqlsocket, config));
522 return sql_check_error(sqlsocket, config);
531 /*************************************************************************
533 * Function: sql_free_result
535 * Purpose: database specific free_result. Frees memory allocated
538 *************************************************************************/
539 static int sql_free_result(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
544 rlm_sql_oracle_sock *oracle_sock = sqlsocket->conn;
546 /* Cancel the cursor first */
547 x=OCIStmtFetch(oracle_sock->queryHandle,
548 oracle_sock->errHandle,
553 num_fields = sql_num_fields(sqlsocket, config);
554 if (num_fields >= 0) {
555 for(x=0; x < num_fields; x++) {
556 free(oracle_sock->results[x]);
558 free(oracle_sock->results);
559 free(oracle_sock->indicators);
561 oracle_sock->results=NULL;
567 /*************************************************************************
569 * Function: sql_finish_query
571 * Purpose: End the query, such as freeing memory
573 *************************************************************************/
574 static int sql_finish_query(SQLSOCK *sqlsocket, SQL_CONFIG *config)
581 /*************************************************************************
583 * Function: sql_finish_select_query
585 * Purpose: End the select query, such as freeing memory or result
587 *************************************************************************/
588 static int sql_finish_select_query(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
591 rlm_sql_oracle_sock *oracle_sock = sqlsocket->conn;
593 if (oracle_sock->results) {
594 while(oracle_sock->results[x]) free(oracle_sock->results[x++]);
595 free(oracle_sock->results);
596 free(oracle_sock->indicators);
597 oracle_sock->results=NULL;
604 /*************************************************************************
606 * Function: sql_affected_rows
608 * Purpose: Return the number of rows affected by the query (update,
611 *************************************************************************/
612 static int sql_affected_rows(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
614 return sql_num_rows(sqlsocket, config);
618 /* Exported to rlm_sql */
619 rlm_sql_module_t rlm_sql_oracle = {
633 sql_finish_select_query,