Replace radlog(L_ERR with DEBUGE
[freeradius.git] / src / modules / rlm_sql / drivers / rlm_sql_db2 / rlm_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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2000,2006  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 RCSID("$Id$")
32
33 #include <freeradius-devel/radiusd.h>
34
35 #include <sys/stat.h>
36
37 #include <sql.h>
38 #include <sqlcli.h>
39 #include "rlm_sql.h"
40
41 typedef struct rlm_sql_conn {
42         SQLHANDLE hdbc;
43         SQLHANDLE henv;
44         SQLHANDLE stmt;
45 } rlm_sql_db2_conn_t;
46
47 static int sql_socket_destructor(void *c)
48 {
49         rlm_sql_db2_conn_t *conn = c;
50         
51         DEBUG2("rlm_sql_db2: Socket destructor called, closing socket");
52         
53         if (conn->hdbc) {
54                 SQLDisconnect(conn->hdbc);
55                 SQLFreeHandle(SQL_HANDLE_DBC, conn->hdbc);
56         }
57         
58         if (conn->henv) {
59                 SQLFreeHandle(SQL_HANDLE_ENV, conn->henv);
60         }
61         
62         return 0;
63 }
64
65 /*************************************************************************
66  *
67  *      Function: sql_create_socket
68  *
69  *      Purpose: Establish connection to the db
70  *
71  *************************************************************************/
72 static int sql_socket_init(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
73 {
74         SQLRETURN retval;
75         rlm_sql_db2_conn_t *conn;
76
77         MEM(conn = handle->conn = talloc_zero(handle, rlm_sql_db2_conn_t));
78         talloc_set_destructor((void *) conn, sql_socket_destructor);
79         
80         /* allocate handles */
81         SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &(conn->henv));
82         SQLAllocHandle(SQL_HANDLE_DBC, conn->henv, &(conn->hdbc));
83
84         /* connect to database */
85         retval = SQLConnect(conn->hdbc,
86                             config->sql_server, SQL_NTS,
87                             config->sql_login,  SQL_NTS,
88                             config->sql_password, SQL_NTS);
89         if(retval != SQL_SUCCESS) {
90                 DEBUGE("could not connect to DB2 server %s\n",
91                        config->sql_server);
92                 
93                 return -1;
94         }
95
96         return 0;
97 }
98
99 /*************************************************************************
100  *
101  *      Function: sql_query
102  *
103  *      Purpose: Issue a query to the database
104  *
105  *************************************************************************/
106 static int sql_query(rlm_sql_handle_t * handle, UNUSED rlm_sql_config_t *config,
107                      char *querystr)
108 {
109         SQLRETURN retval;
110         rlm_sql_db2_conn_t *conn;
111
112         conn = handle->conn;
113
114         /* allocate handle for statement */
115         SQLAllocHandle(SQL_HANDLE_STMT, conn->hdbc,
116                         &(conn->stmt));
117
118         /* execute query */
119         retval = SQLExecDirect(conn->stmt, querystr, SQL_NTS);
120         if(retval != SQL_SUCCESS) {
121                 /* XXX Check if retval means we should return SQL_DOWN */
122                 DEBUGE("could not execute statement \"%s\"\n", querystr);
123                 return -1;
124         }
125
126         return 0;
127 }
128
129
130 /*************************************************************************
131  *
132  *      Function: sql_select_query
133  *
134  *      Purpose: Issue a select query to the database
135  *
136  *************************************************************************/
137 static int sql_select_query(rlm_sql_handle_t * handle, rlm_sql_config_t *config, char *querystr)
138 {
139         return sql_query(handle, config, querystr);
140 }
141
142
143 /*************************************************************************
144  *
145  *      Function: sql_num_fields
146  *
147  *      Purpose: database specific num_fields function. Returns number
148  *             of columns from query
149  *
150  *************************************************************************/
151 static int sql_num_fields(rlm_sql_handle_t * handle, UNUSED rlm_sql_config_t *config)
152 {
153         SQLSMALLINT c;
154         rlm_sql_db2_conn_t *conn;
155
156         conn = handle->conn;
157         SQLNumResultCols(conn->stmt, &c);
158         return c;
159 }
160
161
162 /*************************************************************************
163  *
164  *      Function: sql_fetch_row
165  *
166  *      Purpose: database specific fetch_row. Returns a rlm_sql_row_t struct
167  *             with all the data for the query in 'handle->row'. Returns
168  *               0 on success, -1 on failure, SQL_DOWN if 'database is down'
169  *
170  *************************************************************************/
171 static int sql_fetch_row(rlm_sql_handle_t * handle, rlm_sql_config_t *config)
172 {
173         int c, i;
174         SQLINTEGER len, slen;
175         rlm_sql_row_t retval;
176         rlm_sql_db2_conn_t *conn;
177
178         conn = handle->conn;
179
180         c = sql_num_fields(handle, config);
181         retval = (rlm_sql_row_t)rad_malloc(c*sizeof(char*)+1);
182         memset(retval, 0, c*sizeof(char*)+1);
183
184         /* advance cursor */
185         if(SQLFetch(conn->stmt) == SQL_NO_DATA_FOUND) {
186                 handle->row = NULL;
187                 goto error;
188         }
189
190         for(i = 0; i < c; i++) {
191                 /* get column length */
192                 SQLColAttribute(conn->stmt,
193                                 i+1, SQL_DESC_DISPLAY_SIZE,
194                                 NULL, 0, NULL, &len);
195                 retval[i] = (char*)rad_malloc(len+1);
196                 /* get the actual column */
197                 SQLGetData(conn->stmt,
198                                 i+1, SQL_C_CHAR, retval[i], len+1, &slen);
199                 if(slen == SQL_NULL_DATA)
200                         retval[i][0] = '\0';
201         }
202
203         handle->row = retval;
204         return 0;
205
206 error:
207         for(i = 0; i < c; i++) {
208                 free(retval[i]);
209         }
210         free(retval);
211         return -1;
212 }
213
214 /*************************************************************************
215  *
216  *      Function: sql_free_result
217  *
218  *      Purpose: database specific free_result. Frees memory allocated
219  *             for a result set
220  *
221  *************************************************************************/
222 static int sql_free_result(rlm_sql_handle_t * handle, UNUSED rlm_sql_config_t *config)
223 {
224         rlm_sql_db2_conn_t *conn;
225         conn = handle->conn;
226         SQLFreeHandle(SQL_HANDLE_STMT, conn->stmt);
227         return 0;
228 }
229
230
231
232 /*************************************************************************
233  *
234  *      Function: sql_error
235  *
236  *      Purpose: database specific error. Returns error associated with
237  *             connection
238  *
239  *************************************************************************/
240 static const char *sql_error(rlm_sql_handle_t * handle, UNUSED rlm_sql_config_t *config)
241 {
242         /* this should really be enough, if not, you still got the sqlstate */
243 #define MSGLEN 512
244         char sqlstate[6];
245         char msg[MSGLEN];
246         char *retval;
247         SQLINTEGER err;
248         SQLSMALLINT rl;
249         rlm_sql_db2_conn_t *conn;
250
251         conn = handle->conn;
252
253         SQLGetDiagRec(SQL_HANDLE_STMT, conn->stmt,
254                         1, sqlstate, &err, msg, MSGLEN, &rl);
255         retval = (char*)rad_malloc(strlen(msg)+20);
256         sprintf(retval, "SQLSTATE %s: %s", sqlstate, msg);
257         return retval;
258 }
259
260
261 /*************************************************************************
262  *
263  *      Function: sql_finish_query
264  *
265  *      Purpose: End the query, such as freeing memory
266  *
267  *************************************************************************/
268 static int sql_finish_query(UNUSED rlm_sql_handle_t * handle, UNUSED rlm_sql_config_t *config)
269 {
270         return 0;
271 }
272
273
274
275 /*************************************************************************
276  *
277  *      Function: sql_finish_select_query
278  *
279  *      Purpose: End the select query, such as freeing memory or result
280  *
281  *************************************************************************/
282 static int sql_finish_select_query(rlm_sql_handle_t * handle, rlm_sql_config_t *config)
283 {
284         return sql_finish_query(handle, config);
285 }
286
287
288 /*************************************************************************
289  *
290  *      Function: sql_affected_rows
291  *
292  *      Purpose: Return the number of rows affected by the last query.
293  *
294  *************************************************************************/
295 static int sql_affected_rows(rlm_sql_handle_t * handle, UNUSED rlm_sql_config_t *config)
296 {
297         SQLINTEGER c;
298         rlm_sql_db2_conn_t *conn;
299
300         conn = handle->conn;
301
302         SQLRowCount(conn->stmt, &c);
303         return c;
304 }
305
306
307 static int
308 not_implemented(UNUSED rlm_sql_handle_t * handle, UNUSED rlm_sql_config_t *config)
309 {
310         DEBUGE("sql_db2: calling unimplemented function");
311         exit(1);
312 }
313
314
315 /* Exported to rlm_sql */
316 rlm_sql_module_t rlm_sql_db2 = {
317         "rlm_sql_db2",
318         NULL,
319         sql_socket_init,
320         sql_query,
321         sql_select_query,
322         not_implemented, /* sql_store_result */
323         sql_num_fields,
324         not_implemented, /* sql_num_rows */
325         sql_fetch_row,
326         sql_free_result,
327         sql_error,
328         sql_finish_query,
329         sql_finish_select_query,
330         sql_affected_rows,
331 };