On Thu, Nov 11, 2004 at 02:23:36PM +0300, Alexander Serkin wrote: > OK here is the patched file. You can verify it if you diff it with the original file.
Kostas > > Kostas Zorbadelos wrote: > ... > > > >I resubmit the patch as a text file (output of > >diff sql_oracle.c.before_patch sql_oracle.c > freeradius_oracle_patch) > >because from the web page I had > >problems applying it and I was forced to apply it partly by hand > >editing of the code... > > > > the same problem. I cannot apply patch taken from the web: > > patching file src/modules/rlm_sql/drivers/rlm_sql_oracle/sql_oracle.c > patch: **** malformed patch at line 60: @@ -311,9 +328,11 @@ > > > -- > Sincerely Yours, > Alexander Serkin, > Skylink, Moscow > > - > List info/subscribe/unsubscribe? See > http://www.freeradius.org/list/users.html > -- Kostas Zorbadelos Systems Developer, Otenet SA mailto: [EMAIL PROTECTED] Out there in the darkness, out there in the night out there in the starlight, one soul burns brighter than a thousand suns.
/* * sql_oracle.c Oracle (OCI) routines for rlm_sql * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Copyright 2000 The FreeRADIUS server project * Copyright 2000 David Kerry <[EMAIL PROTECTED]> */ #include <stdio.h> #include <sys/stat.h> #include <sys/time.h> #include <stdlib.h> #include <string.h> #include "radiusd.h" #include <oci.h> #include "rlm_sql.h" typedef struct rlm_sql_oracle_sock { OCIEnv *env; OCIError *errHandle; OCISvcCtx *conn; OCIStmt *queryHandle; sb2 *indicators; char **results; int id; int in_use; struct timeval tv; } rlm_sql_oracle_sock; #define MAX_DATASTR_LEN 64 /************************************************************************* * * Function: sql_error * * Purpose: database specific error. Returns error associated with * connection * *************************************************************************/ static char *sql_error(SQLSOCK *sqlsocket, SQL_CONFIG *config) { static char msgbuf[512]; sb4 errcode = 0; rlm_sql_oracle_sock *oracle_sock = sqlsocket->conn; if (!oracle_sock) return "rlm_sql_oracle: no connection to db"; memset((void *) msgbuf, (int)'\0', sizeof(msgbuf)); OCIErrorGet((dvoid *) oracle_sock->errHandle, (ub4) 1, (text *) NULL, &errcode, msgbuf, (ub4) sizeof(msgbuf), (ub4) OCI_HTYPE_ERROR); if (errcode) { return msgbuf; } else { return NULL; } } /************************************************************************* * * Function: sql_check_error * * Purpose: check the error to see if the server is down * *************************************************************************/ static int sql_check_error(SQLSOCK *sqlsocket, SQL_CONFIG *config) { if (strstr(sql_error(sqlsocket, config), "ORA-03113") || strstr(sql_error(sqlsocket, config), "ORA-03114")) { radlog(L_ERR,"rlm_sql_oracle: OCI_SERVER_NOT_CONNECTED"); return SQL_DOWN; } else { radlog(L_ERR,"rlm_sql_oracle: OCI_SERVER_NORMAL"); return -1; } } /************************************************************************* * * Function: sql_close * * Purpose: database specific close. Closes an open database * connection and cleans up any open handles. * *************************************************************************/ static int sql_close(SQLSOCK *sqlsocket, SQL_CONFIG *config) { rlm_sql_oracle_sock *oracle_sock = sqlsocket->conn; if (oracle_sock->conn) { OCILogoff (oracle_sock->conn, oracle_sock->errHandle); } if (oracle_sock->queryHandle) { OCIHandleFree((dvoid *)oracle_sock->queryHandle, (ub4) OCI_HTYPE_STMT); } if (oracle_sock->errHandle) { OCIHandleFree((dvoid *)oracle_sock->errHandle, (ub4) OCI_HTYPE_ERROR); } if (oracle_sock->env) { OCIHandleFree((dvoid *)oracle_sock->env, (ub4) OCI_HTYPE_ENV); } oracle_sock->conn = NULL; free(oracle_sock); sqlsocket->conn = NULL; return 0; } /************************************************************************* * * Function: sql_init_socket * * Purpose: Establish connection to the db * *************************************************************************/ static int sql_init_socket(SQLSOCK *sqlsocket, SQL_CONFIG *config) { rlm_sql_oracle_sock *oracle_sock; if (!sqlsocket->conn) { sqlsocket->conn = (rlm_sql_oracle_sock *)rad_malloc(sizeof(rlm_sql_oracle_sock)); if (!sqlsocket->conn) { return -1; } } memset(sqlsocket->conn,0,sizeof(rlm_sql_oracle_sock)); oracle_sock = sqlsocket->conn; if (OCIEnvCreate(&oracle_sock->env, OCI_DEFAULT|OCI_THREADED, (dvoid *)0, (dvoid * (*)(dvoid *, size_t)) 0, (dvoid * (*)(dvoid *, dvoid *, size_t))0, (void (*)(dvoid *, dvoid *)) 0, 0, (dvoid **)0 )) { radlog(L_ERR,"rlm_sql_oracle: Couldn't init Oracle OCI environment (OCIEnvCreate())"); return -1; } if (OCIHandleAlloc((dvoid *) oracle_sock->env, (dvoid **) &oracle_sock->errHandle, (ub4) OCI_HTYPE_ERROR, (size_t) 0, (dvoid **) 0)) { radlog(L_ERR,"rlm_sql_oracle: Couldn't init Oracle ERROR handle (OCIHandleAlloc())"); return -1; } /* Allocate handles for select and update queries */ if (OCIHandleAlloc((dvoid *)oracle_sock->env, (dvoid **) &oracle_sock->queryHandle, (ub4)OCI_HTYPE_STMT, (CONST size_t) 0, (dvoid **) 0)) { radlog(L_ERR,"rlm_sql_oracle: Couldn't init Oracle query handles: %s", sql_error(sqlsocket, config)); return -1; } if (OCILogon(oracle_sock->env, oracle_sock->errHandle, &oracle_sock->conn, config->sql_login, strlen(config->sql_login), config->sql_password, strlen(config->sql_password), config->sql_db, strlen(config->sql_db))) { radlog(L_ERR,"rlm_sql_oracle: Oracle logon failed: '%s'", sql_error(sqlsocket, config)); sql_close(sqlsocket,config); return -1; } return 0; } /************************************************************************* * * Function: sql_destroy_socket * * Purpose: Free socket and private connection data * *************************************************************************/ static int sql_destroy_socket(SQLSOCK *sqlsocket, SQL_CONFIG *config) { free(sqlsocket->conn); sqlsocket->conn = NULL; return 0; } /************************************************************************* * * Function: sql_num_fields * * Purpose: database specific num_fields function. Returns number * of columns from query * *************************************************************************/ static int sql_num_fields(SQLSOCK *sqlsocket, SQL_CONFIG *config) { ub4 count; rlm_sql_oracle_sock *oracle_sock = sqlsocket->conn; /* get the number of columns in the select list */ if (OCIAttrGet ((dvoid *)oracle_sock->queryHandle, (ub4)OCI_HTYPE_STMT, (dvoid *) &count, (ub4 *) 0, (ub4)OCI_ATTR_PARAM_COUNT, oracle_sock->errHandle)) { radlog(L_ERR,"rlm_sql_oracle: Error retrieving column count in sql_num_fields: %s", sql_error(sqlsocket, config)); return -1; } return count; } /************************************************************************* * * Function: sql_query * * Purpose: Issue a non-SELECT query (ie: update/delete/insert) to * the database. * *************************************************************************/ static int sql_query(SQLSOCK *sqlsocket, SQL_CONFIG *config, char *querystr) { int x; rlm_sql_oracle_sock *oracle_sock = sqlsocket->conn; if (config->sqltrace) DEBUG(querystr); if (oracle_sock->conn == NULL) { radlog(L_ERR, "rlm_sql_oracle: Socket not connected"); return SQL_DOWN; } if (OCIStmtPrepare (oracle_sock->queryHandle, oracle_sock->errHandle, querystr, strlen(querystr), OCI_NTV_SYNTAX, OCI_DEFAULT)) { radlog(L_ERR,"rlm_sql_oracle: prepare failed in sql_query: %s",sql_error(sqlsocket, config)); return -1; } x = OCIStmtExecute(oracle_sock->conn, oracle_sock->queryHandle, oracle_sock->errHandle, (ub4) 1, (ub4) 0, (OCISnapshot *) NULL, (OCISnapshot *) NULL, (ub4) OCI_COMMIT_ON_SUCCESS); if (x == OCI_SUCCESS) { return 0; } if (x == OCI_ERROR) { radlog(L_ERR,"rlm_sql_oracle: execute query failed in sql_query: %s", sql_error(sqlsocket, config)); return sql_check_error(sqlsocket, config); } else { return -1; } } /************************************************************************* * * Function: sql_select_query * * Purpose: Issue a select query to the database * *************************************************************************/ static int sql_select_query(SQLSOCK *sqlsocket, SQL_CONFIG *config, char *querystr) { int x; int y; int colcount; OCIParam *param; OCIDefine *define; ub2 dtype; ub2 dsize; char **rowdata=NULL; sb2 *indicators; rlm_sql_oracle_sock *oracle_sock = sqlsocket->conn; if (config->sqltrace) DEBUG(querystr); if (oracle_sock->conn == NULL) { radlog(L_ERR, "rlm_sql_oracle: Socket not connected"); return SQL_DOWN; } if (OCIStmtPrepare (oracle_sock->queryHandle, oracle_sock->errHandle, querystr, strlen(querystr), OCI_NTV_SYNTAX, OCI_DEFAULT)) { radlog(L_ERR,"rlm_sql_oracle: prepare failed in sql_select_query: %s",sql_error(sqlsocket, config)); return -1; } /* Query only one row by default (for now) */ x = OCIStmtExecute(oracle_sock->conn, oracle_sock->queryHandle, oracle_sock->errHandle, (ub4) 0, (ub4) 0, (OCISnapshot *) NULL, (OCISnapshot *) NULL, (ub4) OCI_DEFAULT); if (x == OCI_NO_DATA) { /* Nothing to fetch */ return 0; } if (x != OCI_SUCCESS) { radlog(L_ERR,"rlm_sql_oracle: query failed in sql_select_query: %s", sql_error(sqlsocket, config)); return sql_check_error(sqlsocket, config); } /* * 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(sqlsocket, config); /* DEBUG2("sql_select_query(): colcount=%d",colcount); */ /* * FIXME: These malloc's can probably go, as the schema * is fixed... */ rowdata=(char **)rad_malloc(sizeof(char *) * (colcount+1) ); memset(rowdata, 0, (sizeof(char *) * (colcount+1) )); indicators = (sb2 *) rad_malloc(sizeof(sb2) * (colcount+1) ); memset(indicators, 0, sizeof(sb2) * (colcount+1)); for (y=1; y <= colcount; y++) { x=OCIParamGet(oracle_sock->queryHandle, OCI_HTYPE_STMT, oracle_sock->errHandle, (dvoid **)¶m, (ub4) y); if (x != OCI_SUCCESS) { radlog(L_ERR,"rlm_sql_oracle: OCIParamGet() failed in sql_select_query: %s", sql_error(sqlsocket, config)); return -1; } x=OCIAttrGet((dvoid*)param, OCI_DTYPE_PARAM, (dvoid*)&dtype, (ub4*)0, OCI_ATTR_DATA_TYPE, oracle_sock->errHandle); if (x != OCI_SUCCESS) { radlog(L_ERR,"rlm_sql_oracle: OCIAttrGet() failed in sql_select_query: %s", sql_error(sqlsocket, config)); 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) { #ifdef SQLT_AFC case SQLT_AFC: /* ansii fixed char */ #endif #ifdef SQLT_AFV case SQLT_AFV: /* ansii var char */ #endif case SQLT_VCS: /* var char */ case SQLT_CHR: /* char */ case SQLT_STR: /* string */ x=OCIAttrGet((dvoid*)param, (ub4) OCI_DTYPE_PARAM, (dvoid*) &dsize, (ub4 *)0, (ub4) OCI_ATTR_DATA_SIZE, oracle_sock->errHandle); if (x != OCI_SUCCESS) { radlog(L_ERR,"rlm_sql_oracle: OCIAttrGet() failed in sql_select_query: %s", sql_error(sqlsocket, config)); return -1; } rowdata[y-1]=rad_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]=rad_malloc(dsize+1); break; default: dsize=0; rowdata[y-1]=NULL; break; } indicators[y-1] = 0; x=OCIDefineByPos(oracle_sock->queryHandle, &define, oracle_sock->errHandle, y, (ub1 *) rowdata[y-1], dsize+1, SQLT_STR, &indicators[y-1], (dvoid *) 0, (dvoid *) 0, OCI_DEFAULT); /* * FIXME: memory leaks of indicators & rowdata? */ if (x != OCI_SUCCESS) { radlog(L_ERR,"rlm_sql_oracle: OCIDefineByPos() failed in sql_select_query: %s", sql_error(sqlsocket, config)); return -1; } } oracle_sock->results=rowdata; oracle_sock->indicators=indicators; return 0; } /************************************************************************* * * Function: sql_store_result * * Purpose: database specific store_result function. Returns a result * set for the query. * *************************************************************************/ static int sql_store_result(SQLSOCK *sqlsocket, SQL_CONFIG *config) { /* Not needed for Oracle */ return 0; } /************************************************************************* * * Function: sql_num_rows * * Purpose: database specific num_rows. Returns number of rows in * query * *************************************************************************/ static int sql_num_rows(SQLSOCK *sqlsocket, SQL_CONFIG *config) { ub4 rows=0; rlm_sql_oracle_sock *oracle_sock = sqlsocket->conn; OCIAttrGet((CONST dvoid *)oracle_sock->queryHandle, OCI_HTYPE_STMT, (dvoid *)&rows, (ub4 *) sizeof(ub4), OCI_ATTR_ROW_COUNT, oracle_sock->errHandle); return rows; } /************************************************************************* * * Function: sql_fetch_row * * Purpose: database specific fetch_row. Returns a SQL_ROW struct * with all the data for the query in 'sqlsocket->row'. Returns * 0 on success, -1 on failure, SQL_DOWN if database is down. * *************************************************************************/ static int sql_fetch_row(SQLSOCK *sqlsocket, SQL_CONFIG *config) { int x; rlm_sql_oracle_sock *oracle_sock = sqlsocket->conn; if (oracle_sock->conn == NULL) { radlog(L_ERR, "rlm_sql_oracle: Socket not connected"); return SQL_DOWN; } sqlsocket->row = NULL; x=OCIStmtFetch(oracle_sock->queryHandle, oracle_sock->errHandle, 1, OCI_FETCH_NEXT, OCI_DEFAULT); if (x == OCI_SUCCESS) { sqlsocket->row = oracle_sock->results; return 0; } if (x == OCI_ERROR) { radlog(L_ERR,"rlm_sql_oracle: fetch failed in sql_fetch_row: %s", sql_error(sqlsocket, config)); return sql_check_error(sqlsocket, config); } else { return -1; } } /************************************************************************* * * Function: sql_free_result * * Purpose: database specific free_result. Frees memory allocated * for a result set * *************************************************************************/ static int sql_free_result(SQLSOCK *sqlsocket, SQL_CONFIG *config) { int x; int num_fields; rlm_sql_oracle_sock *oracle_sock = sqlsocket->conn; /* Cancel the cursor first */ x=OCIStmtFetch(oracle_sock->queryHandle, oracle_sock->errHandle, 0, OCI_FETCH_NEXT, OCI_DEFAULT); num_fields = sql_num_fields(sqlsocket, config); if (num_fields >= 0) { for(x=0; x < num_fields; x++) { free(oracle_sock->results[x]); } free(oracle_sock->results); free(oracle_sock->indicators); } oracle_sock->results=NULL; return 0; } /************************************************************************* * * Function: sql_finish_query * * Purpose: End the query, such as freeing memory * *************************************************************************/ static int sql_finish_query(SQLSOCK *sqlsocket, SQL_CONFIG *config) { return 0; } /************************************************************************* * * Function: sql_finish_select_query * * Purpose: End the select query, such as freeing memory or result * *************************************************************************/ static int sql_finish_select_query(SQLSOCK *sqlsocket, SQL_CONFIG *config) { int x=0; rlm_sql_oracle_sock *oracle_sock = sqlsocket->conn; if (oracle_sock->results) { while(oracle_sock->results[x]) free(oracle_sock->results[x++]); free(oracle_sock->results); free(oracle_sock->indicators); oracle_sock->results=NULL; } return 0; } /************************************************************************* * * Function: sql_affected_rows * * Purpose: Return the number of rows affected by the query (update, * or insert) * *************************************************************************/ static int sql_affected_rows(SQLSOCK *sqlsocket, SQL_CONFIG *config) { return sql_num_rows(sqlsocket, config); } /* Exported to rlm_sql */ rlm_sql_module_t rlm_sql_oracle = { "rlm_sql_oracle", sql_init_socket, sql_destroy_socket, sql_query, sql_select_query, sql_store_result, sql_num_fields, sql_num_rows, sql_fetch_row, sql_free_result, sql_error, sql_close, sql_finish_query, sql_finish_select_query, sql_affected_rows };