--- sql_oracle.c Thu Aug 27 18:46:35 2009 +++ sql_oracle.c.new Thu Aug 27 18:38:47 2009 @@ -29,6 +29,25 @@ #include <oci.h> #include "rlm_sql.h" +#define MAXBIND 40 +/* + * SQL WITH BIND : <SQL>\P<BIND1>\P<BIND2>.....\P<BINDn> + * BIND1 : <NAME>=<VALUE> ; the <NAME> is optional, if none, bindbyindex + * + */ +typedef struct rlm_sql_oraclesockbind { + char * ptr ; + int idx ; + char * name ; + int namelen ; + char * value ; + int vallen; + + OCIBind *bindp ; +} rlm_sql_oraclesockbind; + + + typedef struct rlm_sql_oracle_sock { OCIEnv *env; OCIError *errHandle; @@ -39,10 +58,108 @@ int id; int in_use; struct timeval tv; + + rlm_sql_oraclesockbind binds[MAXBIND]; + int bindcount; } rlm_sql_oracle_sock; #define MAX_DATASTR_LEN 64 +/************************************************************************* + * + * Function: sql_bindparse + * + * Purpose: split the sql statement for pure sql , each bind item , etc . + * + * + *************************************************************************/ + +static int sql_bindparse(SQLSOCK *sqlsocket, char * query) +{ + char * p = query ; + int count = 0 , i , k; + rlm_sql_oracle_sock *oracle_sock = sqlsocket->conn ; + oracle_sock->bindcount = 0 ; + + while ( *p ) { + switch ( *p ) { + case '\\' : + if (p[1]!='P') { + break; + } + *p = '\0'; + oracle_sock->binds[count].ptr = p+2; + count ++ ; + p ++ ; + break; + //default + } /* end of switch(*p) */ + p ++ ; + if (count>=MAXBIND) + break; + } + + for(i = 0, k = 0 ; k<count; k ++){ + if (oracle_sock->binds[k].ptr==NULL) + continue; + if (oracle_sock->binds[k].ptr[0]=='\0') + continue; + if ((p = strchr(oracle_sock->binds[k].ptr, '='))==NULL) + continue; + *p = '\0'; + oracle_sock->binds[i].value = p+1; + oracle_sock->binds[i].vallen = strlen (oracle_sock->binds[i].value); + if (p==oracle_sock->binds[k].ptr){ + oracle_sock->binds[i].name = NULL; + } else { + oracle_sock->binds[i].name = oracle_sock->binds[k].ptr; + oracle_sock->binds[i].namelen = p - oracle_sock->binds[k].ptr; + } + oracle_sock->binds[i].idx = i+1 ; + radlog(L_DBG, "bind[%d] v_p is<%s>(%d)-<%s>(%d)", i, + oracle_sock->binds[i].name,oracle_sock->binds[i].namelen, + oracle_sock->binds[i].value,oracle_sock->binds[i].vallen ); + i ++ ; continue; + } + + oracle_sock->bindcount = i ; + + return 0 ; +} + + +static int sql_ocibind(SQLSOCK *sqlsocket) +{ + int i ; + rlm_sql_oracle_sock *oracle_sock = sqlsocket->conn ; + for(i = 0;i<oracle_sock->bindcount; i++){ + if (oracle_sock->binds[i].name!=NULL){ + OCIBindByName( + oracle_sock->queryHandle, + &oracle_sock->binds[i].bindp, + oracle_sock->errHandle, + oracle_sock->binds[i].name, + oracle_sock->binds[i].namelen, + (ub1 *) oracle_sock->binds[i].value, + oracle_sock->binds[i].vallen+1, + SQLT_STR, (dvoid *) 0, (ub2 *) 0, (ub2) 0, (ub4) 0, (ub4 *) 0, + OCI_DEFAULT); + } else { + OCIBindByPos( + oracle_sock->queryHandle, + &oracle_sock->binds[i].bindp, + oracle_sock->errHandle, + oracle_sock->binds[i].idx, + (ub1 *) oracle_sock->binds[i].value, + oracle_sock->binds[i].vallen+1, + SQLT_STR, (dvoid *) 0, (ub2 *) 0, (ub2) 0, (ub4) 0, (ub4 *) 0, + OCI_DEFAULT); + } + } + + return 0; +} + /************************************************************************* * @@ -248,6 +365,8 @@ return SQL_DOWN; } + sql_bindparse(sqlsocket, querystr); + if (OCIStmtPrepare (oracle_sock->queryHandle, oracle_sock->errHandle, querystr, strlen(querystr), OCI_NTV_SYNTAX, OCI_DEFAULT)) { @@ -255,6 +374,9 @@ return -1; } + if (oracle_sock->bindcount>0) + sql_ocibind(sqlsocket); + x = OCIStmtExecute(oracle_sock->conn, oracle_sock->queryHandle, oracle_sock->errHandle, @@ -306,12 +428,17 @@ return SQL_DOWN; } + sql_bindparse(sqlsocket, querystr); + 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; } + + if (oracle_sock->bindcount>0) + sql_ocibind(sqlsocket); /* Query only one row by default (for now) */ x = OCIStmtExecute(oracle_sock->conn,