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(rlm_sql_handle_t *handle, rlm_sql_config_t *config) {
57 static char msgbuf[512];
59 rlm_sql_oracle_sock *oracle_sock = handle->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(rlm_sql_handle_t *handle, rlm_sql_config_t *config) {
84 if (strstr(sql_error(handle, config), "ORA-03113") ||
85 strstr(sql_error(handle, 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(rlm_sql_handle_t *handle, rlm_sql_config_t *config) {
105 rlm_sql_oracle_sock *oracle_sock = handle->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;
129 /*************************************************************************
131 * Function: sql_init_socket
133 * Purpose: Establish connection to the db
135 *************************************************************************/
136 static int sql_init_socket(rlm_sql_handle_t *handle, rlm_sql_config_t *config) {
138 rlm_sql_oracle_sock *oracle_sock;
141 handle->conn = (rlm_sql_oracle_sock *)rad_malloc(sizeof(rlm_sql_oracle_sock));
146 memset(handle->conn,0,sizeof(rlm_sql_oracle_sock));
148 oracle_sock = handle->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(handle, 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(handle, config));
182 sql_close(handle,config);
190 /*************************************************************************
192 * Function: sql_destroy_socket
194 * Purpose: Free socket and private connection data
196 *************************************************************************/
197 static int sql_destroy_socket(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
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(rlm_sql_handle_t *handle, rlm_sql_config_t *config) {
215 rlm_sql_oracle_sock *oracle_sock = handle->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(handle, config));
231 /*************************************************************************
233 * Function: sql_query
235 * Purpose: Issue a non-SELECT query (ie: update/delete/insert) to
238 *************************************************************************/
239 static int sql_query(rlm_sql_handle_t *handle, rlm_sql_config_t *config, char *querystr) {
242 rlm_sql_oracle_sock *oracle_sock = handle->conn;
244 if (oracle_sock->conn == NULL) {
245 radlog(L_ERR, "rlm_sql_oracle: Socket not connected");
249 if (OCIStmtPrepare (oracle_sock->queryHandle, oracle_sock->errHandle,
250 querystr, strlen(querystr),
251 OCI_NTV_SYNTAX, OCI_DEFAULT)) {
252 radlog(L_ERR,"rlm_sql_oracle: prepare failed in sql_query: %s",sql_error(handle, config));
256 x = OCIStmtExecute(oracle_sock->conn,
257 oracle_sock->queryHandle,
258 oracle_sock->errHandle,
261 (OCISnapshot *) NULL,
262 (OCISnapshot *) NULL,
263 (ub4) OCI_COMMIT_ON_SUCCESS);
265 if (x == OCI_SUCCESS) {
269 if (x == OCI_ERROR) {
270 radlog(L_ERR,"rlm_sql_oracle: execute query failed in sql_query: %s",
271 sql_error(handle, config));
272 return sql_check_error(handle, config);
280 /*************************************************************************
282 * Function: sql_select_query
284 * Purpose: Issue a select query to the database
286 *************************************************************************/
287 static int sql_select_query(rlm_sql_handle_t *handle, rlm_sql_config_t *config, char *querystr) {
298 rlm_sql_oracle_sock *oracle_sock = handle->conn;
300 if (oracle_sock->conn == NULL) {
301 radlog(L_ERR, "rlm_sql_oracle: Socket not connected");
305 if (OCIStmtPrepare (oracle_sock->queryHandle, oracle_sock->errHandle,
306 querystr, strlen(querystr),
307 OCI_NTV_SYNTAX, OCI_DEFAULT)) {
308 radlog(L_ERR,"rlm_sql_oracle: prepare failed in sql_select_query: %s",sql_error(handle, config));
312 /* Query only one row by default (for now) */
313 x = OCIStmtExecute(oracle_sock->conn,
314 oracle_sock->queryHandle,
315 oracle_sock->errHandle,
318 (OCISnapshot *) NULL,
319 (OCISnapshot *) NULL,
322 if (x == OCI_NO_DATA) {
323 /* Nothing to fetch */
327 if (x != OCI_SUCCESS) {
328 radlog(L_ERR,"rlm_sql_oracle: query failed in sql_select_query: %s",
329 sql_error(handle, config));
330 return sql_check_error(handle, config);
334 * Define where the output from fetch calls will go
336 * This is a gross hack, but it works - we convert
337 * all data to strings for ease of use. Fortunately, most
338 * of the data we deal with is already in string format.
340 colcount = sql_num_fields(handle, config);
342 /* DEBUG2("sql_select_query(): colcount=%d",colcount); */
345 * FIXME: These malloc's can probably go, as the schema
348 rowdata=(char **)rad_malloc(sizeof(char *) * (colcount+1) );
349 memset(rowdata, 0, (sizeof(char *) * (colcount+1) ));
350 indicators = (sb2 *) rad_malloc(sizeof(sb2) * (colcount+1) );
351 memset(indicators, 0, sizeof(sb2) * (colcount+1));
353 for (y=1; y <= colcount; y++) {
354 x=OCIParamGet(oracle_sock->queryHandle, OCI_HTYPE_STMT,
355 oracle_sock->errHandle,
358 if (x != OCI_SUCCESS) {
359 radlog(L_ERR,"rlm_sql_oracle: OCIParamGet() failed in sql_select_query: %s",
360 sql_error(handle, config));
364 x=OCIAttrGet((dvoid*)param, OCI_DTYPE_PARAM,
365 (dvoid*)&dtype, (ub4*)0, OCI_ATTR_DATA_TYPE,
366 oracle_sock->errHandle);
367 if (x != OCI_SUCCESS) {
368 radlog(L_ERR,"rlm_sql_oracle: OCIAttrGet() failed in sql_select_query: %s",
369 sql_error(handle, config));
373 dsize=MAX_DATASTR_LEN;
376 * Use the retrieved length of dname to allocate an output
377 * buffer, and then define the output variable (but only
378 * for char/string type columns).
382 case SQLT_AFC: /* ansii fixed char */
385 case SQLT_AFV: /* ansii var char */
387 case SQLT_VCS: /* var char */
388 case SQLT_CHR: /* char */
389 case SQLT_STR: /* string */
390 x=OCIAttrGet((dvoid*)param, (ub4) OCI_DTYPE_PARAM,
391 (dvoid*) &dsize, (ub4 *)0, (ub4) OCI_ATTR_DATA_SIZE,
392 oracle_sock->errHandle);
393 if (x != OCI_SUCCESS) {
394 radlog(L_ERR,"rlm_sql_oracle: OCIAttrGet() failed in sql_select_query: %s",
395 sql_error(handle, config));
398 rowdata[y-1]=rad_malloc(dsize+1);
399 memset(rowdata[y-1], 0, dsize+1);
408 rowdata[y-1]=rad_malloc(dsize+1);
409 memset(rowdata[y-1], 0, dsize+1);
418 x=OCIDefineByPos(oracle_sock->queryHandle,
420 oracle_sock->errHandle,
422 (ub1 *) rowdata[y-1],
430 if (x != OCI_SUCCESS) {
431 radlog(L_ERR,"rlm_sql_oracle: OCIDefineByPos() failed in sql_select_query: %s",
432 sql_error(handle, config));
437 oracle_sock->results=rowdata;
438 oracle_sock->indicators=indicators;
443 for (y=0; y < colcount; y++) {
454 /*************************************************************************
456 * Function: sql_store_result
458 * Purpose: database specific store_result function. Returns a result
461 *************************************************************************/
462 static int sql_store_result(rlm_sql_handle_t *handle, rlm_sql_config_t *config) {
463 /* Not needed for Oracle */
468 /*************************************************************************
470 * Function: sql_num_rows
472 * Purpose: database specific num_rows. Returns number of rows in
475 *************************************************************************/
476 static int sql_num_rows(rlm_sql_handle_t *handle, rlm_sql_config_t *config) {
479 rlm_sql_oracle_sock *oracle_sock = handle->conn;
481 OCIAttrGet((CONST dvoid *)oracle_sock->queryHandle,
486 oracle_sock->errHandle);
492 /*************************************************************************
494 * Function: sql_fetch_row
496 * Purpose: database specific fetch_row. Returns a rlm_sql_row_t struct
497 * with all the data for the query in 'handle->row'. Returns
498 * 0 on success, -1 on failure, SQL_DOWN if database is down.
500 *************************************************************************/
501 static int sql_fetch_row(rlm_sql_handle_t *handle, rlm_sql_config_t *config) {
504 rlm_sql_oracle_sock *oracle_sock = handle->conn;
506 if (oracle_sock->conn == NULL) {
507 radlog(L_ERR, "rlm_sql_oracle: Socket not connected");
513 x=OCIStmtFetch(oracle_sock->queryHandle,
514 oracle_sock->errHandle,
519 if (x == OCI_SUCCESS) {
520 handle->row = oracle_sock->results;
524 if (x == OCI_ERROR) {
525 radlog(L_ERR,"rlm_sql_oracle: fetch failed in sql_fetch_row: %s",
526 sql_error(handle, config));
527 return sql_check_error(handle, config);
536 /*************************************************************************
538 * Function: sql_free_result
540 * Purpose: database specific free_result. Frees memory allocated
543 *************************************************************************/
544 static int sql_free_result(rlm_sql_handle_t *handle, rlm_sql_config_t *config) {
549 rlm_sql_oracle_sock *oracle_sock = handle->conn;
551 /* Cancel the cursor first */
552 x=OCIStmtFetch(oracle_sock->queryHandle,
553 oracle_sock->errHandle,
558 num_fields = sql_num_fields(handle, config);
559 if (num_fields >= 0) {
560 for(x=0; x < num_fields; x++) {
561 free(oracle_sock->results[x]);
563 free(oracle_sock->results);
564 free(oracle_sock->indicators);
566 oracle_sock->results=NULL;
572 /*************************************************************************
574 * Function: sql_finish_query
576 * Purpose: End the query, such as freeing memory
578 *************************************************************************/
579 static int sql_finish_query(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
586 /*************************************************************************
588 * Function: sql_finish_select_query
590 * Purpose: End the select query, such as freeing memory or result
592 *************************************************************************/
593 static int sql_finish_select_query(rlm_sql_handle_t *handle, rlm_sql_config_t *config) {
596 rlm_sql_oracle_sock *oracle_sock = handle->conn;
598 if (oracle_sock->results) {
599 while(oracle_sock->results[x]) free(oracle_sock->results[x++]);
600 free(oracle_sock->results);
601 free(oracle_sock->indicators);
602 oracle_sock->results=NULL;
609 /*************************************************************************
611 * Function: sql_affected_rows
613 * Purpose: Return the number of rows affected by the query (update,
616 *************************************************************************/
617 static int sql_affected_rows(rlm_sql_handle_t *handle, rlm_sql_config_t *config) {
619 return sql_num_rows(handle, config);
623 /* Exported to rlm_sql */
624 rlm_sql_module_t rlm_sql_oracle = {
638 sql_finish_select_query,