import from HEAD:
[freeradius.git] / src / modules / rlm_sql / drivers / rlm_sql_firebird / 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
23 #include "sql_fbapi.h"
24
25
26 /* Forward declarations */
27 static char *sql_error(SQLSOCK *sqlsocket, SQL_CONFIG *config);
28 static int sql_free_result(SQLSOCK *sqlsocket, SQL_CONFIG *config);
29 static int sql_affected_rows(SQLSOCK *sqlsocket, SQL_CONFIG *config);
30 static int sql_num_fields(SQLSOCK *sqlsocket, SQL_CONFIG *config);
31 static int sql_finish_query(SQLSOCK *sqlsocket, SQL_CONFIG *config);
32
33 /*************************************************************************
34  *
35  *      Function: sql_init_socket
36  *
37  *      Purpose: Establish connection to the db
38  *
39  *************************************************************************/
40 static int sql_init_socket(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
41     rlm_sql_firebird_sock *firebird_sock;
42     long res;
43
44
45     if (!sqlsocket->conn) {
46         sqlsocket->conn = (rlm_sql_firebird_sock *)rad_malloc(sizeof(rlm_sql_firebird_sock));
47         if (!sqlsocket->conn) return -1;
48     }
49
50     firebird_sock = sqlsocket->conn;
51
52     res=fb_init_socket(firebird_sock);
53     if (res)  return -1;
54
55     if (fb_connect(firebird_sock,config)) {
56      radlog(L_ERR, "rlm_sql_firebird: Connection failed %s\n", firebird_sock->lasterror);
57      return SQL_DOWN;
58     }
59
60     return 0;
61 }
62
63
64 /*************************************************************************
65  *
66  *      Function: sql_destroy_socket
67  *
68  *      Purpose: Free socket and private connection data
69  *
70  *************************************************************************/
71 static int sql_destroy_socket(SQLSOCK *sqlsocket, SQL_CONFIG *config)
72 {
73     free(sqlsocket->conn);
74     sqlsocket->conn = NULL;
75     return 0;
76 }
77
78
79 /*************************************************************************
80  *
81  *      Function: sql_query
82  *
83  *      Purpose: Issue a non-SELECT query (ie: update/delete/insert) to
84  *               the database.
85  *
86  *************************************************************************/
87
88 static int sql_query(SQLSOCK *sqlsocket, SQL_CONFIG *config, char *querystr) {
89     rlm_sql_firebird_sock *firebird_sock = sqlsocket->conn;
90     int deadlock=0;
91  if (config->sqltrace)
92         radlog(L_DBG, "sock_id %i: query:  %s", sqlsocket->id,querystr);
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 %i: deadlock. Retry query %s\n",sqlsocket->id,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 %i: rlm_sql_firebird,sql_query error:sql_code=%i, error='%s', query=%s\n",
110      sqlsocket->id,
111      firebird_sock->sql_code,
112      firebird_sock->lasterror,
113      querystr);
114
115    if ((firebird_sock->sql_code==DOWN_SQL_CODE)) return SQL_DOWN;
116 //free problem query
117    if (fb_rollback(firebird_sock)) {
118     //assume the network is down if rollback had failed
119     radlog(L_ERR,"Fail to rollback transaction after previous error. Error: %s\n",
120        firebird_sock->lasterror);
121     return SQL_DOWN;
122    }
123 //   firebird_sock->in_use=0;
124    return -1;
125  }
126
127  if (firebird_sock->statement_type!=isc_info_sql_stmt_select) {
128     if (fb_commit(firebird_sock)) return -1;
129  }
130
131  return 0;
132 }
133
134
135 /*************************************************************************
136  *
137  *      Function: sql_select_query
138  *
139  *      Purpose: Issue a select query to the database
140  *
141  *************************************************************************/
142 static int sql_select_query(SQLSOCK *sqlsocket, SQL_CONFIG *config, char *querystr) {
143 //    rlm_sql_firebird_sock *firebird_sock = sqlsocket->conn;
144     return (sql_query(sqlsocket, config, querystr));
145
146 }
147
148
149 /*************************************************************************
150  *
151  *      Function: sql_store_result
152  *
153  *      Purpose: database specific store_result function. Returns a result
154  *               set for the query.
155  *
156  *************************************************************************/
157 static int sql_store_result(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
158   /*   Not used   */
159     return 0;
160 }
161
162
163 /*************************************************************************
164  *
165  *      Function: sql_num_fields
166  *
167  *      Purpose: database specific num_fields function. Returns number
168  *               of columns from query
169  *
170  *************************************************************************/
171 static int sql_num_fields(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
172     return  ((rlm_sql_firebird_sock *) sqlsocket->conn)->sqlda_out->sqld;
173 }
174
175
176 /*************************************************************************
177  *
178  *      Function: sql_num_rows
179  *
180  *      Purpose: database specific num_rows. Returns number of rows in
181  *               query
182  *
183  *************************************************************************/
184 static int sql_num_rows(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
185     int res=sql_affected_rows(sqlsocket, config);
186     radlog(L_DBG,"sock_id %i: sql_num_rows: %i\n",sqlsocket->id,res);
187     return res;
188 }
189
190
191 /*************************************************************************
192  *
193  *      Function: sql_fetch_row
194  *
195  *      Purpose: database specific fetch_row. Returns a SQL_ROW struct
196  *               with all the data for the query in 'sqlsocket->row'. Returns
197  *               0 on success, -1 on failure, SQL_DOWN if 'database is down'.
198  *
199  *************************************************************************/
200 static int sql_fetch_row(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
201     rlm_sql_firebird_sock *firebird_sock = sqlsocket->conn;
202     int res;
203
204     sqlsocket->row = NULL;
205     if (firebird_sock->statement_type!=isc_info_sql_stmt_exec_procedure) {
206      res=fb_fetch(firebird_sock);
207      if (res==100) return 0;
208      if (res) {
209        radlog(L_ERR, "rlm_sql_firebird. Fetch problem:'%s'\n", firebird_sock->lasterror);
210        return -1;
211      }
212     } else firebird_sock->statement_type=0;
213     fb_store_row(firebird_sock);
214
215     sqlsocket->row = firebird_sock->row;
216     return 0;
217 }
218
219
220 /*************************************************************************
221  *
222  *      Function: sql_finish_select_query
223  *
224  *      Purpose: End the select query, such as freeing memory or result
225  *
226  *************************************************************************/
227 static int sql_finish_select_query(SQLSOCK * sqlsocket, SQL_CONFIG *config) {
228     rlm_sql_firebird_sock *sock=(rlm_sql_firebird_sock *) sqlsocket->conn;
229     fb_commit(sock);
230     fb_close_cursor(sock);
231     return 0;
232 }
233
234 /*************************************************************************
235  *
236  *      Function: sql_finish_query
237  *
238  *      Purpose: End the query, such as freeing memory
239  *
240  *************************************************************************/
241 static int sql_finish_query(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
242 //    sql_free_result(sqlsocket,config);
243     return 0;
244 }
245
246 /*************************************************************************
247  *
248  *      Function: sql_free_result
249  *
250  *      Purpose: database specific free_result. Frees memory allocated
251  *               for a result set
252  *
253  *************************************************************************/
254 static int sql_free_result(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
255     return 0;
256 }
257
258 /*************************************************************************
259  *
260  *      Function: sql_close
261  *
262  *      Purpose: database specific close. Closes an open database
263  *               connection and cleans up any open handles.
264  *
265  *************************************************************************/
266 static int sql_close(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
267 //    radlog(L_INFO,"Closing sql\n");
268     fb_destroy_socket((rlm_sql_firebird_sock *) sqlsocket->conn);
269     return 0;
270 }
271
272 /*************************************************************************
273  *
274  *      Function: sql_error
275  *
276  *      Purpose: database specific error. Returns error associated with
277  *               connection
278  *
279  *************************************************************************/
280 static char *sql_error(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
281     rlm_sql_firebird_sock *firebird_sock = sqlsocket->conn;
282     return firebird_sock->lasterror;
283 }
284 /*************************************************************************
285  *
286  *      Function: sql_affected_rows
287  *
288  *      Purpose: Return the number of rows affected by the query (update,
289  *               or insert)
290  *
291  *************************************************************************/
292 static int sql_affected_rows(SQLSOCK *sqlsocket, SQL_CONFIG *config) {
293  int affected_rows=fb_affected_rows(sqlsocket->conn);
294  if (affected_rows<0)
295    radlog(L_ERR, "sql_affected_rows, rlm_sql_firebird. error:%s\n", sql_error(sqlsocket,config));
296  radlog(L_DBG,"sock_id %i: affected_rows: %i\n",sqlsocket->id,affected_rows);
297  return affected_rows;
298 }
299
300 /* Exported to rlm_sql */
301 rlm_sql_module_t rlm_sql_firebird = {
302         "rlm_sql_firebird",
303         sql_init_socket,
304         sql_destroy_socket,
305         sql_query,
306         sql_select_query,
307         sql_store_result,
308         sql_num_fields,
309         sql_num_rows,
310         sql_fetch_row,
311         sql_free_result,
312         sql_error,
313         sql_close,
314         sql_finish_query,
315         sql_finish_select_query,
316         sql_affected_rows
317 };