/************************************************************************* * * Function: sql_init_socket * * Purpose: Establish connection to the db * *************************************************************************/ static int sql_init_socket(rlm_sql_handle_t *handle, rlm_sql_config_t *config) { rlm_sql_unixodbc_sock *unixodbc_sock; long err_handle; if (!handle->conn) { handle->conn = (rlm_sql_unixodbc_sock *)rad_malloc(sizeof(rlm_sql_unixodbc_sock)); if (!handle->conn) { return -1; } } unixodbc_sock = handle->conn; memset(unixodbc_sock, 0, sizeof(*unixodbc_sock)); /* 1. Allocate environment handle and register version */ err_handle = SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HANDLE,&unixodbc_sock->env_handle); if (sql_state(err_handle, handle, config)) { radlog(L_ERR, "rlm_sql_unixodbc: Can't allocate environment handle\n"); return -1; } err_handle = SQLSetEnvAttr(unixodbc_sock->env_handle, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0); if (sql_state(err_handle, handle, config)) { radlog(L_ERR, "rlm_sql_unixodbc: Can't register ODBC version\n"); SQLFreeHandle(SQL_HANDLE_ENV, unixodbc_sock->env_handle); return -1; } /* 2. Allocate connection handle */ err_handle = SQLAllocHandle(SQL_HANDLE_DBC, unixodbc_sock->env_handle, &unixodbc_sock->dbc_handle); if (sql_state(err_handle, handle, config)) { radlog(L_ERR, "rlm_sql_unixodbc: Can't allocate connection handle\n"); SQLFreeHandle(SQL_HANDLE_ENV, unixodbc_sock->env_handle); return -1; } /* 3. Connect to the datasource */ err_handle = SQLConnect(unixodbc_sock->dbc_handle, (SQLCHAR*) config->sql_server, strlen(config->sql_server), (SQLCHAR*) config->sql_login, strlen(config->sql_login), (SQLCHAR*) config->sql_password, strlen(config->sql_password)); if (sql_state(err_handle, handle, config)) { radlog(L_ERR, "rlm_sql_unixodbc: Connection failed\n"); SQLFreeHandle(SQL_HANDLE_DBC, unixodbc_sock->dbc_handle); SQLFreeHandle(SQL_HANDLE_ENV, unixodbc_sock->env_handle); return -1; } /* 4. Allocate the statement */ err_handle = SQLAllocStmt(unixodbc_sock->dbc_handle, &unixodbc_sock->stmt_handle); if (sql_state(err_handle, handle, config)) { radlog(L_ERR, "rlm_sql_unixodbc: Can't allocate the statement\n"); return -1; } return 0; }
/************************************************************************* * * Function: sql_socket_init * * Purpose: Establish connection to the db * *************************************************************************/ static sql_rcode_t sql_socket_init(rlm_sql_handle_t *handle, rlm_sql_config_t *config) { rlm_sql_unixodbc_conn_t *conn; long err_handle; MEM(conn = handle->conn = talloc_zero(handle, rlm_sql_unixodbc_conn_t)); talloc_set_destructor((void *) conn, sql_socket_destructor); /* 1. Allocate environment handle and register version */ err_handle = SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HANDLE,&conn->env); if (sql_state(err_handle, handle, config)) { ERROR("rlm_sql_unixodbc: Can't allocate environment handle\n"); return -1; } err_handle = SQLSetEnvAttr(conn->env, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0); if (sql_state(err_handle, handle, config)) { ERROR("rlm_sql_unixodbc: Can't register ODBC version\n"); SQLFreeHandle(SQL_HANDLE_ENV, conn->env); return -1; } /* 2. Allocate connection handle */ err_handle = SQLAllocHandle(SQL_HANDLE_DBC, conn->env, &conn->dbc); if (sql_state(err_handle, handle, config)) { ERROR("rlm_sql_unixodbc: Can't allocate connection handle\n"); SQLFreeHandle(SQL_HANDLE_ENV, conn->env); return -1; } /* 3. Connect to the datasource */ { SQLCHAR *odbc_server, *odbc_login, *odbc_password; memcpy(&odbc_server, &config->sql_server, sizeof(odbc_server)); memcpy(&odbc_login, &config->sql_login, sizeof(odbc_login)); memcpy(&odbc_password, &config->sql_password, sizeof(odbc_password)); err_handle = SQLConnect(conn->dbc, odbc_server, strlen(config->sql_server), odbc_login, strlen(config->sql_login), odbc_password, strlen(config->sql_password)); } if (sql_state(err_handle, handle, config)) { ERROR("rlm_sql_unixodbc: Connection failed\n"); SQLFreeHandle(SQL_HANDLE_DBC, conn->dbc); SQLFreeHandle(SQL_HANDLE_ENV, conn->env); return -1; } /* 4. Allocate the statement */ err_handle = SQLAllocStmt(conn->dbc, &conn->statement); if (sql_state(err_handle, handle, config)) { ERROR("rlm_sql_unixodbc: Can't allocate the statement\n"); return -1; } return 0; }
/************************************************************************* * * Function: sql_affected_rows * * Purpose: Return the number of rows affected by the query (update, * or insert) * *************************************************************************/ static int sql_affected_rows(rlm_sql_handle_t *handle, rlm_sql_config_t *config) { rlm_sql_unixodbc_sock *unixodbc_sock = handle->conn; long err_handle; SQLLEN affected_rows; err_handle = SQLRowCount(unixodbc_sock->stmt_handle, &affected_rows); if (sql_state(err_handle, handle, config)) return -1; return affected_rows; }
/************************************************************************* * * Function: sql_num_fields * * Purpose: database specific num_fields function. Returns number * of columns from query * *************************************************************************/ static int sql_num_fields(rlm_sql_handle_t *handle, rlm_sql_config_t *config) { rlm_sql_unixodbc_sock *unixodbc_sock = handle->conn; long err_handle; SQLSMALLINT num_fields = 0; err_handle = SQLNumResultCols(unixodbc_sock->stmt_handle,&num_fields); if (sql_state(err_handle, handle, config)) return -1; return num_fields; }
/************************************************************************* * * Function: sql_affected_rows * * Purpose: Return the number of rows affected by the query (update, * or insert) * *************************************************************************/ static int sql_affected_rows(rlm_sql_handle_t *handle, rlm_sql_config_t *config) { rlm_sql_unixodbc_conn_t *conn = handle->conn; long err_handle; SQLLEN affected_rows; err_handle = SQLRowCount(conn->statement, &affected_rows); if (sql_state(err_handle, handle, config)) { return -1; } return affected_rows; }
/************************************************************************* * * Function: sql_num_fields * * Purpose: database specific num_fields function. Returns number * of columns from query * *************************************************************************/ static int sql_num_fields(rlm_sql_handle_t *handle, rlm_sql_config_t *config) { rlm_sql_unixodbc_conn_t *conn = handle->conn; long err_handle; SQLSMALLINT num_fields = 0; err_handle = SQLNumResultCols(conn->statement,&num_fields); if (sql_state(err_handle, handle, config)) { return -1; } return num_fields; }
/************************************************************************* * * Function: sql_query * * Purpose: Issue a non-SELECT query (ie: update/delete/insert) to * the database. * *************************************************************************/ static int sql_query(rlm_sql_handle_t *handle, rlm_sql_config_t *config, char *querystr) { rlm_sql_unixodbc_sock *unixodbc_sock = handle->conn; long err_handle; int state; /* Executing query */ err_handle = SQLExecDirect(unixodbc_sock->stmt_handle, (SQLCHAR *)querystr, strlen(querystr)); if ((state = sql_state(err_handle, handle, config))) { if(state == SQL_DOWN) DEBUG("rlm_sql_unixodbc: rlm_sql will attempt to reconnect\n"); return state; } return 0; }
/************************************************************************* * * Function: sql_fetch_row * * Purpose: database specific fetch_row. Returns a rlm_sql_row_t struct * with all the data for the query in 'handle->row'. Returns * 0 on success, -1 on failure, SQL_DOWN if 'database is down'. * *************************************************************************/ static int sql_fetch_row(rlm_sql_handle_t *handle, rlm_sql_config_t *config) { rlm_sql_unixodbc_sock *unixodbc_sock = handle->conn; long err_handle; int state; handle->row = NULL; err_handle = SQLFetch(unixodbc_sock->stmt_handle); if(err_handle == SQL_NO_DATA_FOUND) return 0; if ((state = sql_state(err_handle, handle, config))) { if(state == SQL_DOWN) DEBUG("rlm_sql_unixodbc: rlm_sql will attempt to reconnect"); return state; } handle->row = unixodbc_sock->row; return 0; }
/************************************************************************* * * Function: sql_query * * Purpose: Issue a non-SELECT query (ie: update/delete/insert) to * the database. * *************************************************************************/ static sql_rcode_t sql_query(rlm_sql_handle_t *handle, rlm_sql_config_t *config, char const *query) { rlm_sql_unixodbc_conn_t *conn = handle->conn; long err_handle; int state; /* Executing query */ { SQLCHAR *odbc_query; memcpy(&odbc_query, &query, sizeof(odbc_query)); err_handle = SQLExecDirect(conn->statement, odbc_query, strlen(query)); } if ((state = sql_state(err_handle, handle, config))) { if(state == RLM_SQL_RECONNECT) { DEBUG("rlm_sql_unixodbc: rlm_sql will attempt to reconnect"); } return state; } return 0; }
/************************************************************************* * * Function: sql_fetch_row * * Purpose: database specific fetch_row. Returns a rlm_sql_row_t struct * with all the data for the query in 'handle->row'. Returns * 0 on success, -1 on failure, RLM_SQL_RECONNECT if 'database is down'. * *************************************************************************/ static sql_rcode_t sql_fetch_row(rlm_sql_handle_t *handle, rlm_sql_config_t *config) { rlm_sql_unixodbc_conn_t *conn = handle->conn; long err_handle; int state; handle->row = NULL; err_handle = SQLFetch(conn->statement); if(err_handle == SQL_NO_DATA_FOUND) { return 0; } if ((state = sql_state(err_handle, handle, config))) { if(state == RLM_SQL_RECONNECT) { DEBUG("rlm_sql_unixodbc: rlm_sql will attempt to reconnect"); } return state; } handle->row = conn->row; return 0; }