Massively cleaned up #include's, so they're in a consistent
[freeradius.git] / src / modules / rlm_sql / drivers / rlm_sql_iodbc / sql_iodbc.c
1 /*
2  * sql_iodbc.c  iODBC support for FreeRadius
3  *
4  * Version:     $Id$
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 2 of the License, or
9  *   (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program; if not, write to the Free Software
18  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2000,2006  The FreeRADIUS server project
21  * Copyright 2000  Jeff Carneal <jeff@apex.net>
22  */
23
24 #include <freeradius-devel/ident.h>
25 RCSID("$Id$")
26
27 #include <freeradius-devel/radiusd.h>
28
29 #include <sys/stat.h>
30
31 #include <isql.h>
32 #include <isqlext.h>
33 #include <sqltypes.h>
34
35 #include "rlm_sql.h"
36
37 typedef struct rlm_sql_iodbc_sock {
38         HENV    env_handle;
39         HDBC    dbc_handle;
40         HSTMT   stmt_handle;
41         int             id;
42         SQL_ROW row;
43
44         struct sql_socket *next;
45
46         void    *conn;
47 } rlm_sql_iodbc_sock;;
48
49 static char *sql_error(SQLSOCK *sqlsocket, SQL_CONFIG *config);
50 static int sql_num_fields(SQLSOCK *sqlsocket, SQL_CONFIG *config);
51
52 /*************************************************************************
53  *
54  *      Function: sql_init_socket
55  *
56  *      Purpose: Establish connection to the db
57  *
58  *************************************************************************/
59 static int sql_init_socket(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
60
61         rlm_sql_iodbc_sock *iodbc_sock;
62         SQLRETURN rcode;
63
64         if (!sqlsocket->conn) {
65                 sqlsocket->conn = (rlm_sql_iodbc_sock *)rad_malloc(sizeof(rlm_sql_iodbc_sock));
66                 if (!sqlsocket->conn) {
67                         return -1;
68                 }
69         }
70         iodbc_sock = sqlsocket->conn;
71         memset(iodbc_sock, 0, sizeof(*iodbc_sock));
72
73         rcode = SQLAllocEnv(&iodbc_sock->env_handle);
74         if (!SQL_SUCCEEDED(rcode)) {
75                 radlog(L_CONS|L_ERR, "sql_create_socket: SQLAllocEnv failed:  %s",
76                                 sql_error(sqlsocket, config));
77                 return -1;
78         }
79
80         rcode = SQLAllocConnect(iodbc_sock->env_handle,
81                                 &iodbc_sock->dbc_handle);
82         if (!SQL_SUCCEEDED(rcode)) {
83                 radlog(L_CONS|L_ERR, "sql_create_socket: SQLAllocConnect failed:  %s",
84                                 sql_error(sqlsocket, config));
85                 return -1;
86         }
87
88         rcode = SQLConnect(iodbc_sock->dbc_handle, config->sql_db,
89                            SQL_NTS, config->sql_login, SQL_NTS,
90                            config->sql_password, SQL_NTS);
91         if (!SQL_SUCCEEDED(rcode)) {
92                 radlog(L_CONS|L_ERR, "sql_create_socket: SQLConnectfailed:  %s",
93                                 sql_error(sqlsocket, config));
94                 return -1;
95         }
96
97         return 0;
98 }
99
100 /*************************************************************************
101  *
102  *      Function: sql_destroy_socket
103  *
104  *      Purpose: Free socket and private connection data
105  *
106  *************************************************************************/
107 static int sql_destroy_socket(SQLSOCK *sqlsocket, UNUSED SQL_CONFIG *config)
108 {
109         free(sqlsocket->conn);
110         sqlsocket->conn = NULL;
111         return 0;
112 }
113
114 /*************************************************************************
115  *
116  *      Function: sql_query
117  *
118  *      Purpose: Issue a non-SELECT query (ie: update/delete/insert) to
119  *               the database.
120  *
121  *************************************************************************/
122 static int sql_query(SQLSOCK *sqlsocket, SQL_CONFIG *config, char *querystr) {
123
124         rlm_sql_iodbc_sock *iodbc_sock = sqlsocket->conn;
125         SQLRETURN rcode;
126
127         rcode = SQLAllocStmt(iodbc_sock->dbc_handle,
128                              &iodbc_sock->stmt_handle);
129         if (!SQL_SUCCEEDED(rcode)) {
130                 radlog(L_CONS|L_ERR, "sql_create_socket: SQLAllocStmt failed:  %s",
131                                 sql_error(sqlsocket, config));
132                 return -1;
133         }
134
135         if (config->sqltrace)
136                 radlog(L_DBG, "rlm_sql:  %s", querystr);
137         if (iodbc_sock->dbc_handle == NULL) {
138                 radlog(L_ERR, "sql_query:  Socket not connected");
139                 return -1;
140         }
141
142         rcode = SQLExecDirect(iodbc_sock->stmt_handle, querystr, SQL_NTS);
143         if (!SQL_SUCCEEDED(rcode)) {
144                 radlog(L_CONS|L_ERR, "sql_query: failed:  %s",
145                                 sql_error(sqlsocket, config));
146                 return -1;
147         }
148
149         return 0;
150 }
151
152
153 /*************************************************************************
154  *
155  *      Function: sql_select_query
156  *
157  *      Purpose: Issue a select query to the database
158  *
159  *************************************************************************/
160 static int sql_select_query(SQLSOCK *sqlsocket, SQL_CONFIG *config, char *querystr) {
161
162         int numfields = 0;
163         int i=0;
164         char **row=NULL;
165         SQLINTEGER len=0;
166         rlm_sql_iodbc_sock *iodbc_sock = sqlsocket->conn;
167
168         if(sql_query(sqlsocket, config, querystr) < 0) {
169                 return -1;
170         }
171
172         numfields = sql_num_fields(sqlsocket, config);
173
174         row = (char **) rad_malloc(sizeof(char *) * (numfields+1));
175         memset(row, 0, (sizeof(char *) * (numfields)));
176         row[numfields] = NULL;
177
178         for(i=1; i<=numfields; i++) {
179                 SQLColAttributes(iodbc_sock->stmt_handle, ((SQLUSMALLINT) i), SQL_COLUMN_LENGTH,
180                                                                                 NULL, 0, NULL, &len);
181                 len++;
182
183                 /*
184                  * Allocate space for each column
185                  */
186                 row[i-1] = (SQLCHAR*)rad_malloc((int)len);
187
188                 /*
189                  * This makes me feel dirty, but, according to Microsoft, it works.
190                  * Any ODBC datatype can be converted to a 'char *' according to
191                  * the following:
192                  *
193                  * http://msdn.microsoft.com/library/psdk/dasdk/odap4o4z.htm
194                  */
195                 SQLBindCol(iodbc_sock->stmt_handle, i, SQL_C_CHAR, (SQLCHAR *)row[i-1], len, 0);
196         }
197
198         iodbc_sock->row = row;
199
200         return 0;
201 }
202
203
204 /*************************************************************************
205  *
206  *      Function: sql_store_result
207  *
208  *      Purpose: database specific store_result function. Returns a result
209  *               set for the query.
210  *
211  *************************************************************************/
212 static int sql_store_result(UNUSED SQLSOCK *sqlsocket, UNUSED SQL_CONFIG *config) {
213
214         return 0;
215 }
216
217
218 /*************************************************************************
219  *
220  *      Function: sql_num_fields
221  *
222  *      Purpose: database specific num_fields function. Returns number
223  *               of columns from query
224  *
225  *************************************************************************/
226 static int sql_num_fields(SQLSOCK *sqlsocket, UNUSED SQL_CONFIG *config) {
227
228         SQLSMALLINT count=0;
229         rlm_sql_iodbc_sock *iodbc_sock = sqlsocket->conn;
230
231         SQLNumResultCols(iodbc_sock->stmt_handle, &count);
232
233         return (int)count;
234 }
235
236 /*************************************************************************
237  *
238  *      Function: sql_num_rows
239  *
240  *      Purpose: database specific num_rows. Returns number of rows in
241  *               query
242  *
243  *************************************************************************/
244 static int sql_num_rows(UNUSED SQLSOCK *sqlsocket, UNUSED SQL_CONFIG *config) {
245         /*
246          * I presume this function is used to determine the number of
247          * rows in a result set *before* fetching them.  I don't think
248          * this is possible in ODBC 2.x, but I'd be happy to be proven
249          * wrong.  If you know how to do this, email me at jeff@apex.net
250          */
251         return 0;
252 }
253
254
255 /*************************************************************************
256  *
257  *      Function: sql_fetch_row
258  *
259  *      Purpose: database specific fetch_row. Returns a SQL_ROW struct
260  *               with all the data for the query in 'sqlsocket->row'. Returns
261  *               0 on success, -1 on failure, SQL_DOWN if 'database is down'
262  *
263  *************************************************************************/
264 static int sql_fetch_row(SQLSOCK *sqlsocket, UNUSED SQL_CONFIG *config) {
265
266         SQLRETURN rc;
267         rlm_sql_iodbc_sock *iodbc_sock = sqlsocket->conn;
268
269         sqlsocket->row = NULL;
270
271         if((rc = SQLFetch(iodbc_sock->stmt_handle)) == SQL_NO_DATA_FOUND) {
272                 return 0;
273         }
274         /* XXX Check rc for database down, if so, return SQL_DOWN */
275
276         sqlsocket->row = iodbc_sock->row;
277         return 0;
278 }
279
280
281
282 /*************************************************************************
283  *
284  *      Function: sql_free_result
285  *
286  *      Purpose: database specific free_result. Frees memory allocated
287  *               for a result set
288  *
289  *************************************************************************/
290 static int sql_free_result(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
291
292         int i=0;
293         rlm_sql_iodbc_sock *iodbc_sock = sqlsocket->conn;
294
295         for(i=0; i<sql_num_fields(sqlsocket, config); i++) {
296                 free(iodbc_sock->row[i]);
297         }
298         free(iodbc_sock->row);
299         iodbc_sock->row=NULL;
300
301         SQLFreeStmt( iodbc_sock->stmt_handle, SQL_DROP );
302
303         return 0;
304 }
305
306
307 /*************************************************************************
308  *
309  *      Function: sql_error
310  *
311  *      Purpose: database specific error. Returns error associated with
312  *               connection
313  *
314  *************************************************************************/
315 static char *sql_error(SQLSOCK *sqlsocket, UNUSED SQL_CONFIG *config) {
316
317         SQLINTEGER errornum = 0;
318         SQLSMALLINT length = 0;
319         SQLCHAR state[256] = "";
320         static SQLCHAR error[256] = "";
321         rlm_sql_iodbc_sock *iodbc_sock = sqlsocket->conn;
322
323         SQLError(iodbc_sock->env_handle, iodbc_sock->dbc_handle, iodbc_sock->stmt_handle,
324                 state, &errornum, error, 256, &length);
325         return error;
326 }
327
328
329 /*************************************************************************
330  *
331  *      Function: sql_close
332  *
333  *      Purpose: database specific close. Closes an open database
334  *               connection and cleans up any open handles.
335  *
336  *************************************************************************/
337 static int sql_close(SQLSOCK *sqlsocket, UNUSED SQL_CONFIG *config) {
338
339         rlm_sql_iodbc_sock *iodbc_sock = sqlsocket->conn;
340
341         SQLFreeStmt(iodbc_sock->stmt_handle, SQL_DROP);
342         SQLDisconnect(iodbc_sock->dbc_handle);
343         SQLFreeConnect(iodbc_sock->dbc_handle);
344         SQLFreeEnv(iodbc_sock->env_handle);
345
346         iodbc_sock->stmt_handle = NULL;
347         iodbc_sock->dbc_handle = NULL;
348         iodbc_sock->env_handle = NULL;
349
350         return 0;
351 }
352
353
354 /*************************************************************************
355  *
356  *      Function: sql_finish_query
357  *
358  *      Purpose: End the query, such as freeing memory
359  *
360  *************************************************************************/
361 static int sql_finish_query(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
362
363         return sql_free_result(sqlsocket, config);
364 }
365
366
367
368 /*************************************************************************
369  *
370  *      Function: sql_finish_select_query
371  *
372  *      Purpose: End the select query, such as freeing memory or result
373  *
374  *************************************************************************/
375 static int sql_finish_select_query(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
376         return sql_free_result(sqlsocket, config);
377 }
378
379
380 /*************************************************************************
381  *
382  *      Function: sql_affected_rows
383  *
384  *      Purpose: Return the number of rows affected by the query (update,
385  *               or insert)
386  *
387  *************************************************************************/
388 static int sql_affected_rows(SQLSOCK *sqlsocket, UNUSED SQL_CONFIG *config) {
389
390         SQLINTEGER count;
391         rlm_sql_iodbc_sock *iodbc_sock = sqlsocket->conn;
392
393         SQLRowCount(iodbc_sock->stmt_handle, &count);
394         return (int)count;
395 }
396
397 /* Exported to rlm_sql */
398 rlm_sql_module_t rlm_sql_iodbc = {
399         "rlm_sql_iodbc",
400         sql_init_socket,
401         sql_destroy_socket,
402         sql_query,
403         sql_select_query,
404         sql_store_result,
405         sql_num_fields,
406         sql_num_rows,
407         sql_fetch_row,
408         sql_free_result,
409         sql_error,
410         sql_close,
411         sql_finish_query,
412         sql_finish_select_query,
413         sql_affected_rows
414 };