935a2e610b8a65943ee2ea23e00563312a9df397
[freeradius.git] / src / modules / rlm_sql / drivers / rlm_sql_firebird / rlm_sql_firebird.c
1 /*
2  * sql_firebird.c Part of Firebird rlm_sql driver
3  *
4  *   This program is free software; you can redistribute it and/or modify
5  *   it under the terms of the GNU General Public License as published by
6  *   the Free Software Foundation; either version 2 of the License, or
7  *   (at your option) any later version.
8  *
9  *   This program is distributed in the hope that it will be useful,
10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *   GNU General Public License for more details.
13  *
14  *   You should have received a copy of the GNU General Public License
15  *   along with this program; if not, write to the Free Software
16  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  *
18  * Copyright 2006  The FreeRADIUS server project
19  * Copyright 2006  Vitaly Bodzhgua <vitaly@eastera.net>
20  */
21
22 #include <freeradius-devel/ident.h>
23 RCSID("$Id$")
24
25 #include "sql_fbapi.h"
26
27
28 /* Forward declarations */
29 static const char *sql_error(rlm_sql_handle_t *handle, rlm_sql_config_t *config);
30 static int sql_free_result(rlm_sql_handle_t *handle, rlm_sql_config_t *config);
31 static int sql_affected_rows(rlm_sql_handle_t *handle, rlm_sql_config_t *config);
32 static int sql_num_fields(rlm_sql_handle_t *handle, rlm_sql_config_t *config);
33 static int sql_finish_query(rlm_sql_handle_t *handle, rlm_sql_config_t *config);
34
35 /*************************************************************************
36  *
37  *      Function: sql_init_socket
38  *
39  *      Purpose: Establish connection to the db
40  *
41  *************************************************************************/
42 static int sql_init_socket(rlm_sql_handle_t *handle, rlm_sql_config_t *config) {
43     rlm_sql_firebird_sock *firebird_sock;
44     long res;
45
46
47     if (!handle->conn) {
48         handle->conn = (rlm_sql_firebird_sock *)rad_malloc(sizeof(rlm_sql_firebird_sock));
49         if (!handle->conn) return -1;
50     }
51
52     firebird_sock = handle->conn;
53
54     res=fb_init_socket(firebird_sock);
55     if (res)  return -1;
56
57     if (fb_connect(firebird_sock,config)) {
58      radlog(L_ERR, "rlm_sql_firebird: Connection failed %s\n", firebird_sock->lasterror);
59      return SQL_DOWN;
60     }
61
62     return 0;
63 }
64
65
66 /*************************************************************************
67  *
68  *      Function: sql_destroy_socket
69  *
70  *      Purpose: Free socket and private connection data
71  *
72  *************************************************************************/
73 static int sql_destroy_socket(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
74 {
75     free(handle->conn);
76     handle->conn = NULL;
77     return 0;
78 }
79
80
81 /*************************************************************************
82  *
83  *      Function: sql_query
84  *
85  *      Purpose: Issue a non-SELECT query (ie: update/delete/insert) to
86  *               the database.
87  *
88  *************************************************************************/
89
90 static int sql_query(rlm_sql_handle_t *handle, rlm_sql_config_t *config, char *querystr) {
91     rlm_sql_firebird_sock *firebird_sock = handle->conn;
92     int deadlock=0;
93
94 #ifdef _PTHREAD_H
95  pthread_mutex_lock(&firebird_sock->mut);
96 #endif
97
98 TryAgain:
99  if (fb_sql_query(firebird_sock,querystr)) {
100 //Try again query when deadlock, beacuse in any case it will be retried.
101 // but may be lost for short sessions
102    if ((firebird_sock->sql_code==DEADLOCK_SQL_CODE) && !deadlock) {
103       radlog(L_DBG,"sock_id deadlock. Retry query %s\n",querystr);
104 //For non READ_COMMITED transactions put rollback here
105 // fb_rollback(sock);
106       deadlock=1;
107       goto TryAgain;
108    }
109    radlog(L_ERR, "sock_id rlm_sql_firebird,sql_query error:sql_code=%li, error='%s', query=%s\n",
110      firebird_sock->sql_code,
111      firebird_sock->lasterror,
112      querystr);
113
114    if ((firebird_sock->sql_code==DOWN_SQL_CODE)) return SQL_DOWN;
115 //free problem query
116    if (fb_rollback(firebird_sock)) {
117     //assume the network is down if rollback had failed
118     radlog(L_ERR,"Fail to rollback transaction after previous error. Error: %s\n",
119        firebird_sock->lasterror);
120     return SQL_DOWN;
121    }
122 //   firebird_sock->in_use=0;
123    return -1;
124  }
125
126  if (firebird_sock->statement_type!=isc_info_sql_stmt_select) {
127     if (fb_commit(firebird_sock)) return -1;
128  }
129
130  return 0;
131 }
132
133
134 /*************************************************************************
135  *
136  *      Function: sql_select_query
137  *
138  *      Purpose: Issue a select query to the database
139  *
140  *************************************************************************/
141 static int sql_select_query(rlm_sql_handle_t *handle, rlm_sql_config_t *config, char *querystr) {
142 //    rlm_sql_firebird_sock *firebird_sock = handle->conn;
143     return (sql_query(handle, config, querystr));
144
145 }
146
147
148 /*************************************************************************
149  *
150  *      Function: sql_store_result
151  *
152  *      Purpose: database specific store_result function. Returns a result
153  *               set for the query.
154  *
155  *************************************************************************/
156 static int sql_store_result(rlm_sql_handle_t *handle, rlm_sql_config_t *config) {
157   /*   Not used   */
158     return 0;
159 }
160
161
162 /*************************************************************************
163  *
164  *      Function: sql_num_fields
165  *
166  *      Purpose: database specific num_fields function. Returns number
167  *               of columns from query
168  *
169  *************************************************************************/
170 static int sql_num_fields(rlm_sql_handle_t *handle, rlm_sql_config_t *config) {
171     return  ((rlm_sql_firebird_sock *) handle->conn)->sqlda_out->sqld;
172 }
173
174
175 /*************************************************************************
176  *
177  *      Function: sql_num_rows
178  *
179  *      Purpose: database specific num_rows. Returns number of rows in
180  *               query
181  *
182  *************************************************************************/
183 static int sql_num_rows(rlm_sql_handle_t *handle, rlm_sql_config_t *config) {
184     int res=sql_affected_rows(handle, config);
185     return res;
186 }
187
188
189 /*************************************************************************
190  *
191  *      Function: sql_fetch_row
192  *
193  *      Purpose: database specific fetch_row. Returns a rlm_sql_row_t struct
194  *               with all the data for the query in 'handle->row'. Returns
195  *               0 on success, -1 on failure, SQL_DOWN if 'database is down'.
196  *
197  *************************************************************************/
198 static int sql_fetch_row(rlm_sql_handle_t *handle, rlm_sql_config_t *config) {
199     rlm_sql_firebird_sock *firebird_sock = handle->conn;
200     int res;
201
202     handle->row = NULL;
203     if (firebird_sock->statement_type!=isc_info_sql_stmt_exec_procedure) {
204      res=fb_fetch(firebird_sock);
205      if (res==100) return 0;
206      if (res) {
207        radlog(L_ERR, "rlm_sql_firebird. Fetch problem:'%s'\n", firebird_sock->lasterror);
208        return -1;
209      }
210     } else firebird_sock->statement_type=0;
211     fb_store_row(firebird_sock);
212
213     handle->row = firebird_sock->row;
214     return 0;
215 }
216
217
218 /*************************************************************************
219  *
220  *      Function: sql_finish_select_query
221  *
222  *      Purpose: End the select query, such as freeing memory or result
223  *
224  *************************************************************************/
225 static int sql_finish_select_query(rlm_sql_handle_t * handle, rlm_sql_config_t *config) {
226     rlm_sql_firebird_sock *sock=(rlm_sql_firebird_sock *) handle->conn;
227     fb_commit(sock);
228     fb_close_cursor(sock);
229     return 0;
230 }
231
232 /*************************************************************************
233  *
234  *      Function: sql_finish_query
235  *
236  *      Purpose: End the query, such as freeing memory
237  *
238  *************************************************************************/
239 static int sql_finish_query(rlm_sql_handle_t *handle, rlm_sql_config_t *config) {
240 //    sql_free_result(handle,config);
241     return 0;
242 }
243
244 /*************************************************************************
245  *
246  *      Function: sql_free_result
247  *
248  *      Purpose: database specific free_result. Frees memory allocated
249  *               for a result set
250  *
251  *************************************************************************/
252 static int sql_free_result(rlm_sql_handle_t *handle, rlm_sql_config_t *config) {
253     return 0;
254 }
255
256 /*************************************************************************
257  *
258  *      Function: sql_close
259  *
260  *      Purpose: database specific close. Closes an open database
261  *               connection and cleans up any open handles.
262  *
263  *************************************************************************/
264 static int sql_close(rlm_sql_handle_t *handle, rlm_sql_config_t *config) {
265     fb_destroy_socket((rlm_sql_firebird_sock *) handle->conn);
266     return 0;
267 }
268
269 /*************************************************************************
270  *
271  *      Function: sql_error
272  *
273  *      Purpose: database specific error. Returns error associated with
274  *               connection
275  *
276  *************************************************************************/
277 static const char *sql_error(rlm_sql_handle_t *handle, rlm_sql_config_t *config) {
278     rlm_sql_firebird_sock *firebird_sock = handle->conn;
279     return firebird_sock->lasterror;
280 }
281 /*************************************************************************
282  *
283  *      Function: sql_affected_rows
284  *
285  *      Purpose: Return the number of rows affected by the query (update,
286  *               or insert)
287  *
288  *************************************************************************/
289 static int sql_affected_rows(rlm_sql_handle_t *handle, rlm_sql_config_t *config) {
290  int affected_rows=fb_affected_rows(handle->conn);
291  if (affected_rows<0)
292    radlog(L_ERR, "sql_affected_rows, rlm_sql_firebird. error:%s\n", sql_error(handle,config));
293  return affected_rows;
294 }
295
296 /* Exported to rlm_sql */
297 rlm_sql_module_t rlm_sql_firebird = {
298         "rlm_sql_firebird",
299         sql_init_socket,
300         sql_destroy_socket,
301         sql_query,
302         sql_select_query,
303         sql_store_result,
304         sql_num_fields,
305         sql_num_rows,
306         sql_fetch_row,
307         sql_free_result,
308         sql_error,
309         sql_close,
310         sql_finish_query,
311         sql_finish_select_query,
312         sql_affected_rows
313 };