The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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 RCSID("$Id: dcc25145d12f04e9a648369d753979427c685532 $")
22 
23 #define LOG_PREFIX "sql - firebird"
24 
25 #include "sql_fbapi.h"
26 #include <freeradius-devel/util/debug.h>
27 
28 
29 /* Forward declarations */
34 
36 {
37  int i;
38 
39  DEBUG2("socket destructor called, closing socket");
40 
41  fb_commit(conn);
42  if (conn->dbh) {
43  fb_free_statement(conn);
44  isc_detach_database(conn->status, &(conn->dbh));
45 
46  if (fb_error(conn)) {
47  WARN("Got error "
48  "when closing socket: %s", conn->error);
49  }
50  }
51 
52  pthread_mutex_destroy (&conn->mut);
53 
54  for (i = 0; i < conn->row_fcount; i++) free(conn->row[i]);
55 
56  free(conn->row);
57  free(conn->row_sizes);
58  fb_free_sqlda(conn->sqlda_out);
59 
60  free(conn->sqlda_out);
61  free(conn->tpb);
62  free(conn->dpb);
63 
64  return 0;
65 }
66 
67 /** Establish connection to the db
68  *
69  */
72 {
74 
75  long res;
76 
77  MEM(conn = handle->conn = talloc_zero(handle, rlm_sql_firebird_conn_t));
78  talloc_set_destructor(conn, _sql_socket_destructor);
79 
80  res = fb_init_socket(conn);
81  if (res) return RLM_SQL_ERROR;
82 
83  if (fb_connect(conn, config)) {
84  ERROR("Connection failed: %s", conn->error);
85 
86  return RLM_SQL_RECONNECT;
87  }
88 
89  return 0;
90 }
91 
92 /** Issue a non-SELECT query (ie: update/delete/insert) to the database.
93  *
94  */
95 static sql_rcode_t sql_query(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t const *config, char const *query)
96 {
97  rlm_sql_firebird_conn_t *conn = handle->conn;
98 
99  int deadlock = 0;
100 
101  pthread_mutex_lock(&conn->mut);
102 
103  try_again:
104  /*
105  * Try again query when deadlock, because in any case it
106  * will be retried.
107  */
108  if (fb_sql_query(conn, query)) {
109  /* but may be lost for short sessions */
110  if ((conn->sql_code == DEADLOCK_SQL_CODE) &&
111  !deadlock) {
112  DEBUG("conn_id deadlock. Retry query %s", query);
113 
114  /*
115  * @todo For non READ_COMMITED transactions put
116  * rollback here
117  * fb_rollback(conn);
118  */
119  deadlock = 1;
120  goto try_again;
121  }
122 
123  ERROR("conn_id rlm_sql_firebird,sql_query error: sql_code=%li, error='%s', query=%s",
124  (long int) conn->sql_code, conn->error, query);
125 
126  if (conn->sql_code == DOWN_SQL_CODE) {
127  pthread_mutex_unlock(&conn->mut);
128 
129  return RLM_SQL_RECONNECT;
130  }
131 
132  /* Free problem query */
133  if (fb_rollback(conn)) {
134  //assume the network is down if rollback had failed
135  ERROR("Fail to rollback transaction after previous error: %s", conn->error);
136 
137  return RLM_SQL_RECONNECT;
138  }
139  // conn->in_use=0;
140 
141  return RLM_SQL_ERROR;
142  }
143 
144  if (conn->statement_type != isc_info_sql_stmt_select) {
145  if (fb_commit(conn)) return RLM_SQL_ERROR; /* fb_commit unlocks the mutex */
146  } else {
147  pthread_mutex_unlock(&conn->mut);
148  }
149 
150  return 0;
151 }
152 
153 /** Issue a select query to the database.
154  *
155  */
156 static sql_rcode_t sql_select_query(rlm_sql_handle_t *handle, rlm_sql_config_t const *config, char const *query)
157 {
158  return sql_query(handle, config, query);
159 }
160 
161 /** Returns number of columns from query.
162  *
163  */
165 {
166  return ((rlm_sql_firebird_conn_t *) handle->conn)->sqlda_out->sqld;
167 }
168 
169 /** Returns number of rows in query.
170  *
171  */
173 {
174  return sql_affected_rows(handle, config);
175 }
176 
177 /** Returns name of fields.
178  *
179  */
180 static sql_rcode_t sql_fields(char const **out[], rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t const *config)
181 {
182  rlm_sql_firebird_conn_t *conn = handle->conn;
183 
184  int fields, i;
185  char const **names;
186 
187  fields = conn->sqlda_out->sqld;
188  if (fields <= 0) return RLM_SQL_ERROR;
189 
190  MEM(names = talloc_array(handle, char const *, fields));
191 
192  for (i = 0; i < fields; i++) names[i] = conn->sqlda_out->sqlvar[i].sqlname;
193  *out = names;
194 
195  return RLM_SQL_OK;
196 }
197 
198 /** Returns an individual row.
199  *
200  */
202 {
203  rlm_sql_firebird_conn_t *conn = handle->conn;
204  int res;
205 
206  *out = NULL;
207  handle->row = NULL;
208 
209  if (conn->statement_type != isc_info_sql_stmt_exec_procedure) {
210  res = fb_fetch(conn);
211  if (res == 100) return RLM_SQL_NO_MORE_ROWS;
212 
213  if (res) {
214  ERROR("Fetch problem: %s", conn->error);
215 
216  return RLM_SQL_ERROR;
217  }
218  } else {
219  conn->statement_type = 0;
220  }
221 
222  fb_store_row(conn);
223 
224  *out = handle->row = conn->row;
225 
226  return RLM_SQL_OK;
227 }
228 
229 /** End the select query, such as freeing memory or result.
230  *
231  */
233 {
235 
236  fb_commit(conn);
237  fb_close_cursor(conn);
238 
239  return 0;
240 }
241 
242 /** End the query
243  *
244  */
246 {
247  return 0;
248 }
249 
250 /** Frees memory allocated for a result set.
251  *
252  */
254 {
255  return 0;
256 }
257 
258 /** Retrieves any errors associated with the connection handle
259  *
260  * @note Caller will free any memory allocated in ctx.
261  *
262  * @param ctx to allocate temporary error buffers in.
263  * @param out Array of sql_log_entrys to fill.
264  * @param outlen Length of out array.
265  * @param handle rlm_sql connection handle.
266  * @param config rlm_sql config.
267  * @return number of errors written to the #sql_log_entry_t array.
268  */
269 static size_t sql_error(UNUSED TALLOC_CTX *ctx, sql_log_entry_t out[], NDEBUG_UNUSED size_t outlen,
271 {
272  rlm_sql_firebird_conn_t *conn = handle->conn;
273 
274  fr_assert(conn);
275  fr_assert(outlen > 0);
276 
277  if (!conn->error) return 0;
278 
279  out[0].type = L_ERR;
280  out[0].msg = conn->error;
281 
282  return 1;
283 }
284 
285 /** Return the number of rows affected by the query (update, or insert)
286  *
287  */
289 {
290  return fb_affected_rows(handle->conn);
291 }
292 
293 /* Exported to rlm_sql */
296  .common = {
297  .name = "sql_firebird",
298  .magic = MODULE_MAGIC_INIT
299  },
300  .number = 9,
301  .sql_socket_init = sql_socket_init,
302  .sql_query = sql_query,
303  .sql_select_query = sql_select_query,
304  .sql_num_fields = sql_num_fields,
305  .sql_num_rows = sql_num_rows,
306  .sql_affected_rows = sql_affected_rows,
307  .sql_fetch_row = sql_fetch_row,
308  .sql_fields = sql_fields,
309  .sql_free_result = sql_free_result,
310  .sql_error = sql_error,
311  .sql_finish_query = sql_finish_query,
312  .sql_finish_select_query = sql_finish_select_query
313 };
#define RCSID(id)
Definition: build.h:444
#define NDEBUG_UNUSED
Definition: build.h:324
#define UNUSED
Definition: build.h:313
#define ERROR(fmt,...)
Definition: dhcpclient.c:41
#define DEBUG(fmt,...)
Definition: dhcpclient.c:39
static fr_time_delta_t timeout
Definition: dhcpclient.c:54
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition: dl_module.h:65
free(array)
@ L_ERR
Error message.
Definition: log.h:56
static const conf_parser_t config[]
Definition: base.c:188
#define DEBUG2(fmt,...)
Definition: radclient.h:43
#define WARN(fmt,...)
Definition: radclient.h:47
void * conn
Database specific connection handle.
Definition: rlm_sql.h:101
sql_rcode_t
Action to take at end of an SQL query.
Definition: rlm_sql.h:42
@ RLM_SQL_RECONNECT
Stale connection, should reconnect.
Definition: rlm_sql.h:46
@ RLM_SQL_ERROR
General connection/server error.
Definition: rlm_sql.h:44
@ RLM_SQL_OK
Success.
Definition: rlm_sql.h:45
@ RLM_SQL_NO_MORE_ROWS
No more rows available.
Definition: rlm_sql.h:48
char ** rlm_sql_row_t
Definition: rlm_sql.h:57
rlm_sql_row_t row
Row data from the last query.
Definition: rlm_sql.h:102
Definition: rlm_sql.h:59
rlm_sql_driver_t rlm_sql_firebird
static sql_rcode_t sql_free_result(rlm_sql_handle_t *handle, rlm_sql_config_t const *config)
static int _sql_socket_destructor(rlm_sql_firebird_conn_t *conn)
static sql_rcode_t sql_finish_query(rlm_sql_handle_t *handle, rlm_sql_config_t const *config)
static sql_rcode_t sql_fetch_row(rlm_sql_row_t *out, rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t const *config)
Returns an individual row.
static int sql_num_rows(rlm_sql_handle_t *handle, rlm_sql_config_t const *config)
Returns number of rows in query.
static int sql_num_fields(rlm_sql_handle_t *handle, rlm_sql_config_t const *config)
static int sql_affected_rows(rlm_sql_handle_t *handle, rlm_sql_config_t const *config)
static sql_rcode_t sql_finish_select_query(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t const *config)
End the select query, such as freeing memory or result.
static sql_rcode_t sql_query(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t const *config, char const *query)
Issue a non-SELECT query (ie: update/delete/insert) to the database.
static sql_rcode_t sql_select_query(rlm_sql_handle_t *handle, rlm_sql_config_t const *config, char const *query)
Issue a select query to the database.
static sql_rcode_t sql_socket_init(rlm_sql_handle_t *handle, rlm_sql_config_t const *config, UNUSED fr_time_delta_t timeout)
Establish connection to the db.
static sql_rcode_t sql_fields(char const **out[], rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t const *config)
Returns name of fields.
static size_t sql_error(UNUSED TALLOC_CTX *ctx, sql_log_entry_t out[], NDEBUG_UNUSED size_t outlen, rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t const *config)
Retrieves any errors associated with the connection handle.
int fb_init_socket(rlm_sql_firebird_conn_t *conn)
Definition: sql_fbapi.c:322
int fb_sql_query(rlm_sql_firebird_conn_t *conn, char const *query)
Definition: sql_fbapi.c:479
void fb_store_row(rlm_sql_firebird_conn_t *conn)
Definition: sql_fbapi.c:149
int fb_connect(rlm_sql_firebird_conn_t *conn, rlm_sql_config_t const *config)
Definition: sql_fbapi.c:345
int fb_rollback(rlm_sql_firebird_conn_t *conn)
Definition: sql_fbapi.c:544
int fb_error(rlm_sql_firebird_conn_t *conn)
Definition: sql_fbapi.c:81
int fb_fetch(rlm_sql_firebird_conn_t *conn)
Definition: sql_fbapi.c:399
int fb_close_cursor(rlm_sql_firebird_conn_t *conn)
Definition: sql_fbapi.c:531
void fb_free_sqlda(XSQLDA *sqlda)
Definition: sql_fbapi.c:127
int fb_commit(rlm_sql_firebird_conn_t *conn)
Definition: sql_fbapi.c:558
int fb_affected_rows(rlm_sql_firebird_conn_t *conn)
Definition: sql_fbapi.c:498
void fb_free_statement(rlm_sql_firebird_conn_t *conn)
Definition: sql_fbapi.c:537
#define DEADLOCK_SQL_CODE
Definition: sql_fbapi.h:33
#define DOWN_SQL_CODE
Definition: sql_fbapi.h:34
isc_db_handle dbh
Definition: sql_fbapi.h:45
ISC_STATUS status[20]
Magic interbase status code array (holds multiple error codes used to construct more detailed error m...
Definition: sql_fbapi.h:49
rlm_sql_row_t row
Definition: sql_fbapi.h:62
pthread_mutex_t mut
Definition: sql_fbapi.h:66
fr_assert(0)
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
module_t common
Common fields for all loadable modules.
Definition: rlm_sql.h:148
static const char * names[8]
Definition: time.c:617
A time delta, a difference in time measured in nanoseconds.
Definition: time.h:80
static size_t char ** out
Definition: value.h:984