Normalized error messages
[freeradius.git] / src / modules / rlm_sql / drivers / rlm_sql_mysql / sql_mysql.c
1 /*
2  * sql_mysql.c          SQL Module
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  */
24
25 #include <stdio.h>
26 #include <sys/stat.h>
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include <mysql/errmsg.h>
31
32 #include        "radiusd.h"
33
34 #include        <mysql/mysql.h>
35 #include        "rlm_sql.h"
36
37 typedef struct rlm_sql_mysql_sock {
38         MYSQL conn;
39         MYSQL *sock;
40         MYSQL_RES *result;
41         SQL_ROW row;
42 } rlm_sql_mysql_sock;
43
44 /*************************************************************************
45  *
46  *      Function: sql_create_socket
47  *
48  *      Purpose: Establish connection to the db
49  *
50  *************************************************************************/
51 static int sql_init_socket(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
52
53         rlm_sql_mysql_sock *mysql_sock;
54
55         sqlsocket->conn = (rlm_sql_mysql_sock *)rad_malloc(sizeof(rlm_sql_mysql_sock));
56
57         mysql_sock = sqlsocket->conn;
58
59         radlog(L_INFO, "rlm_sql_mysql: Starting connect to MySQL server for #%d",
60                         sqlsocket->id);
61
62         mysql_init(&(mysql_sock->conn));
63         if (!(mysql_sock->sock = mysql_real_connect(&(mysql_sock->conn), config->sql_server, config->sql_login, config->sql_password,
64                                                                                                         config->sql_db, 0, NULL, CLIENT_FOUND_ROWS))) {
65                 radlog(L_ERR, "rlm_sql_mysql: Couldn't connect socket to MySQL server %s@%s:%s", config->sql_login, config->sql_server, config->sql_db);
66                 radlog(L_ERR, "rlm_sql_mysql: Mysql error '%s'", mysql_error(&mysql_sock->conn));
67                 mysql_sock->sock = NULL;
68                 return -1;
69         }
70
71
72         return 0;
73 }
74
75
76 /*************************************************************************
77  *
78  *      Function: sql_destroy_socket
79  *
80  *      Purpose: Free socket and any private connection data
81  *
82  *************************************************************************/
83 static int sql_destroy_socket(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
84
85         rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
86
87         free(mysql_sock);
88         free(sqlsocket);
89
90         return 0;
91 }
92
93
94 /*************************************************************************
95  *
96  *      Function: sql_query
97  *
98  *      Purpose: Issue a query to the database
99  *
100  *************************************************************************/
101 static int sql_query(SQLSOCK * sqlsocket, SQL_CONFIG *config, char *querystr) {
102
103         rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
104
105         if (config->sqltrace)
106                 radlog(L_DBG,"rlm_sql_mysql: query:  %s", querystr);
107         if (mysql_sock->sock == NULL) {
108                 radlog(L_ERR, "rlm_sql_mysql: Socket not connected");
109                 return SQL_DOWN;
110         }
111
112         mysql_query(mysql_sock->sock, querystr);
113         return sql_check_error(mysql_errno(mysql_sock->sock));
114 }
115
116
117 /*************************************************************************
118  *
119  *      Function: sql_select_query
120  *
121  *      Purpose: Issue a select query to the database
122  *
123  *************************************************************************/
124 static int sql_select_query(SQLSOCK *sqlsocket, SQL_CONFIG *config, char *querystr) {
125
126         int ret;
127
128         ret = sql_query(sqlsocket, config, querystr);
129         if(ret)
130                 return ret;
131         ret = sql_store_result(sqlsocket, config);
132         if (ret) {
133                 return ret;
134         }
135
136         /* Why? Per http://www.mysql.com/doc/n/o/node_591.html,
137          * this cannot return an error.  Perhaps just to complain if no
138          * fields are found?
139          */
140         sql_num_fields(sqlsocket, config);
141
142         return ret;
143 }
144
145
146 /*************************************************************************
147  *
148  *      Function: sql_store_result
149  *
150  *      Purpose: database specific store_result function. Returns a result
151  *               set for the query.
152  *
153  *************************************************************************/
154 static int sql_store_result(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
155
156         rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
157
158         if (mysql_sock->sock == NULL) {
159                 radlog(L_ERR, "rlm_sql_mysql: Socket not connected");
160                 return SQL_DOWN;
161         }
162         if (!(mysql_sock->result = mysql_store_result(mysql_sock->sock))) {
163                 radlog(L_ERR, "rlm_sql_mysql: MYSQL Error: Cannot get result");
164                 radlog(L_ERR, "rlm_sql_mysql: MYSQL Error: %s", mysql_error(mysql_sock->sock));
165                 return sql_check_error(mysql_errno(mysql_sock->sock));
166         }
167         return 0;
168 }
169
170
171 /*************************************************************************
172  *
173  *      Function: sql_num_fields
174  *
175  *      Purpose: database specific num_fields function. Returns number
176  *               of columns from query
177  *
178  *************************************************************************/
179 static int sql_num_fields(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
180
181
182         int     num = 0;
183         rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
184
185 #if MYSQL_VERSION_ID >= 32224
186         if (!(num = mysql_field_count(mysql_sock->sock))) {
187 #else
188         if (!(num = mysql_num_fields(mysql_sock->sock))) {
189 #endif
190                 radlog(L_ERR, "rlm_sql_mysql: MYSQL Error: No Fields");
191                 radlog(L_ERR, "rlm_sql_mysql: MYSQL error: %s", mysql_error(mysql_sock->sock));
192         }
193         return num;
194 }
195
196
197 /*************************************************************************
198  *
199  *      Function: sql_num_rows
200  *
201  *      Purpose: database specific num_rows. Returns number of rows in
202  *               query
203  *
204  *************************************************************************/
205 static int sql_num_rows(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
206
207         rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
208
209         if(mysql_sock->result)
210                 return mysql_num_rows(mysql_sock->result);
211
212         return 0;
213 }
214
215
216 /*************************************************************************
217  *
218  *      Function: sql_fetch_row
219  *
220  *      Purpose: database specific fetch_row. Returns a SQL_ROW struct
221  *               with all the data for the query in 'sqlsocket->row'. Returns
222  *               0 on success, -1 on failure, SQL_DOWN if database is down.
223  *
224  *************************************************************************/
225 static int sql_fetch_row(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
226
227         rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
228
229         sqlsocket->row = mysql_fetch_row(mysql_sock->result);
230
231         if (sqlsocket->row == NULL) {
232                 return sql_check_error(mysql_errno(mysql_sock->sock));
233         }
234         return 0;
235 }
236
237
238 /*************************************************************************
239  *
240  *      Function: sql_check_error
241  *
242  *      Purpose: check the error to see if the server is down
243  *
244  *************************************************************************/
245 static int sql_check_error(int error) {
246         switch(error) {
247         case CR_SERVER_GONE_ERROR:
248         case CR_SERVER_LOST:
249         case -1:
250                 radlog(L_DBG, "rlm_sql_mysql: MYSQL check_error: %d, returning SQL_DOWN", error);
251                 return SQL_DOWN;
252                 break;
253         case 0:
254                 return 0;
255                 break;
256         case CR_OUT_OF_MEMORY:
257         case CR_COMMANDS_OUT_OF_SYNC:
258         case CR_UNKNOWN_ERROR:
259         default:
260                 radlog(L_DBG, "rlm_sql_mysql: MYSQL check_error: %d received", error);
261                 return -1;
262                 break;
263         }
264 }
265
266
267
268 /*************************************************************************
269  *
270  *      Function: sql_free_result
271  *
272  *      Purpose: database specific free_result. Frees memory allocated
273  *               for a result set
274  *
275  *************************************************************************/
276 static int sql_free_result(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
277
278         rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
279
280         if (mysql_sock->result) {
281                 mysql_free_result(mysql_sock->result);
282         }
283
284         return 0;
285 }
286
287
288
289 /*************************************************************************
290  *
291  *      Function: sql_error
292  *
293  *      Purpose: database specific error. Returns error associated with
294  *               connection
295  *
296  *************************************************************************/
297 static char *sql_error(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
298
299         rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
300
301         if (mysql_sock == NULL || mysql_sock->sock == NULL) {
302                 return "rlm_sql_mysql: no connection to db";
303         }
304         return mysql_error(mysql_sock->sock);
305 }
306
307
308 /*************************************************************************
309  *
310  *      Function: sql_close
311  *
312  *      Purpose: database specific close. Closes an open database
313  *               connection
314  *
315  *************************************************************************/
316 static int sql_close(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
317
318         rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
319
320         if (mysql_sock && mysql_sock->sock){
321                 mysql_close(mysql_sock->sock);
322                 mysql_sock->sock = NULL;
323         }
324
325         return 0;
326 }
327
328
329 /*************************************************************************
330  *
331  *      Function: sql_finish_query
332  *
333  *      Purpose: End the query, such as freeing memory
334  *
335  *************************************************************************/
336 static int sql_finish_query(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
337
338         return 0;
339 }
340
341
342
343 /*************************************************************************
344  *
345  *      Function: sql_finish_select_query
346  *
347  *      Purpose: End the select query, such as freeing memory or result
348  *
349  *************************************************************************/
350 static int sql_finish_select_query(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
351
352         sql_free_result(sqlsocket, config);
353
354         return 0;
355 }
356
357
358 /*************************************************************************
359  *
360  *      Function: sql_affected_rows
361  *
362  *      Purpose: End the select query, such as freeing memory or result
363  *
364  *************************************************************************/
365 static int sql_affected_rows(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
366
367         rlm_sql_mysql_sock *mysql_sock = sqlsocket->conn;
368
369         return mysql_affected_rows(mysql_sock->sock);
370 }
371
372
373 /* Exported to rlm_sql */
374 rlm_sql_module_t rlm_sql_mysql = {
375         "rlm_sql_mysql",
376         sql_init_socket,
377         sql_destroy_socket,
378         sql_query,
379         sql_select_query,
380         sql_store_result,
381         sql_num_fields,
382         sql_num_rows,
383         sql_fetch_row,
384         sql_free_result,
385         sql_error,
386         sql_close,
387         sql_finish_query,
388         sql_finish_select_query,
389         sql_affected_rows
390 };