58 static int has_explicit_like_escaping;
84 REALTIME_SQLITE3_REQ_WARN,
85 REALTIME_SQLITE3_REQ_CLOSE,
86 REALTIME_SQLITE3_REQ_CHAR,
97 unsigned int requirements:2;
100 unsigned int exiting:1;
101 unsigned int wakeup:1;
102 unsigned int has_batch_thread:1;
110 AST_MUTEX_DEFINE_STATIC(config_lock);
117 typedef int (*callback_t)(
void*, int,
char **,
char **);
119 static int realtime_sqlite3_exec_query_with_handle(
struct realtime_sqlite3_db *,
const char *, callback_t,
void *);
120 static int realtime_sqlite3_exec_query(
const char *,
const char *, callback_t,
void *);
121 static int realtime_sqlite3_exec_update_with_handle(
struct realtime_sqlite3_db *,
const char *);
122 static int realtime_sqlite3_exec_update(
const char *,
const char *);
127 static inline const char *sqlite3_escape_string_helper(
struct ast_threadstorage *ts,
const char *param)
129 size_t maxlen = strlen(param) * 2 +
sizeof(
"\"\"");
135 char q = ts == &escape_value_buf ?
'\'' :
'"';
140 ast_str_make_space(&buf, maxlen);
146 while ((*tmp++ = *param++)) {
148 if (*(tmp - 1) == q) {
159 static inline const char *sqlite3_escape_table(
const char *param)
161 return sqlite3_escape_string_helper(&escape_table_buf, param);
164 static inline const char *sqlite3_escape_column(
const char *param)
166 return sqlite3_escape_string_helper(&escape_column_buf, param);
170 static const char *sqlite3_escape_column_op(
const char *param)
172 size_t maxlen = strlen(param) * 2 +
sizeof(
"\"\" =");
179 ast_str_make_space(&buf, maxlen);
185 while ((*tmp++ = *param++)) {
192 if (*(tmp - 1) ==
' ') {
196 }
else if (*(tmp - 1) ==
'"') {
201 strcpy(tmp - 1,
"\" =");
209 static inline const char *sqlite3_escape_value(
const char *param)
211 return sqlite3_escape_string_helper(&escape_value_buf, param);
214 static int db_hash_fn(
const void *obj,
const int flags)
221 static int db_cmp_fn(
void *obj,
void *arg,
int flags) {
223 const char *name = arg;
228 static void db_destructor(
void *obj)
232 ast_debug(1,
"Destroying db: %s\n", db->name);
237 sqlite3_close(db->handle);
244 return ao2_find(databases, database,
OBJ_KEY);
253 static int stop_batch_cb(
void *obj,
void *arg,
int flags)
261 static int mark_dirty_cb(
void *obj,
void *arg,
int flags)
268 static void mark_all_databases_dirty(
void)
273 static int is_dirty_cb(
void *obj,
void *arg,
int flags)
283 static void unlink_dirty_databases(
void)
288 static int str_to_requirements(
const char *data)
290 if (!strcasecmp(data,
"createclose")) {
291 return REALTIME_SQLITE3_REQ_CLOSE;
292 }
else if (!strcasecmp(data,
"createchar")) {
293 return REALTIME_SQLITE3_REQ_CHAR;
296 return REALTIME_SQLITE3_REQ_WARN;
303 ast_debug(3,
"DB: %s SQL: %s\n", db->name, sql);
311 realtime_sqlite3_exec_query_with_handle(db,
"BEGIN TRANSACTION", NULL, NULL);
317 if (realtime_sqlite3_exec_query_with_handle(db,
"COMMIT", NULL, NULL) < 0) {
318 realtime_sqlite3_exec_query_with_handle(db,
"ROLLBACK", NULL, NULL);
324 realtime_sqlite3_exec_query_with_handle(db,
"BEGIN TRANSACTION", NULL, NULL);
326 usleep(1000 * db->batch);
339 if (sqlite3_open(db->filename, &db->handle) != SQLITE_OK) {
340 ast_log(LOG_WARNING,
"Could not open %s: %s\n", db->filename, sqlite3_errmsg(db->handle));
344 sqlite3_busy_timeout(db->handle, db->busy_timeout);
347 sqlite3_trace(db->handle,
trace_cb, db);
349 sqlite3_trace(db->handle, NULL, NULL);
360 ast_cond_signal(&db->cond);
366 ast_cond_init(&db->cond, NULL);
368 db->has_batch_thread = !ast_pthread_create_background(&db->syncthread, NULL,
db_sync_thread, db);
374 if (db->has_batch_thread) {
375 db->has_batch_thread = 0;
378 pthread_join(db->syncthread, NULL);
390 if (!(db = ao2_alloc(
sizeof(*db), db_destructor))) {
400 db->requirements = REALTIME_SQLITE3_REQ_WARN;
403 db->busy_timeout = 1000;
405 for (var = ast_variable_browse(config, cat); var; var = var->
next) {
406 if (!strcasecmp(var->
name,
"dbfile")) {
408 }
else if (!strcasecmp(var->
name,
"requirements")) {
409 db->requirements = str_to_requirements(var->
value);
410 }
else if (!strcasecmp(var->
name,
"batch")) {
412 }
else if (!strcasecmp(var->
name,
"debug")) {
414 }
else if (!strcasecmp(var->
name,
"busy_timeout")) {
415 if (
ast_parse_arg(var->
value, PARSE_INT32|PARSE_DEFAULT, &(db->busy_timeout), 1000) != 0) {
416 ast_log(LOG_WARNING,
"Invalid busy_timeout value '%s' at res_config_sqlite3.conf:%d. Using 1000 instead.\n", var->
value, var->lineno);
421 if (ast_strlen_zero(db->filename)) {
422 ast_log(LOG_WARNING,
"Must specify dbfile in res_config_sqlite3.conf\n");
444 db->requirements =
new->requirements;
447 if (db->debug != new->debug) {
449 sqlite3_trace(db->handle, NULL, NULL);
451 sqlite3_trace(db->handle,
trace_cb, db);
453 db->debug =
new->debug;
456 if (strcmp(db->filename, new->filename)) {
457 sqlite3_close(db->handle);
462 if (db->busy_timeout != new->busy_timeout) {
463 db->busy_timeout =
new->busy_timeout;
464 sqlite3_busy_timeout(db->handle, db->busy_timeout);
467 if (db->batch != new->batch) {
468 if (db->batch == 0) {
469 db->batch =
new->batch;
471 }
else if (new->batch == 0) {
472 db->batch =
new->batch;
475 db->batch =
new->batch;
491 if (!(
new = ast_variable_new(columns[0],
S_OR(values[0],
""),
""))) {
496 for (i = 1; i < num_columns; i++) {
497 if (!(
new = ast_variable_new(columns[i],
S_OR(values[i],
""),
""))) {
521 for (i = 0; i < num_columns; i++) {
523 if (!(var = ast_variable_new(columns[i],
S_OR(values[i],
""),
""))) {
524 ast_log(LOG_ERROR,
"Could not create new variable for '%s: %s', throwing away list\n", columns[i], values[i]);
527 ast_variable_append(cat, var);
544 const char *who_asked;
551 callback_t wrapped_callback;
573 static int row_counter_wrapper(
void *arg,
int num_columns,
char **
values,
char **
columns)
576 wrapped->row_count++;
577 if (wrapped->wrapped_callback) {
578 return wrapped->wrapped_callback(wrapped->wrapped_arg, num_columns, values, columns);
596 static int realtime_sqlite3_exec_query_with_handle(
struct realtime_sqlite3_db *db,
const char *sql, callback_t callback,
void *arg)
601 .wrapped_callback = callback,
607 if (sqlite3_exec(db->handle, sql, row_counter_wrapper, &wrapper, &errmsg) != SQLITE_OK) {
608 ast_log(LOG_WARNING,
"Could not execute '%s': %s\n", sql, errmsg);
609 sqlite3_free(errmsg);
614 return res == 0 ? wrapper.row_count : res;
630 static int realtime_sqlite3_exec_query(
const char *database,
const char *sql, callback_t callback,
void *arg)
635 if (!(db = find_database(database))) {
636 ast_log(LOG_WARNING,
"Could not find database: %s\n", database);
640 res = realtime_sqlite3_exec_query_with_handle(db, sql, callback, arg);
659 static int realtime_sqlite3_exec_update_with_handle(
struct realtime_sqlite3_db *db,
const char *sql)
665 if (sqlite3_exec(db->handle, sql, NULL, NULL, &errmsg) != SQLITE_OK) {
666 ast_log(LOG_WARNING,
"Could not execute '%s': %s\n", sql, errmsg);
667 sqlite3_free(errmsg);
670 res = sqlite3_changes(db->handle);
692 static int realtime_sqlite3_exec_update(
const char *database,
const char *sql)
697 if (!(db = find_database(database))) {
698 ast_log(LOG_WARNING,
"Could not find database: %s\n", database);
702 res = realtime_sqlite3_exec_update_with_handle(db, sql);
709 static const char *
static_sql =
"SELECT category, var_name, var_val FROM \"%q\" WHERE filename = %Q AND commented = 0 ORDER BY cat_metric ASC, var_metric ASC";
717 static int static_realtime_cb(
void *arg,
int num_columns,
char **values,
char **columns)
722 if (!strcmp(values[COL_VAR_NAME],
"#include")) {
726 val = values[COL_VAR_VAL];
727 if (!(cfg = ast_config_internal_load(val, args->cfg, args->flags,
"", args->who_asked))) {
728 ast_log(LOG_WARNING,
"Unable to include %s\n", val);
736 if (!args->cat_name || strcmp(args->cat_name, values[COL_CATEGORY])) {
742 ast_free(args->cat_name);
744 if (!(args->cat_name =
ast_strdup(values[COL_CATEGORY]))) {
745 ast_category_destroy(args->cat);
752 if (!(var = ast_variable_new(values[COL_VAR_NAME], values[COL_VAR_VAL],
""))) {
753 ast_log(LOG_WARNING,
"Unable to allocate variable\n");
757 ast_variable_append(args->cat, var);
770 if (ast_strlen_zero(table)) {
771 ast_log(LOG_WARNING,
"Must have a table to query!\n");
775 if (!(sql = sqlite3_mprintf(static_sql, table, configfile))) {
776 ast_log(LOG_WARNING,
"Couldn't allocate query\n");
782 args.cat_name = NULL;
784 args.who_asked = who_asked;
786 realtime_sqlite3_exec_query(database, sql, static_realtime_cb, &args);
793 #define IS_SQL_LIKE_CLAUSE(x) ((x) && ast_ends_with(x, " LIKE"))
802 if (ast_strlen_zero(table)) {
803 ast_log(LOG_WARNING,
"Must have a table to query!\n");
811 for (field = fields; field; field = field->
next) {
813 ast_str_set(&sql, 0,
"SELECT * FROM %s WHERE %s %s", sqlite3_escape_table(table),
814 sqlite3_escape_column_op(field->
name), sqlite3_escape_value(field->
value));
818 sqlite3_escape_value(field->
value));
821 if (has_explicit_like_escaping && IS_SQL_LIKE_CLAUSE(field->
name)) {
885 if (ast_strlen_zero(table)) {
886 ast_log(LOG_WARNING,
"Must have a table to query!\n");
894 for (field = fields; field; field = field->
next) {
897 sqlite3_escape_table(table), sqlite3_escape_column(field->
name), sqlite3_escape_value(field->
value));
904 ast_str_append(&sql, 0,
" WHERE %s %s", sqlite3_escape_column_op(keyfield), sqlite3_escape_value(entity));
906 res = realtime_sqlite3_exec_update(database,
ast_str_buffer(sql));
922 if (ast_strlen_zero(table)) {
923 ast_log(LOG_WARNING,
"Must have a table to query!\n");
936 for (field = lookup_fields; field; field = field->
next) {
938 ast_str_set(&where_clause, 0,
" WHERE %s %s", sqlite3_escape_column_op(field->
name), sqlite3_escape_value(field->
value));
941 ast_str_append(&where_clause, 0,
" AND %s %s", sqlite3_escape_column_op(field->
name), sqlite3_escape_value(field->
value));
946 for (field = update_fields; field; field = field->
next) {
948 ast_str_set(&sql, 0,
"UPDATE %s SET %s = %s", sqlite3_escape_table(table), sqlite3_escape_column(field->
name), sqlite3_escape_value(field->
value));
957 res = realtime_sqlite3_exec_update(database,
ast_str_buffer(sql));
960 ast_free(where_clause);
974 if (ast_strlen_zero(table)) {
975 ast_log(LOG_WARNING,
"Must have a table to query!\n");
988 for (field = fields; field; field = field->
next) {
990 ast_str_set(&sql, 0,
"INSERT INTO %s (%s", sqlite3_escape_table(table), sqlite3_escape_column(field->
name));
991 ast_str_set(&values, 0,
") VALUES (%s", sqlite3_escape_value(field->
value));
1001 res = realtime_sqlite3_exec_update(database,
ast_str_buffer(sql));
1018 if (ast_strlen_zero(table)) {
1019 ast_log(LOG_WARNING,
"Must have a table to query!\n");
1027 for (field = fields; field; field = field->
next) {
1029 ast_str_set(&sql, 0,
"DELETE FROM %s WHERE %s %s", sqlite3_escape_table(table),
1030 sqlite3_escape_column_op(field->
name), sqlite3_escape_value(field->
value));
1033 ast_str_append(&sql, 0,
" AND %s %s", sqlite3_escape_column_op(field->
name), sqlite3_escape_value(field->
value));
1037 res = realtime_sqlite3_exec_update(database,
ast_str_buffer(sql));
1082 int type, first = 1, res;
1090 while ((column = va_arg(ap, typeof(column)))) {
1091 type = va_arg(ap, typeof(type));
1092 sz = va_arg(ap, typeof(sz));
1094 ast_str_set(&sql, 0,
"CREATE TABLE IF NOT EXISTS %s (%s %s", sqlite3_escape_table(table),
1104 res = realtime_sqlite3_exec_update_with_handle(db,
ast_str_buffer(sql)) < 0 ? -1 : 0;
1118 if (db->requirements == REALTIME_SQLITE3_REQ_WARN) {
1119 ast_log(LOG_WARNING,
"Missing column '%s' of type '%s' in %s.%s\n", column, sqltype, db->name, table);
1121 }
else if (db->requirements == REALTIME_SQLITE3_REQ_CHAR) {
1125 if (!(sql = sqlite3_mprintf(
"ALTER TABLE \"%q\" ADD COLUMN \"%q\" %s", table, column, sqltype))) {
1129 if (!(res = (realtime_sqlite3_exec_update_with_handle(db, sql) < 0 ? -1 : 0))) {
1130 ast_log(LOG_NOTICE,
"Creating column '%s' type %s for table %s\n", column, sqltype, table);
1138 static int str_hash_fn(
const void *obj,
const int flags)
1143 static int str_cmp_fn(
void *obj,
void *arg,
int flags) {
1144 return !strcasecmp((
const char *) obj, (
const char *) arg);
1155 if (!(column = ao2_alloc(strlen(values[1]) + 1, NULL))) {
1159 strcpy(column, values[1]);
1187 if (ast_strlen_zero(table)) {
1188 ast_log(LOG_WARNING,
"Must have a table to query!\n");
1192 if (!(db = find_database(database))) {
1197 str_hash_fn, NULL, str_cmp_fn);
1203 if (!(sql = sqlite3_mprintf(
"PRAGMA table_info(\"%q\")", table))) {
1209 if ((res = realtime_sqlite3_exec_query_with_handle(db, sql,
add_column_name, columns)) < 0) {
1214 }
else if (res == 0) {
1225 while ((column = va_arg(ap, typeof(column)))) {
1227 type = va_arg(ap, typeof(type));
1228 sz = va_arg(ap, typeof(sz));
1263 static const char *config_filename =
"res_config_sqlite3.conf";
1267 if (config == CONFIG_STATUS_FILEUNCHANGED) {
1268 ast_debug(1,
"%s was unchanged, skipping parsing\n", config_filename);
1272 ast_mutex_lock(&config_lock);
1274 if (config == CONFIG_STATUS_FILEMISSING || config == CONFIG_STATUS_FILEINVALID) {
1275 ast_log(LOG_ERROR,
"%s config file '%s'\n",
1276 config == CONFIG_STATUS_FILEMISSING ?
"Missing" :
"Invalid", config_filename);
1277 ast_mutex_unlock(&config_lock);
1283 mark_all_databases_dirty();
1285 if (!strcasecmp(cat,
"general")) {
1288 if (!(db = find_database(cat))) {
1290 ast_log(LOG_WARNING,
"Could not allocate new db for '%s' - skipping.\n", cat);
1308 unlink_dirty_databases();
1311 ast_mutex_unlock(&config_lock);
1318 static int reload(
void)
1324 static int unload_module(
void)
1326 ast_mutex_lock(&config_lock);
1331 ast_mutex_unlock(&config_lock);
1336 static void discover_sqlite3_caps(
void)
1349 #if defined(SQLITE_VERSION_NUMBER)
1350 has_explicit_like_escaping = 1;
1352 has_explicit_like_escaping = 0;
1355 ast_debug(3,
"SQLite3 has 'LIKE ... ESCAPE ...' support? %s\n",
1356 has_explicit_like_escaping ?
"Yes" :
"No");
1371 discover_sqlite3_caps();
1374 db_hash_fn, NULL, db_cmp_fn);
1385 ast_log(LOG_ERROR,
"The config API must have changed, this shouldn't happen.\n");
1393 AST_MODULE_INFO(
ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER,
"SQLite 3 realtime config engine",
1394 .support_level = AST_MODULE_SUPPORT_CORE,
1396 .unload = unload_module,
1399 .requires =
"extconfig",
static int db_open(struct realtime_sqlite3_db *db)
Open a database and appropriately set debugging on the db handle.
static struct realtime_sqlite3_db * new_realtime_sqlite3_db(struct ast_config *config, const char *cat)
Create a db object based on a config category.
struct ast_variable * next
#define AST_THREADSTORAGE(name)
Define a thread storage variable.
static int realtime_sqlite3_update2(const char *database, const char *table, const struct ast_variable *lookup_fields, const struct ast_variable *update_fields)
Realtime callback for updating a row based on multiple criteria.
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
static void * db_sync_thread(void *data)
Wrap commands in transactions increased write performance.
int ast_parse_arg(const char *arg, enum ast_parse_flags flags, void *p_result,...)
The argument parsing routine.
static const char * get_sqlite_column_type(int type)
Convert Asterisk realtime types to SQLite 3 types.
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
static const char * static_sql
size_t ast_str_size(const struct ast_str *buf)
Returns the current maximum length (without reallocation) of the current buffer.
static struct ast_config * realtime_sqlite3_multi(const char *database, const char *table, const struct ast_variable *fields)
Realtime callback for a multi-row query.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container, as described below.
static void trace_cb(void *arg, const char *sql)
static int handle_missing_column(struct realtime_sqlite3_db *db, const char *table, const char *column, int type, size_t sz)
If ast_realtime_require sends info about a column we don't have, create it.
Structure for variables, used for configurations and for channel variables.
data for a thread locally stored variable
int ast_config_engine_deregister(struct ast_config_engine *del)
Deregister config engine.
static int realtime_sqlite3_store(const char *database, const char *table, const struct ast_variable *fields)
Realtime callback for inserting a row.
int ast_config_engine_register(struct ast_config_engine *newconfig)
Register config engine.
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
#define ast_strdup(str)
A wrapper for strdup()
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
static int realtime_sqlite3_unload(const char *database, const char *table)
Callback for clearing any cached info.
Configuration engine structure, used to define realtime drivers.
void ast_category_append(struct ast_config *config, struct ast_category *category)
Appends a category to a config.
#define ast_category_new_anonymous()
Create a nameless category that is not backed by a file.
static int parse_config(int reload)
Parse the res_config_sqlite3 config file.
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
void * ao2_object_get_lockaddr(void *obj)
Return the mutex lock address of an object.
Configuration File Parser.
static int update_realtime_sqlite3_db(struct realtime_sqlite3_db *db, struct ast_config *config, const char *cat)
Update an existing db object based on config data.
static struct ast_config * realtime_sqlite3_load(const char *database, const char *table, const char *configfile, struct ast_config *config, struct ast_flags flags, const char *suggested_include_file, const char *who_asked)
Realtime callback for static realtime.
#define ast_config_load(filename, flags)
Load a config file.
Asterisk file paths, configured in asterisk.conf.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
#define AST_STRING_FIELD(name)
Declare a string field.
static int realtime_sqlite3_destroy(const char *database, const char *table, const char *keyfield, const char *entity, const struct ast_variable *fields)
Realtime callback for deleting a row.
#define ast_debug(level,...)
Log a DEBUG message.
static int append_row_to_cfg(void *arg, int num_columns, char **values, char **columns)
Callback for creating an ast_config from a successive sqlite3 result rows.
struct ast_config * ast_config_new(void)
Create a new base configuration structure.
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Support for dynamic strings.
#define ast_category_new_dynamic(name)
Create a category that is not backed by a file.
Module has failed to load, may be in an inconsistent state.
static int realtime_sqlite3_helper(const char *database, const char *table, const struct ast_variable *fields, int is_multi, void *arg)
Helper function for single and multi-row realtime load functions.
static int row_to_varlist(void *arg, int num_columns, char **values, char **columns)
Create a varlist from a single sqlite3 result row.
static int realtime_sqlite3_update(const char *database, const char *table, const char *keyfield, const char *entity, const struct ast_variable *fields)
Realtime callback for updating a row based on a single criteria.
Structure used to handle boolean flags.
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
static int realtime_sqlite3_require(const char *database, const char *table, va_list ap)
Callback for ast_realtime_require.
void ast_str_update(struct ast_str *buf)
Update the length of the buffer, after using ast_str merely as a buffer.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
int ast_app_parse_timelen(const char *timestr, int *result, enum ast_timelen defunit)
Common routine to parse time lengths, with optional time unit specifier.
static int handle_missing_table(struct realtime_sqlite3_db *db, const char *table, va_list ap)
Create a table if ast_realtime_require shows that we are configured to handle the data...
static int add_column_name(void *arg, int num_columns, char **values, char **columns)
Callback for creating a hash of column names for comparison in realtime_sqlite3_require.
#define ASTERISK_GPL_KEY
The text the key() function should return.
Asterisk module definitions.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
static struct ast_variable * realtime_sqlite3(const char *database, const char *table, const struct ast_variable *fields)
Realtime callback for a single row query.
static int load_module(void)
Load the module.
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
#define ao2_link(container, obj)
Add an object to a container.