25 RCSID(
"$Id: 51cd8ff821b7cf12459aa663f263f9b9039355c4 $")
27 #define LOG_PREFIX "sql - sqlite"
28 #include <freeradius-devel/server/base.h>
29 #include <freeradius-devel/util/debug.h>
40 #define BOOTSTRAP_MAX (1048576 * 10)
45 #ifndef SQLITE_OPEN_NOMUTEX
46 # define SQLITE_OPEN_NOMUTEX 0
49 #ifndef HAVE_SQLITE3_INT64
84 switch (status & 0xff) {
104 case SQLITE_CONSTRAINT:
127 int hstatus = SQLITE_OK;
130 hstatus = sqlite3_errcode(db);
131 switch (hstatus & 0xff) {
143 switch (status & 0xff) {
177 int hstatus = SQLITE_OK;
180 hstatus = sqlite3_errcode(db);
181 switch (hstatus & 0xff) {
193 switch (status & 0xff) {
207 if ((hstatus == SQLITE_OK) && (status == SQLITE_OK))
return;
213 MEM(p = talloc_vasprintf(NULL,
fmt, ap));
220 if ((status != SQLITE_OK) && (status != hstatus)) {
221 ERROR(
"%s: Code 0x%04x (%i): %s", p, status, status, sqlite3_errstr(status));
224 if (hstatus != SQLITE_OK)
ERROR(
"%s: Code 0x%04x (%i): %s",
225 p, hstatus, hstatus, sqlite3_errmsg(db));
228 static int sql_loadfile(TALLOC_CTX *ctx, sqlite3 *db,
char const *filename)
231 int statement_len, statement_cnt = 0;
239 sqlite3_stmt *statement;
242 INFO(
"Executing SQL statements from file \"%s\"", filename);
244 f = fopen(filename,
"r");
246 ERROR(
"Failed opening SQL file \"%s\": %s", filename,
252 if (fstat(fileno(f), &finfo) < 0) {
253 ERROR(
"Failed stating SQL file \"%s\": %s", filename,
263 ERROR(
"Size of SQL (%zu) file exceeds limit (%uk)",
271 MEM(
buffer = talloc_array(ctx,
char, finfo.st_size + 1));
272 len = fread(
buffer,
sizeof(
char), finfo.st_size, f);
273 if (len > finfo.st_size) {
288 DEBUG(
"Ignoring empty SQL file");
304 if ((*p != 0x0a) && (*p != 0x0d) && (*p !=
'\t'))
break;
312 if ((p -
buffer) != len) {
313 ERROR(
"Bootstrap file contains non-UTF8 char at offset %zu", p -
buffer);
320 statement_len = len - (p -
buffer);
321 status = sqlite3_prepare_v2(db, p, statement_len, &statement, &z_tail);
324 sql_print_error(db, status,
"Failed preparing statement %i", statement_cnt);
332 if (!statement)
break;
334 status = sqlite3_step(statement);
336 sql_print_error(db, status,
"Failed executing statement %i", statement_cnt);
337 sqlite3_finalize(statement);
342 status = sqlite3_finalize(statement);
344 sql_print_error(db, status,
"Failed finalizing statement %i", statement_cnt);
357 static void _sql_greatest(sqlite3_context *ctx,
int num_values, sqlite3_value **values)
362 for (i = 0; i < num_values; i++) {
363 value = sqlite3_value_int64(values[i]);
369 sqlite3_result_int64(ctx, max);
383 INFO(
"Opening SQLite database \"%s\"",
inst->filename);
388 if (!
inst->bootstrap) {
389 INFO(
"Use the sqlite driver 'bootstrap' option to automatically create the database file");
404 status = sqlite3_extended_result_codes(c->
db, 1);
410 status = sqlite3_create_function_v2(c->
db,
"GREATEST", -1, SQLITE_ANY, NULL,
427 DEBUG2(
"Socket destructor called, closing socket");
430 status = sqlite3_close(c->
db);
431 if (status != SQLITE_OK)
WARN(
"Got SQLite error when closing socket: %s",
432 sqlite3_errmsg(c->
db));
443 fields = sqlite3_column_count(conn->
statement);
446 MEM(
names = talloc_array(query_ctx,
char const *, fields));
448 for (i = 0; i < fields; i++)
names[i] = sqlite3_column_name(conn->
statement, i);
461 TALLOC_FREE(query_ctx->
row);
480 if (status == SQLITE_DONE) {
497 MEM(row = query_ctx->
row = talloc_zero_array(query_ctx,
char *, conn->
col_count + 1));
500 switch (sqlite3_column_type(conn->
statement, i)) {
512 p = (
char const *) sqlite3_column_text(conn->
statement, i);
523 p = sqlite3_column_blob(conn->
statement, i);
525 len = sqlite3_column_bytes(conn->
statement, i);
527 MEM(row[i] = talloc_zero_array(row,
char, len + 1));
528 memcpy(row[i], p, len);
547 TALLOC_FREE(query_ctx->
row);
549 (void) sqlite3_finalize(conn->
statement);
583 error = sqlite3_errmsg(conn->
db);
584 if (!error)
return 0;
602 if (conn->
db)
return sqlite3_changes(conn->
db);
625 query_ctx->
tconn = tconn;
639 status = sqlite3_step(sql_conn->
statement);
654 query_ctx->
treq = NULL;
675 if (!
inst->filename) {
688 }
else if (fstatat(fd, r, &buf, 0) == 0) {
690 }
else if (errno == ENOENT) {
699 inst->bootstrap =
true;
702 if (
inst->bootstrap && !exists) {
710 INFO(
"Database \"%s\" doesn't exist, creating it and loading schema",
inst->filename);
712 p = strrchr(
inst->filename,
'/');
714 size_t len = (p -
inst->filename) + 1;
716 buff = talloc_array(mctx->
mi->
conf,
char, len);
725 PERROR(
"Failed creating directory for SQLite database");
731 status = sqlite3_open_v2(
inst->filename, &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
733 ERROR(
"Failed creating opening/creating SQLite database: %s",
734 sqlite3_errstr(status));
739 (void) sqlite3_close(db);
755 (void) sqlite3_close(db);
760 status = sqlite3_close(db);
761 if (status != SQLITE_OK) {
765 ERROR(
"Error closing SQLite handle: %s", sqlite3_errstr(status));
771 if ((unlinkat(fd, r, 0) < 0) && (errno != ENOENT)) {
772 ERROR(
"Error removing partially initialised database: %s",
786 if (sqlite3_libversion_number() != SQLITE_VERSION_NUMBER) {
787 WARN(
"libsqlite version changed since the server was built");
788 WARN(
"linked: %s built: %s", sqlite3_libversion(), SQLITE_VERSION);
790 INFO(
"libsqlite version: %s", sqlite3_libversion());
799 .name =
"sql_sqlite",
807 .sql_query_resume = sql_query_resume,
808 .sql_select_query_resume = sql_query_resume,
818 .connection_alloc = sql_trunk_connection_alloc,
819 .request_mux = sql_trunk_request_mux,
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
static int const char char buffer[256]
static int const char * fmt
#define CONF_PARSER_TERMINATOR
#define FR_CONF_OFFSET_FLAGS(_name, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
@ CONF_FLAG_REQUIRED
Error out if no matching CONF_PAIR is found, and no dflt value is set.
@ CONF_FLAG_FILE_OUTPUT
File matching value must exist, and must be writable.
Defines a CONF_PAIR to C data type mapping.
Configuration AVP similar to a fr_pair_t.
CONF_PAIR * cf_pair_find(CONF_SECTION const *cs, char const *attr)
Search for a CONF_PAIR with a specific name.
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
CONF_PAIR * cf_pair_find_next(CONF_SECTION const *cs, CONF_PAIR const *prev, char const *attr)
Find a pair with a name matching attr, after specified pair.
@ CONNECTION_STATE_FAILED
Connection has failed.
@ CONNECTION_STATE_CONNECTED
File descriptor is open (ready for writing).
fr_dcursor_eval_t void const * uctx
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
ssize_t fr_mkdir(int *fd_out, char const *path, ssize_t len, mode_t mode, fr_mkdir_func_t func, void *uctx)
Create directories that are missing in the specified path.
int fr_dirfd(int *dirfd, char const **filename, char const *pathname)
From a pathname, return fd and filename needed for *at() functions.
#define ROPTIONAL(_l_request, _l_global, _fmt,...)
Use different logging functions depending on whether request is NULL or not.
Stores all information relating to an event list.
main_config_t const * main_config
Main server configuration.
char const * raddb_dir
Path to raddb directory.
module_instance_t * mi
Instance of the module being instantiated.
Temporary structure to hold arguments for instantiation calls.
size_t fr_utf8_char(uint8_t const *str, ssize_t inlen)
Checks for utf-8, taken from http://www.w3.org/International/questions/qa-forms-utf-8.
static const conf_parser_t config[]
rlm_rcode_t
Return codes indicating the result of the module call.
static int instantiate(module_inst_ctx_t const *mctx)
Prototypes and functions for the SQL module.
fr_sql_query_status_t status
Status of the query.
trunk_connection_t * tconn
Trunk connection this query is being run on.
fr_sql_query_type_t type
Type of query.
char const * query_str
Query string to run.
request_t * request
Request this query relates to.
sql_rcode_t
Action to take at end of an SQL query.
@ RLM_SQL_ALT_QUERY
Key constraint violation, use an alternative query.
@ RLM_SQL_RECONNECT
Stale connection, should reconnect.
@ RLM_SQL_ERROR
General connection/server error.
@ RLM_SQL_NO_MORE_ROWS
No more rows available.
#define RLM_SQL_RCODE_FLAGS_ALT_QUERY
Can distinguish between other errors and those.
rlm_sql_row_t row
Row data from the last query.
sql_rcode_t rcode
Result code.
trunk_request_t * treq
Trunk request for this query.
@ SQL_QUERY_FAILED
Failed to submit.
static void sql_request_complete(UNUSED request_t *request, void *preq, UNUSED void *rctx, UNUSED void *uctx)
static size_t sql_error(UNUSED TALLOC_CTX *ctx, sql_log_entry_t out[], NDEBUG_UNUSED size_t outlen, fr_sql_query_t *query_ctx)
Retrieves any errors associated with the query context.
sqlite_int64 sqlite3_int64
static int mod_load(void)
static sql_rcode_t sql_fields(char const **out[], fr_sql_query_t *query_ctx, UNUSED rlm_sql_config_t const *config)
static void sql_print_error(sqlite3 *db, int status, char const *fmt,...))
Print an error to the global debug log.
rlm_sql_driver_t rlm_sql_sqlite
static int sql_loadfile(TALLOC_CTX *ctx, sqlite3 *db, char const *filename)
static unlang_action_t sql_fetch_row(rlm_rcode_t *p_result, UNUSED int *priority, UNUSED request_t *request, void *uctx)
static void _sql_connection_close(UNUSED fr_event_list_t *el, void *h, UNUSED void *uctx)
static const conf_parser_t driver_config[]
static sql_rcode_t sql_error_to_rcode(int status)
Convert an sqlite status code to an sql_rcode_t.
#define SQLITE_OPEN_NOMUTEX
static SQL_QUERY_RESUME void sql_request_fail(UNUSED request_t *request, void *preq, UNUSED void *rctx, UNUSED trunk_request_state_t state, UNUSED void *uctx)
static sql_rcode_t sql_finish_query(fr_sql_query_t *query_ctx, rlm_sql_config_t const *config)
static sql_rcode_t sql_free_result(fr_sql_query_t *query_ctx, UNUSED rlm_sql_config_t const *config)
static int sql_affected_rows(fr_sql_query_t *query_ctx, UNUSED rlm_sql_config_t const *config)
static int mod_instantiate(module_inst_ctx_t const *mctx)
static sql_rcode_t sql_check_error(sqlite3 *db, int status)
Determine if an error occurred, and what type of error it was.
static void _sql_greatest(sqlite3_context *ctx, int num_values, sqlite3_value **values)
Macros to reduce boilerplate in trunk SQL drivers.
#define SQL_TRUNK_CONNECTION_ALLOC
Allocate an SQL trunk connection.
CONF_SECTION * conf
Module's instance configuration.
void * data
Module's instance data.
module_instance_t const * parent
Parent module's instance (if any).
static char buff[sizeof("18446744073709551615")+3]
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
eap_aka_sim_process_conf_t * inst
size_t strlcpy(char *dst, char const *src, size_t siz)
module_t common
Common fields for all loadable modules.
module_instance_t * driver_submodule
Driver's submodule.
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
char * talloc_typed_strdup(TALLOC_CTX *ctx, char const *p)
Call talloc_strdup, setting the type on the new chunk correctly.
char * talloc_typed_asprintf(TALLOC_CTX *ctx, char const *fmt,...)
Call talloc vasprintf, setting the type on the new chunk correctly.
#define talloc_get_type_abort_const
static const char * names[8]
static int64_t fr_time_delta_to_sec(fr_time_delta_t delta)
void trunk_request_signal_fail(trunk_request_t *treq)
Signal that a trunk request failed.
int trunk_connection_pop_request(trunk_request_t **treq_out, trunk_connection_t *tconn)
Pop a request off a connection's pending queue.
void trunk_request_signal_reapable(trunk_request_t *treq)
Signal that the request was written to a connection successfully, but no response is expected.
Associates request queues with a connection.
trunk_request_state_t
Used for sanity checks and to simplify freeing.
static fr_event_list_t * el
int format(printf, 5, 0))
static size_t char ** out