diff --git a/scripts/base/frameworks/logging/writers/sqlite.zeek b/scripts/base/frameworks/logging/writers/sqlite.zeek index f7ebd9130c..56c762cb61 100644 --- a/scripts/base/frameworks/logging/writers/sqlite.zeek +++ b/scripts/base/frameworks/logging/writers/sqlite.zeek @@ -21,5 +21,38 @@ export { ## String to use for empty fields. This should be different from ## *unset_field* to make the output unambiguous. const empty_field = Log::empty_field &redef; + + type SQLiteSynchronous: enum { + SQLITE_SYNCHRONOUS_OFF, + SQLITE_SYNCHRONOUS_NORMAL, + SQLITE_SYNCHRONOUS_FULL, + SQLITE_SYNCHRONOUS_EXTRA, + }; + + ## Values supported for SQLite's PRAGMA journal_mode statement. + type SQLiteJournalMode: enum { + SQLITE_JOURNAL_MODE_DELETE, + SQLITE_JOURNAL_MODE_TRUNCATE, + SQLITE_JOURNAL_MODE_PERIST, + SQLITE_JOURNAL_MODE_MEMORY, + SQLITE_JOURNAL_MODE_WAL, + SQLITE_JOURNAL_MODE_OFF, + }; + + ## If set, runs the PRAGMA synchronous statement with the + ## provided value after connecting to the SQLite database. See + ## `SQLite's synchronous documentation `_ + ## for more details around performance and data safety trade offs. + + const synchronous = SQLITE_SYNCHRONOUS_FULL &redef; + + ## If set, runs the PRAGMA journal_mode statement with the + ## provided value after connecting to the SQLite database. See + ## `SQLite's journal_mode documentation `_ + ## for more details around performance, data safety trade offs + ## and interaction with the PRAGMA synchronous statement. + const journal_mode = SQLITE_JOURNAL_MODE_DELETE &redef; + + } diff --git a/src/logging/writers/sqlite/SQLite.cc b/src/logging/writers/sqlite/SQLite.cc index 21942d82ec..e7b1af313c 100644 --- a/src/logging/writers/sqlite/SQLite.cc +++ b/src/logging/writers/sqlite/SQLite.cc @@ -26,6 +26,9 @@ SQLite::SQLite(WriterFrontend* frontend) : WriterBackend(frontend), fields(), nu empty_field.assign((const char*)BifConst::LogSQLite::empty_field->Bytes(), BifConst::LogSQLite::empty_field->Len()); + synchronous = BifConst::LogSQLite::synchronous->AsInt(); + journal_mode = BifConst::LogSQLite::journal_mode->AsInt(); + threading::formatter::Ascii::SeparatorInfo sep_info(string(), set_separator, unset_field, empty_field); io = new threading::formatter::Ascii(this, sep_info); } @@ -128,6 +131,49 @@ bool SQLite::DoInit(const WriterInfo& info, int arg_num_fields, const Field* con SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX, NULL)) ) return false; + char* errorMsg = 0; + int res; + switch ( synchronous ) { + case SQLITE_SYNCHRONOUS_OFF: res = sqlite3_exec(db, "PRAGMA synchronous=OFF;", NULL, NULL, &errorMsg); break; + case SQLITE_SYNCHRONOUS_NORMAL: + res = sqlite3_exec(db, "PRAGMA synchronous=NORMAL;", NULL, NULL, &errorMsg); + break; + case SQLITE_SYNCHRONOUS_FULL: res = sqlite3_exec(db, "PRAGMA synchronous=FULL;", NULL, NULL, &errorMsg); break; + case SQLITE_SYNCHRONOUS_EXTRA: + res = sqlite3_exec(db, "PRAGMA synchronous=EXTRA;", NULL, NULL, &errorMsg); + break; + default: Error("Invalid LogSQLite::synchronous enum"); return false; + } + if ( res != SQLITE_OK ) { + Error(Fmt("Error setting synchronous pragma %s", errorMsg)); + sqlite3_free(errorMsg); + return false; + } + + switch ( journal_mode ) { + case SQLITE_JOURNAL_MODE_DELETE: + res = sqlite3_exec(db, "PRAGMA journal_mode=DELETE;", NULL, NULL, &errorMsg); + break; + case SQLITE_JOURNAL_MODE_TRUNCATE: + res = sqlite3_exec(db, "PRAGMA journal_mode=TRUNCATE;", NULL, NULL, &errorMsg); + break; + case SQLITE_JOURNAL_MODE_PERSIST: + res = sqlite3_exec(db, "PRAGMA journal_mode=PERSIST;", NULL, NULL, &errorMsg); + break; + case SQLITE_JOURNAL_MODE_MEMORY: + res = sqlite3_exec(db, "PRAGMA journal_mode=MEMORY;", NULL, NULL, &errorMsg); + break; + case SQLITE_JOURNAL_MODE_WAL: res = sqlite3_exec(db, "PRAGMA journal_mode=WAL;", NULL, NULL, &errorMsg); break; + case SQLITE_JOURNAL_MODE_OFF: res = sqlite3_exec(db, "PRAGMA journal_mode=OFF;", NULL, NULL, &errorMsg); break; + default: Error("Invalid LogSQLite::journal_mode enum"); return false; + } + if ( res != SQLITE_OK ) { + Error(Fmt("Error setting journal_mode pragma %s", errorMsg)); + sqlite3_free(errorMsg); + return false; + } + + string create = "CREATE TABLE IF NOT EXISTS " + tablename + " (\n"; //"id SERIAL UNIQUE NOT NULL"; // SQLite has rowids, we do not need a counter here. @@ -163,8 +209,8 @@ bool SQLite::DoInit(const WriterInfo& info, int arg_num_fields, const Field* con create += "\n);"; - char* errorMsg = 0; - int res = sqlite3_exec(db, create.c_str(), NULL, NULL, &errorMsg); + errorMsg = 0; + res = sqlite3_exec(db, create.c_str(), NULL, NULL, &errorMsg); if ( res != SQLITE_OK ) { Error(Fmt("Error executing table creation statement: %s", errorMsg)); sqlite3_free(errorMsg); diff --git a/src/logging/writers/sqlite/SQLite.h b/src/logging/writers/sqlite/SQLite.h index 15e1255730..61acdc28af 100644 --- a/src/logging/writers/sqlite/SQLite.h +++ b/src/logging/writers/sqlite/SQLite.h @@ -45,6 +45,24 @@ private: std::string unset_field; std::string empty_field; + int64_t synchronous; + int64_t journal_mode; + + enum SQLiteSynchronous { + SQLITE_SYNCHRONOUS_OFF, + SQLITE_SYNCHRONOUS_NORMAL, + SQLITE_SYNCHRONOUS_FULL, + SQLITE_SYNCHRONOUS_EXTRA, + }; + enum SQLiteJournalMode { + SQLITE_JOURNAL_MODE_DELETE, + SQLITE_JOURNAL_MODE_TRUNCATE, + SQLITE_JOURNAL_MODE_PERSIST, + SQLITE_JOURNAL_MODE_MEMORY, + SQLITE_JOURNAL_MODE_WAL, + SQLITE_JOURNAL_MODE_OFF, + }; + threading::formatter::Ascii* io; }; diff --git a/src/logging/writers/sqlite/sqlite.bif b/src/logging/writers/sqlite/sqlite.bif index 29b93f3a0c..7c68f2795e 100644 --- a/src/logging/writers/sqlite/sqlite.bif +++ b/src/logging/writers/sqlite/sqlite.bif @@ -7,3 +7,23 @@ const set_separator: string; const empty_field: string; const unset_field: string; +enum SQLiteSynchronous %{ + SQLITE_SYNCHRONOUS_OFF, + SQLITE_SYNCHRONOUS_NORMAL, + SQLITE_SYNCHRONOUS_FULL, + SQLITE_SYNCHRONOUS_EXTRA, +%} + +enum SQLiteJournalMode %{ + SQLITE_JOURNAL_MODE_DELETE, + SQLITE_JOURNAL_MODE_TRUNCATE, + SQLITE_JOURNAL_MODE_PERIST, + SQLITE_JOURNAL_MODE_MEMORY, + SQLITE_JOURNAL_MODE_WAL, + SQLITE_JOURNAL_MODE_OFF, +%} + +const synchronous: SQLiteSynchronous; +const journal_mode: SQLiteJournalMode; + +