All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
rlm_sql_firebird.c
Go to the documentation of this file.
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 RCSID("$Id: 27c7b7848f9529b92aa7dea44bf31fcb577a3347 $")
23 
24 #include "sql_fbapi.h"
25 #include <freeradius-devel/rad_assert.h>
26 
27 
28 /* Forward declarations */
30 static int sql_affected_rows(rlm_sql_handle_t *handle, rlm_sql_config_t *config);
31 static int sql_num_fields(rlm_sql_handle_t *handle, rlm_sql_config_t *config);
33 
35 {
36  int i;
37 
38  DEBUG2("rlm_sql_firebird: socket destructor called, closing socket");
39 
40  fb_commit(conn);
41  if (conn->dbh) {
42  fb_free_statement(conn);
43  isc_detach_database(conn->status, &(conn->dbh));
44 
45  if (fb_error(conn)) {
46  WARN("rlm_sql_firebird: Got error "
47  "when closing socket: %s", conn->error);
48  }
49  }
50 
51 #ifdef _PTHREAD_H
52  pthread_mutex_destroy (&conn->mut);
53 #endif
54 
55  for (i = 0; i < conn->row_fcount; i++) free(conn->row[i]);
56 
57  free(conn->row);
58  free(conn->row_sizes);
59  fb_free_sqlda(conn->sqlda_out);
60 
61  free(conn->sqlda_out);
62  free(conn->tpb);
63  free(conn->dpb);
64 
65  return 0;
66 }
67 
68 /** Establish connection to the db
69  *
70  */
72  UNUSED struct timeval const *timeout)
73 {
75 
76  long res;
77 
78  MEM(conn = handle->conn = talloc_zero(handle, rlm_sql_firebird_conn_t));
79  talloc_set_destructor(conn, _sql_socket_destructor);
80 
81  res = fb_init_socket(conn);
82  if (res) return RLM_SQL_ERROR;
83 
84  if (fb_connect(conn, config)) {
85  ERROR("rlm_sql_firebird: Connection failed: %s", conn->error);
86 
87  return RLM_SQL_RECONNECT;
88  }
89 
90  return 0;
91 }
92 
93 /** Issue a non-SELECT query (ie: update/delete/insert) to the database.
94  *
95  */
96 static sql_rcode_t sql_query(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config, char const *query)
97 {
98  rlm_sql_firebird_conn_t *conn = handle->conn;
99 
100  int deadlock = 0;
101 
102 #ifdef _PTHREAD_H
103  pthread_mutex_lock(&conn->mut);
104 #endif
105 
106  try_again:
107  /*
108  * Try again query when deadlock, beacuse in any case it
109  * will be retried.
110  */
111  if (fb_sql_query(conn, query)) {
112  /* but may be lost for short sessions */
113  if ((conn->sql_code == DEADLOCK_SQL_CODE) &&
114  !deadlock) {
115  DEBUG("conn_id deadlock. Retry query %s", query);
116 
117  /*
118  * @todo For non READ_COMMITED transactions put
119  * rollback here
120  * fb_rollback(conn);
121  */
122  deadlock = 1;
123  goto try_again;
124  }
125 
126  ERROR("conn_id rlm_sql_firebird,sql_query error: sql_code=%li, error='%s', query=%s",
127  (long int) conn->sql_code, conn->error, query);
128 
129  if (conn->sql_code == DOWN_SQL_CODE) {
130  reconnect:
131 #ifdef _PTHREAD_H
132  pthread_mutex_unlock(&conn->mut);
133 #endif
134  return RLM_SQL_RECONNECT;
135  }
136 
137  /* Free problem query */
138  if (fb_rollback(conn)) {
139  //assume the network is down if rollback had failed
140  ERROR("Fail to rollback transaction after previous error: %s", conn->error);
141 
142  goto reconnect;
143  }
144  // conn->in_use=0;
145  fail:
146 #ifdef _PTHREAD_H
147  pthread_mutex_unlock(&conn->mut);
148 #endif
149  return RLM_SQL_ERROR;
150  }
151 
152  if (conn->statement_type != isc_info_sql_stmt_select) {
153  if (fb_commit(conn)) goto fail;
154  }
155 
156 #ifdef _PTHREAD_H
157  pthread_mutex_unlock(&conn->mut);
158 #endif
159  return 0;
160 }
161 
162 /** Issue a select query to the database.
163  *
164  */
165 static sql_rcode_t sql_select_query(rlm_sql_handle_t *handle, rlm_sql_config_t *config, char const *query)
166 {
167  return sql_query(handle, config, query);
168 }
169 
170 /** Returns number of columns from query.
171  *
172  */
174 {
175  return ((rlm_sql_firebird_conn_t *) handle->conn)->sqlda_out->sqld;
176 }
177 
178 /** Returns number of rows in query.
179  *
180  */
181 static int sql_num_rows(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
182 {
183  return sql_affected_rows(handle, config);
184 }
185 
186 /** Returns name of fields.
187  *
188  */
189 static sql_rcode_t sql_fields(char const **out[], rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
190 {
191  rlm_sql_firebird_conn_t *conn = handle->conn;
192 
193  int fields, i;
194  char const **names;
195 
196  fields = conn->sqlda_out->sqld;
197  if (fields <= 0) return RLM_SQL_ERROR;
198 
199  MEM(names = talloc_array(handle, char const *, fields));
200 
201  for (i = 0; i < fields; i++) names[i] = conn->sqlda_out->sqlvar[i].sqlname;
202  *out = names;
203 
204  return RLM_SQL_OK;
205 }
206 
207 /** Returns an individual row.
208  *
209  */
211 {
212  rlm_sql_firebird_conn_t *conn = handle->conn;
213  int res;
214 
215  *out = NULL;
216  handle->row = NULL;
217 
218  if (conn->statement_type != isc_info_sql_stmt_exec_procedure) {
219  res = fb_fetch(conn);
220  if (res == 100) return RLM_SQL_OK;
221  if (res) {
222  ERROR("rlm_sql_firebird. Fetch problem: %s", conn->error);
223 
224  return RLM_SQL_ERROR;
225  }
226  } else {
227  conn->statement_type = 0;
228  }
229 
230  fb_store_row(conn);
231 
232  *out = handle->row = conn->row;
233 
234  return RLM_SQL_OK;
235 }
236 
237 /** End the select query, such as freeing memory or result.
238  *
239  */
241 {
243 
244  fb_commit(conn);
245  fb_close_cursor(conn);
246 
247  return 0;
248 }
249 
250 /** End the query
251  *
252  */
254 {
255  sql_free_result(handle, config);
256 
257  return 0;
258 }
259 
260 /** Frees memory allocated for a result set.
261  *
262  */
264 {
265  return 0;
266 }
267 
268 /** Retrieves any errors associated with the connection handle
269  *
270  * @note Caller will free any memory allocated in ctx.
271  *
272  * @param ctx to allocate temporary error buffers in.
273  * @param out Array of sql_log_entrys to fill.
274  * @param outlen Length of out array.
275  * @param handle rlm_sql connection handle.
276  * @param config rlm_sql config.
277  * @return number of errors written to the #sql_log_entry_t array.
278  */
279 static size_t sql_error(UNUSED TALLOC_CTX *ctx, sql_log_entry_t out[], size_t outlen,
280  rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
281 {
282  rlm_sql_firebird_conn_t *conn = handle->conn;
283 
284  rad_assert(conn);
285  rad_assert(outlen > 0);
286 
287  if (!conn->error) return 0;
288 
289  out[0].type = L_ERR;
290  out[0].msg = conn->error;
291 
292  return 1;
293 }
294 
295 /** Return the number of rows affected by the query (update, or insert)
296  *
297  */
299 {
300  return fb_affected_rows(handle->conn);
301 }
302 
303 /* Exported to rlm_sql */
305 rlm_sql_module_t rlm_sql_firebird = {
306  .name = "rlm_sql_firebird",
307  .sql_socket_init = sql_socket_init,
308  .sql_query = sql_query,
309  .sql_select_query = sql_select_query,
310  .sql_num_fields = sql_num_fields,
311  .sql_num_rows = sql_num_rows,
312  .sql_affected_rows = sql_affected_rows,
313  .sql_fetch_row = sql_fetch_row,
314  .sql_fields = sql_fields,
315  .sql_free_result = sql_free_result,
316  .sql_error = sql_error,
317  .sql_finish_query = sql_finish_query,
318  .sql_finish_select_query = sql_finish_select_query
319 };
static sql_rcode_t sql_fetch_row(rlm_sql_row_t *out, rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
Returns an individual row.
General connection/server error.
Definition: rlm_sql.h:46
static int sql_num_rows(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
Returns number of rows in query.
static sql_rcode_t sql_free_result(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
char ** rlm_sql_row_t
Definition: rlm_sql.h:59
log_type_t type
Type of log entry L_ERR, L_WARN, L_INFO, L_DBG etc..
Definition: rlm_sql.h:62
static sql_rcode_t sql_finish_select_query(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
End the select query, such as freeing memory or result.
#define MEM(x)
Definition: radiusd.h:396
char const * msg
Log message.
Definition: rlm_sql.h:63
int fb_sql_query(rlm_sql_firebird_conn_t *conn, char const *query)
Definition: sql_fbapi.c:484
#define UNUSED
Definition: libradius.h:134
Error message.
Definition: log.h:36
int fb_close_cursor(rlm_sql_firebird_conn_t *conn)
Definition: sql_fbapi.c:534
rlm_sql_row_t row
Definition: sql_fbapi.h:66
static float timeout
Definition: radclient.c:43
int fb_fetch(rlm_sql_firebird_conn_t *conn)
Definition: sql_fbapi.c:404
void fb_store_row(rlm_sql_firebird_conn_t *conn)
Definition: sql_fbapi.c:151
#define DEADLOCK_SQL_CODE
Definition: sql_fbapi.h:37
int fb_commit(rlm_sql_firebird_conn_t *conn)
Definition: sql_fbapi.c:563
int fb_init_socket(rlm_sql_firebird_conn_t *conn)
Definition: sql_fbapi.c:326
static sql_rcode_t sql_socket_init(rlm_sql_handle_t *handle, rlm_sql_config_t *config, UNUSED struct timeval const *timeout)
Establish connection to the db.
#define rad_assert(expr)
Definition: rad_assert.h:38
Stale connection, should reconnect.
Definition: rlm_sql.h:48
char const * name
Definition: rlm_sql.h:191
int fb_affected_rows(rlm_sql_firebird_conn_t *conn)
Definition: sql_fbapi.c:503
#define pthread_mutex_unlock(_x)
Definition: rlm_eap.h:78
int fb_connect(rlm_sql_firebird_conn_t *conn, rlm_sql_config_t *config)
Definition: sql_fbapi.c:350
#define DEBUG(fmt,...)
Definition: log.h:175
sql_rcode_t
Definition: rlm_sql.h:44
static sql_rcode_t sql_query(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config, char const *query)
Issue a non-SELECT query (ie: update/delete/insert) to the database.
#define DEBUG2(fmt,...)
Definition: log.h:176
static sql_rcode_t sql_fields(char const **out[], rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
Returns name of fields.
Definition: rlm_sql.h:61
static int sql_affected_rows(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
static sql_rcode_t sql_finish_query(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
End the query.
Success.
Definition: rlm_sql.h:47
void * conn
Database specific connection handle.
Definition: rlm_sql.h:153
void fb_free_sqlda(XSQLDA *sqlda)
Definition: sql_fbapi.c:129
#define DOWN_SQL_CODE
Definition: sql_fbapi.h:38
rlm_sql_row_t row
Row data from the last query.
Definition: rlm_sql.h:154
static sql_rcode_t sql_select_query(rlm_sql_handle_t *handle, rlm_sql_config_t *config, char const *query)
Issue a select query to the database.
static int sql_num_fields(rlm_sql_handle_t *handle, rlm_sql_config_t *config)
int fb_error(rlm_sql_firebird_conn_t *conn)
Definition: sql_fbapi.c:83
int fb_rollback(rlm_sql_firebird_conn_t *conn)
Definition: sql_fbapi.c:547
#define WARN(fmt,...)
Definition: log.h:144
void fb_free_statement(rlm_sql_firebird_conn_t *conn)
Definition: sql_fbapi.c:540
#define pthread_mutex_lock(_x)
Definition: rlm_eap.h:77
static int _sql_socket_destructor(rlm_sql_firebird_conn_t *conn)
static size_t sql_error(UNUSED TALLOC_CTX *ctx, sql_log_entry_t out[], size_t outlen, rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t *config)
Retrieves any errors associated with the connection handle.
#define pthread_mutex_destroy(_x)
Definition: rlm_eap.h:76
#define RCSID(id)
Definition: build.h:135
isc_db_handle dbh
Definition: sql_fbapi.h:49
ISC_STATUS status[20]
Magic interbase status code array (holds multiple error codes used to construct more detailed error m...
Definition: sql_fbapi.h:53
#define ERROR(fmt,...)
Definition: log.h:145
rlm_sql_module_t rlm_sql_firebird