1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2026-03-24 07:41:54 -07:00
emacs/mps/code/eventsql.c
Nick Barnes 04c5aca708 Event sql interface now creates a table for each type of event.
Copied from Perforce
 Change: 179868
 ServerID: perforce.ravenbrook.com
2012-10-13 12:16:24 +01:00

231 lines
8.9 KiB
C

#include "config.h"
#include "eventdef.h"
#include "eventpro.h"
#include <stdio.h>
#include <stdlib.h>
#include <sqlite3.h>
unsigned int verbosity = 4;
#define LOG_ALWAYS 0
#define LOG_OFTEN 1
#define LOG_SOMETIMES 2
#define LOG_SELDOM 3
#define LOG_RARELY 4
static void vlog(unsigned int level, const char *format, va_list args)
{
if (level <= verbosity) {
fflush(stderr); /* sync */
fprintf(stderr, "log %d: ", level);
vfprintf(stderr, format, args);
fprintf(stderr, "\n");
}
}
static void log(unsigned int level, const char *format, ...)
{
va_list args;
va_start(args, format);
vlog(level, format, args);
va_end(args);
}
#if 0 /* UNUSED */
static void error(const char *format, ...)
{
va_list args;
fprintf(stderr, "Fatal error: ");
va_start(args, format);
vlog(LOG_ALWAYS, format, args);
va_end(args);
exit(1);
}
#endif /* UNUSED */
static void sqlite_error(int res, sqlite3 *db, const char *format, ...)
{
log(LOG_ALWAYS, "Fatal SQL error %d", res);
va_list args;
va_start(args, format);
vlog(LOG_ALWAYS, format, args);
va_end(args);
log(LOG_ALWAYS, "SQLite message: %s\n", sqlite3_errmsg(db));
exit(1);
}
static void openDatabase(sqlite3 **dbReturn)
{
sqlite3 *db;
int res;
const char *filename = getenv("MPS_EVENT_DATABASE");
if(filename == NULL)
filename = "mpsevent.db";
log(LOG_OFTEN, "Opening %s.", filename);
res = sqlite3_open_v2(filename,
&db,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
NULL); /* use default sqlite_vfs object */
if (res != SQLITE_OK)
sqlite_error(res, db, "Opening %s failed", filename);
*dbReturn = db;
return;
}
/* Macro magic to make a CREATE TABLE statement for each event type. */
#define EVENT_PARAM_SQL_TYPE_A "INTEGER"
#define EVENT_PARAM_SQL_TYPE_P "INTEGER"
#define EVENT_PARAM_SQL_TYPE_U "INTEGER"
#define EVENT_PARAM_SQL_TYPE_W "INTEGER"
#define EVENT_PARAM_SQL_TYPE_D "REAL "
#define EVENT_PARAM_SQL_TYPE_S "TEXT "
#define EVENT_PARAM_SQL_TYPE_B "INTEGER"
#define EVENT_PARAM_SQL_COLUMN(X, index, sort, ident) \
"\"" #ident "\" " EVENT_PARAM_SQL_TYPE_##sort ", "
#define EVENT_TABLE_CREATE(X, name, code, always, kind) \
"CREATE TABLE IF NOT EXISTS EVENT_" #name " ( " \
EVENT_##name##_PARAMS(EVENT_PARAM_SQL_COLUMN, X) \
"time INTEGER ) ",
const char *createStatements[] = {
"CREATE TABLE IF NOT EXISTS event_kind (name TEXT,"
" description TEXT,"
" enum INTEGER PRIMARY KEY)",
"CREATE TABLE IF NOT EXISTS event_type (name TEXT,"
" code INTEGER PRIMARY KEY,"
" always INTEGER,"
" kind INTEGER,"
" FOREIGN KEY (kind) REFERENCES event_kind(enum));",
EVENT_LIST(EVENT_TABLE_CREATE, X)
};
const char *populateStatements[] = {
};
#define EVENT_KIND_DO_INSERT(X, name, description) \
res = sqlite3_bind_text(statement, 1, #name, -1, SQLITE_STATIC); \
if (res != SQLITE_OK) \
sqlite_error(res, db, "event_kind bind of name \"" #name "\" failed."); \
res = sqlite3_bind_text(statement, 2, description, -1, SQLITE_STATIC); \
if (res != SQLITE_OK) \
sqlite_error(res, db, "event_kind bind of description \"" description "\" failed."); \
res = sqlite3_bind_int(statement, 3, i); \
if (res != SQLITE_OK) \
sqlite_error(res, db, "event_kind bind of enum %d failed.", i); \
++i; \
res = sqlite3_step(statement); \
if (res != SQLITE_DONE) \
sqlite_error(res, db, "event_kind insert of name \"" #name "\" failed."); \
if (sqlite3_changes(db) != 0) \
log(LOG_SOMETIMES, "Insert of event_kind row for \"" #name "\" affected %d rows.", sqlite3_changes(db)); \
res = sqlite3_reset(statement); \
if (res != SQLITE_OK) \
sqlite_error(res, db, "Couldn't reset event_kind insert statement.");
#define EVENT_TYPE_DO_INSERT(X, name, code, always, kind) \
res = sqlite3_bind_text(statement, 1, #name, -1, SQLITE_STATIC); \
if (res != SQLITE_OK) \
sqlite_error(res, db, "event_type bind of name \"" #name "\" failed."); \
res = sqlite3_bind_int(statement, 2, code); \
if (res != SQLITE_OK) \
sqlite_error(res, db, "event_type bind of code %d failed.", code); \
res = sqlite3_bind_int(statement, 3, always); \
if (res != SQLITE_OK) \
sqlite_error(res, db, "event_type bind of always for name \"" #name "\" failed."); \
res = sqlite3_bind_int(statement, 4, EventKind##kind); \
if (res != SQLITE_OK) \
sqlite_error(res, db, "event_type bind of kind for name \"" #name "\" failed."); \
res = sqlite3_step(statement); \
if (res != SQLITE_DONE) \
sqlite_error(res, db, "event_type insert of name \"" #name "\" failed."); \
if (sqlite3_changes(db) != 0) \
log(LOG_SOMETIMES, "Insert of event_type row for \"" #name "\" affected %d rows.", sqlite3_changes(db)); \
res = sqlite3_reset(statement); \
if (res != SQLITE_OK) \
sqlite_error(res, db, "Couldn't reset event_type insert statement.");
static void fillTables(sqlite3 *db)
{
int i;
sqlite3_stmt *statement;
int res;
res = sqlite3_prepare_v2(db,
"INSERT OR IGNORE INTO event_kind (name, description, enum)"
"VALUES (?, ?, ?)",
-1, /* prepare whole string as statement */
&statement,
NULL);
if (res != SQLITE_OK)
sqlite_error(res, db, "event_kind preparation failed");
i = 0;
EventKindENUM(EVENT_KIND_DO_INSERT, X);
res = sqlite3_finalize(statement);
if (res != SQLITE_OK)
sqlite_error(res, db, "event_kind finalize failed");
res = sqlite3_prepare_v2(db,
"INSERT OR IGNORE INTO event_type (name, code, always, kind)"
"VALUES (?, ?, ?, ?)",
-1, /* prepare whole string as statement */
&statement,
NULL);
if (res != SQLITE_OK)
sqlite_error(res, db, "event_type preparation failed");
EVENT_LIST(EVENT_TYPE_DO_INSERT, X);
res = sqlite3_finalize(statement);
if (res != SQLITE_OK)
sqlite_error(res, db, "event_type finalize failed");
}
static void makeTables(sqlite3 *db)
{
int i;
int res;
for (i=0; i < (sizeof(createStatements)/sizeof(createStatements[0])); ++i) {
log(LOG_SOMETIMES, "Creating tables. SQL command: %s", createStatements[i]);
res = sqlite3_exec(db,
createStatements[i],
NULL, /* No callback */
NULL, /* No callback closure */
NULL); /* error messages handled by sqlite_error */
if (res != SQLITE_OK)
sqlite_error(res, db, "Table creation failed: %s", createStatements[i]);
}
}
void closeDatabase(sqlite3 *db)
{
int res = sqlite3_close(db);
if (res != SQLITE_OK)
sqlite_error(res, db, "Closing database failed");
log(LOG_ALWAYS, "Closed database.");
}
int main(void)
{
sqlite3 *db;
openDatabase(&db);
makeTables(db);
fillTables(db);
closeDatabase(db);
return 0;
}