corrected typo
[freeradius.git] / src / modules / rlm_sql / drivers / rlm_sql_db2 / sql_db2.c
1 /*
2  * sql_db2.c            IBM DB2 rlm_sql driver
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * Copyright 2000  The FreeRADIUS server project
21  * Copyright 2000  Mike Machado <mike@innercite.com>
22  * Copyright 2000  Alan DeKok <aland@ox.org>
23  * Copyright 2001  Joerg Wendland <wendland@scan-plus.de>
24  */
25
26 /*
27  * Modification of rlm_sql_db2 to handle IBM DB2 UDB V7
28  * by Joerg Wendland <wendland@scan-plus.de>
29  */
30
31 #include <stdio.h>
32 #include <sys/stat.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36 #include "radiusd.h"
37 #include <sql.h>
38 #include <sqlcli.h>
39 #include "rlm_sql.h"
40
41 typedef struct rlm_sql_db2_sock {
42         SQLHANDLE hdbc;
43         SQLHANDLE henv;
44         SQLHANDLE stmt;
45 } rlm_sql_db2_sock;
46
47 /*************************************************************************
48  *
49  *      Function: sql_create_socket
50  *
51  *      Purpose: Establish connection to the db
52  *
53  *************************************************************************/
54 static int sql_init_socket(SQLSOCK *sqlsocket, SQL_CONFIG *config)
55 {
56         SQLRETURN retval;
57         rlm_sql_db2_sock *sock;
58
59         /* allocate socket */
60         if (!sqlsocket->conn) {
61                 sqlsocket->conn = (rlm_sql_db2_sock*)rad_malloc(sizeof(rlm_sql_db2_sock));
62                 if (!sqlsocket->conn) {
63                         return -1;
64                 }
65         }
66         sock = sqlsocket->conn;
67         memset(sock, 0, sizeof(*sock));
68
69         /* allocate handles */
70         SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &(sock->henv));
71         SQLAllocHandle(SQL_HANDLE_DBC, sock->henv, &(sock->hdbc));
72
73         /* connect to database */
74         retval = SQLConnect(sock->hdbc,
75                         config->sql_server, SQL_NTS,
76                         config->sql_login,  SQL_NTS,
77                         config->sql_password, SQL_NTS);
78         if(retval != SQL_SUCCESS) {
79                 radlog(L_ERR, "could not connect to DB2 server %s\n", config->sql_server);
80                 SQLDisconnect(sock->hdbc);
81                 SQLFreeHandle(SQL_HANDLE_DBC, sock->hdbc);
82                 SQLFreeHandle(SQL_HANDLE_ENV, sock->henv);
83                 return -1;
84         }
85
86         return 0;
87 }
88
89
90 /*************************************************************************
91  *
92  *      Function: sql_destroy_socket
93  *
94  *      Purpose: Free socket and private connection data
95  *
96  *************************************************************************/
97 static int sql_destroy_socket(SQLSOCK *sqlsocket, SQL_CONFIG *config)
98 {
99         free(sqlsocket->conn);
100         sqlsocket->conn = NULL;
101         return 0;
102 }
103
104 /*************************************************************************
105  *
106  *      Function: sql_query
107  *
108  *      Purpose: Issue a query to the database
109  *
110  *************************************************************************/
111 static int sql_query(SQLSOCK * sqlsocket, SQL_CONFIG *config, char *querystr)
112 {
113         SQLRETURN retval;
114         rlm_sql_db2_sock *sock;
115
116         sock = sqlsocket->conn;
117
118         if (config->sqltrace)
119                 radlog(L_DBG,"query:\n%s", querystr);
120
121         /* allocate handle for statement */
122         SQLAllocHandle(SQL_HANDLE_STMT, sock->hdbc,
123                         &(sock->stmt));
124
125         /* execute query */
126         retval = SQLExecDirect(sock->stmt, querystr, SQL_NTS);
127         if(retval != SQL_SUCCESS) {
128                 /* XXX Check if retval means we should return SQL_DOWN */
129                 radlog(L_ERR, "could not execute statement \"%s\"\n", querystr);
130                 return -1;
131         }
132
133         return 0;
134 }
135
136
137 /*************************************************************************
138  *
139  *      Function: sql_select_query
140  *
141  *      Purpose: Issue a select query to the database
142  *
143  *************************************************************************/
144 static int sql_select_query(SQLSOCK * sqlsocket, SQL_CONFIG *config, char *querystr)
145 {
146         return sql_query(sqlsocket, config, querystr);
147 }
148
149
150 /*************************************************************************
151  *
152  *      Function: sql_store_result
153  *
154  *      Purpose: database specific store_result function. Returns a result
155  *               set for the query.
156  *
157  *************************************************************************/
158 static int sql_store_result(SQLSOCK * sqlsocket, SQL_CONFIG *config)
159 {
160         return 0;
161 }
162
163
164 /*************************************************************************
165  *
166  *      Function: sql_num_fields
167  *
168  *      Purpose: database specific num_fields function. Returns number
169  *               of columns from query
170  *
171  *************************************************************************/
172 static int sql_num_fields(SQLSOCK * sqlsocket, SQL_CONFIG *config)
173 {
174         SQLSMALLINT c;
175         rlm_sql_db2_sock *sock;
176
177         sock = sqlsocket->conn;
178         SQLNumResultCols(sock->stmt, &c);
179         return c;
180 }
181
182
183 /*************************************************************************
184  *
185  *      Function: sql_fetch_row
186  *
187  *      Purpose: database specific fetch_row. Returns a SQL_ROW struct
188  *               with all the data for the query in 'sqlsocket->row'. Returns
189  *               0 on success, -1 on failure, SQL_DOWN if 'database is down'
190  *
191  *************************************************************************/
192 static int sql_fetch_row(SQLSOCK * sqlsocket, SQL_CONFIG *config)
193 {
194         int c, i;
195         SQLINTEGER len, slen;
196         SQL_ROW retval;
197         rlm_sql_db2_sock *sock;
198
199         sock = sqlsocket->conn;
200
201         c = sql_num_fields(sqlsocket, config);
202         retval = (SQL_ROW)rad_malloc(c*sizeof(char*)+1);
203         /* advance cursor */
204         if(SQLFetch(sock->stmt) == SQL_NO_DATA_FOUND) {
205                 sqlsocket->row = NULL;
206                 return 0;
207         }
208
209         for(i = 0; i < c; i++) {
210                 /* get column length */
211                 SQLColAttribute(sock->stmt,
212                                 i+1, SQL_DESC_DISPLAY_SIZE,
213                                 NULL, 0, NULL, &len);
214                 retval[i] = (char*)rad_malloc(len+1);
215                 /* get the actual column */
216                 SQLGetData(sock->stmt,
217                                 i+1, SQL_C_CHAR, retval[i], len+1, &slen);
218                 if(slen == SQL_NULL_DATA)
219                         retval[i][0] = '\0';
220         }
221
222         sqlsocket->row = retval;
223         return 0;
224 }
225
226 /*************************************************************************
227  *
228  *      Function: sql_free_result
229  *
230  *      Purpose: database specific free_result. Frees memory allocated
231  *               for a result set
232  *
233  *************************************************************************/
234 static int sql_free_result(SQLSOCK * sqlsocket, SQL_CONFIG *config)
235 {
236         rlm_sql_db2_sock *sock;
237         sock = sqlsocket->conn;
238         SQLFreeHandle(SQL_HANDLE_STMT, sock->stmt);
239         return 0;
240 }
241
242
243
244 /*************************************************************************
245  *
246  *      Function: sql_error
247  *
248  *      Purpose: database specific error. Returns error associated with
249  *               connection
250  *
251  *************************************************************************/
252 static char *sql_error(SQLSOCK * sqlsocket, SQL_CONFIG *config)
253 {
254         /* this should really be enough, if not, you still got the sqlstate */
255 #define MSGLEN 512
256         char sqlstate[6];
257         char msg[MSGLEN];
258         char *retval;
259         SQLINTEGER err;
260         SQLSMALLINT rl;
261         rlm_sql_db2_sock *sock;
262
263         sock = sqlsocket->conn;
264
265         SQLGetDiagRec(SQL_HANDLE_STMT, sock->stmt,
266                         1, sqlstate, &err, msg, MSGLEN, &rl);
267         retval = (char*)rad_malloc(strlen(msg)+20);
268         sprintf(retval, "SQLSTATE %s: %s", sqlstate, msg);
269         return retval;
270 }
271
272
273 /*************************************************************************
274  *
275  *      Function: sql_close
276  *
277  *      Purpose: database specific close. Closes an open database
278  *               connection
279  *
280  *************************************************************************/
281 static int sql_close(SQLSOCK * sqlsocket, SQL_CONFIG *config)
282 {
283         rlm_sql_db2_sock *sock;
284
285         sock = sqlsocket->conn;
286
287         SQLFreeHandle(SQL_HANDLE_DBC, sock->hdbc);
288         SQLFreeHandle(SQL_HANDLE_ENV, sock->henv);
289         return 0;
290 }
291
292
293 /*************************************************************************
294  *
295  *      Function: sql_finish_query
296  *
297  *      Purpose: End the query, such as freeing memory
298  *
299  *************************************************************************/
300 static int sql_finish_query(SQLSOCK * sqlsocket, SQL_CONFIG *config)
301 {
302         return 0;
303 }
304
305
306
307 /*************************************************************************
308  *
309  *      Function: sql_finish_select_query
310  *
311  *      Purpose: End the select query, such as freeing memory or result
312  *
313  *************************************************************************/
314 static int sql_finish_select_query(SQLSOCK * sqlsocket, SQL_CONFIG *config)
315 {
316         return sql_finish_query(sqlsocket, config);
317 }
318
319
320 /*************************************************************************
321  *
322  *      Function: sql_affected_rows
323  *
324  *      Purpose: Return the number of rows affected by the last query.
325  *
326  *************************************************************************/
327 static int sql_affected_rows(SQLSOCK * sqlsocket, SQL_CONFIG *config)
328 {
329         SQLINTEGER c;
330         rlm_sql_db2_sock *sock;
331
332         sock = sqlsocket->conn;
333
334         SQLRowCount(sock->stmt, &c);
335         return c;
336 }
337
338
339 static int
340 not_implemented(SQLSOCK * sqlsocket, SQL_CONFIG *config)
341 {
342         radlog(L_ERR, "sql_db2: calling unimplemented function");
343         exit(1);
344 }
345
346
347 /* Exported to rlm_sql */
348 rlm_sql_module_t rlm_sql_db2 = {
349         "rlm_sql_db2",
350         sql_init_socket,
351         sql_destroy_socket, /* sql_destroy_socket*/
352         sql_query,
353         sql_select_query,
354         not_implemented, /* sql_store_result */
355         sql_num_fields,
356         not_implemented, /* sql_num_rows */
357         sql_fetch_row,
358         sql_free_result,
359         sql_error,
360         sql_close,
361         sql_finish_query,
362         sql_finish_select_query,
363         sql_affected_rows,
364 };