Define return codes for SQL drivers
[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 sql_rcode_t 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         /*
85          *      The db2 API doesn't qualify arguments as const even when they should be.
86          */
87         {
88                 SQLCHAR *server, *login, *password;
89                 
90                 memcpy(&server, &config->sql_server, sizeof(server));
91                 memcpy(&login, &config->sql_login, sizeof(login));
92                 memcpy(&password, &config->sql_password, sizeof(password));
93                 
94                 retval = SQLConnect(conn->hdbc,
95                                     server, SQL_NTS,
96                                     login,  SQL_NTS,
97                                     password, SQL_NTS);
98         }
99
100         
101         if(retval != SQL_SUCCESS) {
102                 ERROR("could not connect to DB2 server %s\n",
103                        config->sql_server);
104                 
105                 return -1;
106         }
107
108         return 0;
109 }
110
111 /*************************************************************************
112  *
113  *      Function: sql_query
114  *
115  *      Purpose: Issue a query to the database
116  *
117  *************************************************************************/
118 static sql_rcode_t sql_query(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config, char const *query)
119 {
120         SQLRETURN retval;
121         rlm_sql_db2_conn_t *conn;
122
123         conn = handle->conn;
124
125         /* allocate handle for statement */
126         SQLAllocHandle(SQL_HANDLE_STMT, conn->hdbc, &(conn->stmt));
127
128         /* execute query */
129         {
130                 SQLCHAR *db2_query;
131                 memcpy(&db2_query, &query, sizeof(query));
132
133                 retval = SQLExecDirect(conn->stmt, db2_query, SQL_NTS);
134                 if(retval != SQL_SUCCESS) {
135                         /* XXX Check if retval means we should return RLM_SQL_RECONNECT */
136                         ERROR("Could not execute statement \"%s\"\n", query);
137                         return -1;
138                 }
139         }
140
141         return 0;
142 }
143
144
145 /*************************************************************************
146  *
147  *      Function: sql_select_query
148  *
149  *      Purpose: Issue a select query to the database
150  *
151  *************************************************************************/
152 static sql_rcode_t sql_select_query(rlm_sql_handle_t * handle, rlm_sql_config_t *config, char const *query)
153 {
154         return sql_query(handle, config, query);
155 }
156
157
158 /*************************************************************************
159  *
160  *      Function: sql_num_fields
161  *
162  *      Purpose: database specific num_fields function. Returns number
163  *             of columns from query
164  *
165  *************************************************************************/
166 static int sql_num_fields(rlm_sql_handle_t * handle, UNUSED rlm_sql_config_t *config)
167 {
168         SQLSMALLINT c;
169         rlm_sql_db2_conn_t *conn;
170
171         conn = handle->conn;
172         SQLNumResultCols(conn->stmt, &c);
173         return c;
174 }
175
176
177 /*************************************************************************
178  *
179  *      Function: sql_fetch_row
180  *
181  *      Purpose: database specific fetch_row. Returns a rlm_sql_row_t struct
182  *             with all the data for the query in 'handle->row'. Returns
183  *               0 on success, -1 on failure, RLM_SQL_RECONNECT if 'database is down'
184  *
185  *************************************************************************/
186 static sql_rcode_t sql_fetch_row(rlm_sql_handle_t * handle, rlm_sql_config_t *config)
187 {
188         int c, i;
189         SQLINTEGER len, slen;
190         rlm_sql_row_t retval;
191         rlm_sql_db2_conn_t *conn;
192
193         conn = handle->conn;
194
195         c = sql_num_fields(handle, config);
196         retval = (rlm_sql_row_t)rad_malloc(c*sizeof(char*)+1);
197         memset(retval, 0, c*sizeof(char*)+1);
198
199         /* advance cursor */
200         if(SQLFetch(conn->stmt) == SQL_NO_DATA_FOUND) {
201                 handle->row = NULL;
202                 goto error;
203         }
204
205         for(i = 0; i < c; i++) {
206                 /* get column length */
207                 SQLColAttribute(conn->stmt,
208                                 i+1, SQL_DESC_DISPLAY_SIZE,
209                                 NULL, 0, NULL, &len);
210                 retval[i] = (char*)rad_malloc(len+1);
211                 /* get the actual column */
212                 SQLGetData(conn->stmt,
213                                 i+1, SQL_C_CHAR, retval[i], len+1, &slen);
214                 if(slen == SQL_NULL_DATA)
215                         retval[i][0] = '\0';
216         }
217
218         handle->row = retval;
219         return 0;
220
221 error:
222         for(i = 0; i < c; i++) {
223                 free(retval[i]);
224         }
225         free(retval);
226         return -1;
227 }
228
229 /*************************************************************************
230  *
231  *      Function: sql_free_result
232  *
233  *      Purpose: database specific free_result. Frees memory allocated
234  *             for a result set
235  *
236  *************************************************************************/
237 static sql_rcode_t sql_free_result(rlm_sql_handle_t * handle, UNUSED rlm_sql_config_t *config)
238 {
239         rlm_sql_db2_conn_t *conn;
240         conn = handle->conn;
241         SQLFreeHandle(SQL_HANDLE_STMT, conn->stmt);
242         return 0;
243 }
244
245
246
247 /*************************************************************************
248  *
249  *      Function: sql_error
250  *
251  *      Purpose: database specific error. Returns error associated with
252  *             connection
253  *
254  *************************************************************************/
255 static char const *sql_error(rlm_sql_handle_t * handle, UNUSED rlm_sql_config_t *config)
256 {
257         /* this should really be enough, if not, you still got the sqlstate */
258 #define MSGLEN 512
259         char sqlstate[6];
260         char msg[MSGLEN];
261         char *retval;
262         SQLINTEGER err;
263         SQLSMALLINT rl;
264         rlm_sql_db2_conn_t *conn;
265
266         conn = handle->conn;
267
268         SQLGetDiagRec(SQL_HANDLE_STMT, conn->stmt, 1, (SQLCHAR *) sqlstate, &err, (SQLCHAR *) msg, MSGLEN, &rl);
269         
270         retval = rad_malloc(strlen(msg)+20);
271         sprintf(retval, "SQLSTATE %s: %s", sqlstate, msg);
272         
273         return retval;
274 }
275
276
277 /*************************************************************************
278  *
279  *      Function: sql_finish_query
280  *
281  *      Purpose: End the query, such as freeing memory
282  *
283  *************************************************************************/
284 static sql_rcode_t sql_finish_query(UNUSED rlm_sql_handle_t * handle, UNUSED rlm_sql_config_t *config)
285 {
286         return 0;
287 }
288
289
290
291 /*************************************************************************
292  *
293  *      Function: sql_finish_select_query
294  *
295  *      Purpose: End the select query, such as freeing memory or result
296  *
297  *************************************************************************/
298 static sql_rcode_t sql_finish_select_query(rlm_sql_handle_t * handle, rlm_sql_config_t *config)
299 {
300         return sql_finish_query(handle, config);
301 }
302
303
304 /*************************************************************************
305  *
306  *      Function: sql_affected_rows
307  *
308  *      Purpose: Return the number of rows affected by the last query.
309  *
310  *************************************************************************/
311 static int sql_affected_rows(rlm_sql_handle_t * handle, UNUSED rlm_sql_config_t *config)
312 {
313         SQLINTEGER c;
314         rlm_sql_db2_conn_t *conn;
315
316         conn = handle->conn;
317
318         SQLRowCount(conn->stmt, &c);
319         return c;
320 }
321
322
323 static int
324 not_implemented(UNUSED rlm_sql_handle_t * handle, UNUSED rlm_sql_config_t *config)
325 {
326         ERROR("sql_db2: calling unimplemented function");
327         exit(1);
328 }
329
330
331 /* Exported to rlm_sql */
332 rlm_sql_module_t rlm_sql_db2 = {
333         "rlm_sql_db2",
334         NULL,
335         sql_socket_init,
336         sql_query,
337         sql_select_query,
338         not_implemented, /* sql_store_result */
339         sql_num_fields,
340         not_implemented, /* sql_num_rows */
341         sql_fetch_row,
342         sql_free_result,
343         sql_error,
344         sql_finish_query,
345         sql_finish_select_query,
346         sql_affected_rows,
347 };