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 The FreeRADIUS server project
19 * Copyright 2000 David Kerry <davidk@snti.com>
22 #include <freeradius-devel/autoconf.h>
30 #include <freeradius-devel/radiusd.h>
35 typedef struct rlm_sql_oracle_sock {
45 } rlm_sql_oracle_sock;
47 #define MAX_DATASTR_LEN 64
50 /*************************************************************************
54 * Purpose: database specific error. Returns error associated with
57 *************************************************************************/
58 static char *sql_error(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
60 static char msgbuf[512];
62 rlm_sql_oracle_sock *oracle_sock = sqlsocket->conn;
64 if (!oracle_sock) return "rlm_sql_oracle: no connection to db";
66 memset((void *) msgbuf, (int)'\0', sizeof(msgbuf));
68 OCIErrorGet((dvoid *) oracle_sock->errHandle, (ub4) 1, (text *) NULL,
69 &errcode, msgbuf, (ub4) sizeof(msgbuf), (ub4) OCI_HTYPE_ERROR);
78 /*************************************************************************
80 * Function: sql_check_error
82 * Purpose: check the error to see if the server is down
84 *************************************************************************/
85 static int sql_check_error(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
87 if (strstr(sql_error(sqlsocket, config), "ORA-03113") ||
88 strstr(sql_error(sqlsocket, config), "ORA-03114")) {
89 radlog(L_ERR,"rlm_sql_oracle: OCI_SERVER_NOT_CONNECTED");
93 radlog(L_ERR,"rlm_sql_oracle: OCI_SERVER_NORMAL");
98 /*************************************************************************
100 * Function: sql_close
102 * Purpose: database specific close. Closes an open database
103 * connection and cleans up any open handles.
105 *************************************************************************/
106 static int sql_close(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
108 rlm_sql_oracle_sock *oracle_sock = sqlsocket->conn;
110 if (oracle_sock->conn) {
111 OCILogoff (oracle_sock->conn, oracle_sock->errHandle);
114 if (oracle_sock->queryHandle) {
115 OCIHandleFree((dvoid *)oracle_sock->queryHandle, (ub4) OCI_HTYPE_STMT);
117 if (oracle_sock->errHandle) {
118 OCIHandleFree((dvoid *)oracle_sock->errHandle, (ub4) OCI_HTYPE_ERROR);
120 if (oracle_sock->env) {
121 OCIHandleFree((dvoid *)oracle_sock->env, (ub4) OCI_HTYPE_ENV);
124 oracle_sock->conn = NULL;
126 sqlsocket->conn = NULL;
132 /*************************************************************************
134 * Function: sql_init_socket
136 * Purpose: Establish connection to the db
138 *************************************************************************/
139 static int sql_init_socket(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
141 rlm_sql_oracle_sock *oracle_sock;
143 if (!sqlsocket->conn) {
144 sqlsocket->conn = (rlm_sql_oracle_sock *)rad_malloc(sizeof(rlm_sql_oracle_sock));
145 if (!sqlsocket->conn) {
149 memset(sqlsocket->conn,0,sizeof(rlm_sql_oracle_sock));
151 oracle_sock = sqlsocket->conn;
153 if (OCIEnvCreate(&oracle_sock->env, OCI_DEFAULT|OCI_THREADED, (dvoid *)0,
154 (dvoid * (*)(dvoid *, size_t)) 0,
155 (dvoid * (*)(dvoid *, dvoid *, size_t))0,
156 (void (*)(dvoid *, dvoid *)) 0,
158 radlog(L_ERR,"rlm_sql_oracle: Couldn't init Oracle OCI environment (OCIEnvCreate())");
162 if (OCIHandleAlloc((dvoid *) oracle_sock->env, (dvoid **) &oracle_sock->errHandle,
163 (ub4) OCI_HTYPE_ERROR, (size_t) 0, (dvoid **) 0))
165 radlog(L_ERR,"rlm_sql_oracle: Couldn't init Oracle ERROR handle (OCIHandleAlloc())");
169 /* Allocate handles for select and update queries */
170 if (OCIHandleAlloc((dvoid *)oracle_sock->env, (dvoid **) &oracle_sock->queryHandle,
171 (ub4)OCI_HTYPE_STMT, (CONST size_t) 0, (dvoid **) 0))
173 radlog(L_ERR,"rlm_sql_oracle: Couldn't init Oracle query handles: %s",
174 sql_error(sqlsocket, config));
179 if (OCILogon(oracle_sock->env, oracle_sock->errHandle, &oracle_sock->conn,
180 config->sql_login, strlen(config->sql_login),
181 config->sql_password, strlen(config->sql_password),
182 config->sql_db, strlen(config->sql_db)))
184 radlog(L_ERR,"rlm_sql_oracle: Oracle logon failed: '%s'", sql_error(sqlsocket, config));
185 sql_close(sqlsocket,config);
193 /*************************************************************************
195 * Function: sql_destroy_socket
197 * Purpose: Free socket and private connection data
199 *************************************************************************/
200 static int sql_destroy_socket(SQLSOCK *sqlsocket, SQL_CONFIG *config)
202 free(sqlsocket->conn);
203 sqlsocket->conn = NULL;
207 /*************************************************************************
209 * Function: sql_num_fields
211 * Purpose: database specific num_fields function. Returns number
212 * of columns from query
214 *************************************************************************/
215 static int sql_num_fields(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
218 rlm_sql_oracle_sock *oracle_sock = sqlsocket->conn;
220 /* get the number of columns in the select list */
221 if (OCIAttrGet ((dvoid *)oracle_sock->queryHandle,
225 (ub4)OCI_ATTR_PARAM_COUNT,
226 oracle_sock->errHandle)) {
227 radlog(L_ERR,"rlm_sql_oracle: Error retrieving column count in sql_num_fields: %s",
228 sql_error(sqlsocket, config));
234 /*************************************************************************
236 * Function: sql_query
238 * Purpose: Issue a non-SELECT query (ie: update/delete/insert) to
241 *************************************************************************/
242 static int sql_query(SQLSOCK *sqlsocket, SQL_CONFIG *config, char *querystr) {
245 rlm_sql_oracle_sock *oracle_sock = sqlsocket->conn;
247 if (config->sqltrace)
249 if (oracle_sock->conn == NULL) {
250 radlog(L_ERR, "rlm_sql_oracle: Socket not connected");
254 if (OCIStmtPrepare (oracle_sock->queryHandle, oracle_sock->errHandle,
255 querystr, strlen(querystr),
256 OCI_NTV_SYNTAX, OCI_DEFAULT)) {
257 radlog(L_ERR,"rlm_sql_oracle: prepare failed in sql_query: %s",sql_error(sqlsocket, config));
261 x = OCIStmtExecute(oracle_sock->conn,
262 oracle_sock->queryHandle,
263 oracle_sock->errHandle,
266 (OCISnapshot *) NULL,
267 (OCISnapshot *) NULL,
268 (ub4) OCI_COMMIT_ON_SUCCESS);
270 if (x == OCI_SUCCESS) {
274 if (x == OCI_ERROR) {
275 radlog(L_ERR,"rlm_sql_oracle: execute query failed in sql_query: %s",
276 sql_error(sqlsocket, config));
277 return sql_check_error(sqlsocket, config);
285 /*************************************************************************
287 * Function: sql_select_query
289 * Purpose: Issue a select query to the database
291 *************************************************************************/
292 static int sql_select_query(SQLSOCK *sqlsocket, SQL_CONFIG *config, char *querystr) {
303 rlm_sql_oracle_sock *oracle_sock = sqlsocket->conn;
305 if (config->sqltrace)
307 if (oracle_sock->conn == NULL) {
308 radlog(L_ERR, "rlm_sql_oracle: Socket not connected");
312 if (OCIStmtPrepare (oracle_sock->queryHandle, oracle_sock->errHandle,
313 querystr, strlen(querystr),
314 OCI_NTV_SYNTAX, OCI_DEFAULT)) {
315 radlog(L_ERR,"rlm_sql_oracle: prepare failed in sql_select_query: %s",sql_error(sqlsocket, config));
319 /* Query only one row by default (for now) */
320 x = OCIStmtExecute(oracle_sock->conn,
321 oracle_sock->queryHandle,
322 oracle_sock->errHandle,
325 (OCISnapshot *) NULL,
326 (OCISnapshot *) NULL,
329 if (x == OCI_NO_DATA) {
330 /* Nothing to fetch */
334 if (x != OCI_SUCCESS) {
335 radlog(L_ERR,"rlm_sql_oracle: query failed in sql_select_query: %s",
336 sql_error(sqlsocket, config));
337 return sql_check_error(sqlsocket, config);
341 * Define where the output from fetch calls will go
343 * This is a gross hack, but it works - we convert
344 * all data to strings for ease of use. Fortunately, most
345 * of the data we deal with is already in string format.
347 colcount = sql_num_fields(sqlsocket, config);
349 /* DEBUG2("sql_select_query(): colcount=%d",colcount); */
352 * FIXME: These malloc's can probably go, as the schema
355 rowdata=(char **)rad_malloc(sizeof(char *) * (colcount+1) );
356 memset(rowdata, 0, (sizeof(char *) * (colcount+1) ));
357 indicators = (sb2 *) rad_malloc(sizeof(sb2) * (colcount+1) );
358 memset(indicators, 0, sizeof(sb2) * (colcount+1));
360 for (y=1; y <= colcount; y++) {
361 x=OCIParamGet(oracle_sock->queryHandle, OCI_HTYPE_STMT,
362 oracle_sock->errHandle,
365 if (x != OCI_SUCCESS) {
366 radlog(L_ERR,"rlm_sql_oracle: OCIParamGet() failed in sql_select_query: %s",
367 sql_error(sqlsocket, config));
371 x=OCIAttrGet((dvoid*)param, OCI_DTYPE_PARAM,
372 (dvoid*)&dtype, (ub4*)0, OCI_ATTR_DATA_TYPE,
373 oracle_sock->errHandle);
374 if (x != OCI_SUCCESS) {
375 radlog(L_ERR,"rlm_sql_oracle: OCIAttrGet() failed in sql_select_query: %s",
376 sql_error(sqlsocket, config));
380 dsize=MAX_DATASTR_LEN;
383 * Use the retrieved length of dname to allocate an output
384 * buffer, and then define the output variable (but only
385 * for char/string type columns).
389 case SQLT_AFC: /* ansii fixed char */
392 case SQLT_AFV: /* ansii var char */
394 case SQLT_VCS: /* var char */
395 case SQLT_CHR: /* char */
396 case SQLT_STR: /* string */
397 x=OCIAttrGet((dvoid*)param, (ub4) OCI_DTYPE_PARAM,
398 (dvoid*) &dsize, (ub4 *)0, (ub4) OCI_ATTR_DATA_SIZE,
399 oracle_sock->errHandle);
400 if (x != OCI_SUCCESS) {
401 radlog(L_ERR,"rlm_sql_oracle: OCIAttrGet() failed in sql_select_query: %s",
402 sql_error(sqlsocket, config));
405 rowdata[y-1]=rad_malloc(dsize+1);
414 rowdata[y-1]=rad_malloc(dsize+1);
423 x=OCIDefineByPos(oracle_sock->queryHandle,
425 oracle_sock->errHandle,
427 (ub1 *) rowdata[y-1],
436 * FIXME: memory leaks of indicators & rowdata?
438 if (x != OCI_SUCCESS) {
439 radlog(L_ERR,"rlm_sql_oracle: OCIDefineByPos() failed in sql_select_query: %s",
440 sql_error(sqlsocket, config));
445 oracle_sock->results=rowdata;
446 oracle_sock->indicators=indicators;
452 /*************************************************************************
454 * Function: sql_store_result
456 * Purpose: database specific store_result function. Returns a result
459 *************************************************************************/
460 static int sql_store_result(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
461 /* Not needed for Oracle */
466 /*************************************************************************
468 * Function: sql_num_rows
470 * Purpose: database specific num_rows. Returns number of rows in
473 *************************************************************************/
474 static int sql_num_rows(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
477 rlm_sql_oracle_sock *oracle_sock = sqlsocket->conn;
479 OCIAttrGet((CONST dvoid *)oracle_sock->queryHandle,
484 oracle_sock->errHandle);
490 /*************************************************************************
492 * Function: sql_fetch_row
494 * Purpose: database specific fetch_row. Returns a SQL_ROW struct
495 * with all the data for the query in 'sqlsocket->row'. Returns
496 * 0 on success, -1 on failure, SQL_DOWN if database is down.
498 *************************************************************************/
499 static int sql_fetch_row(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
502 rlm_sql_oracle_sock *oracle_sock = sqlsocket->conn;
504 if (oracle_sock->conn == NULL) {
505 radlog(L_ERR, "rlm_sql_oracle: Socket not connected");
509 sqlsocket->row = NULL;
511 x=OCIStmtFetch(oracle_sock->queryHandle,
512 oracle_sock->errHandle,
517 if (x == OCI_SUCCESS) {
518 sqlsocket->row = oracle_sock->results;
522 if (x == OCI_ERROR) {
523 radlog(L_ERR,"rlm_sql_oracle: fetch failed in sql_fetch_row: %s",
524 sql_error(sqlsocket, config));
525 return sql_check_error(sqlsocket, config);
534 /*************************************************************************
536 * Function: sql_free_result
538 * Purpose: database specific free_result. Frees memory allocated
541 *************************************************************************/
542 static int sql_free_result(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
547 rlm_sql_oracle_sock *oracle_sock = sqlsocket->conn;
549 /* Cancel the cursor first */
550 x=OCIStmtFetch(oracle_sock->queryHandle,
551 oracle_sock->errHandle,
556 num_fields = sql_num_fields(sqlsocket, config);
557 if (num_fields >= 0) {
558 for(x=0; x < num_fields; x++) {
559 free(oracle_sock->results[x]);
561 free(oracle_sock->results);
562 free(oracle_sock->indicators);
564 oracle_sock->results=NULL;
570 /*************************************************************************
572 * Function: sql_finish_query
574 * Purpose: End the query, such as freeing memory
576 *************************************************************************/
577 static int sql_finish_query(SQLSOCK *sqlsocket, SQL_CONFIG *config)
584 /*************************************************************************
586 * Function: sql_finish_select_query
588 * Purpose: End the select query, such as freeing memory or result
590 *************************************************************************/
591 static int sql_finish_select_query(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
594 rlm_sql_oracle_sock *oracle_sock = sqlsocket->conn;
596 if (oracle_sock->results) {
597 while(oracle_sock->results[x]) free(oracle_sock->results[x++]);
598 free(oracle_sock->results);
599 free(oracle_sock->indicators);
600 oracle_sock->results=NULL;
607 /*************************************************************************
609 * Function: sql_affected_rows
611 * Purpose: Return the number of rows affected by the query (update,
614 *************************************************************************/
615 static int sql_affected_rows(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
617 return sql_num_rows(sqlsocket, config);
621 /* Exported to rlm_sql */
622 rlm_sql_module_t rlm_sql_oracle = {
636 sql_finish_select_query,