1//============================================================================
2//
3// SSSS tt lll lll
4// SS SS tt ll ll
5// SS tttttt eeee ll ll aaaa
6// SSSS tt ee ee ll ll aa
7// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
8// SS SS tt ee ll ll aa aa
9// SSSS ttt eeeee llll llll aaaaa
10//
11// Copyright (c) 1995-2019 by Bradford W. Mott, Stephen Anthony
12// and the Stella Team
13//
14// See the file "License.txt" for information on usage and redistribution of
15// this file, and for a DISCLAIMER OF ALL WARRANTIES.
16//============================================================================
17
18#include <cstdio>
19
20#include "SqliteDatabase.hxx"
21#include "Logger.hxx"
22#include "SqliteError.hxx"
23
24#ifdef BSPF_WINDOWS
25 #define SEPARATOR "\""
26#else
27 #define SEPARATOR "/"
28#endif
29
30// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
31SqliteDatabase::SqliteDatabase(
32 const string& databaseDirectory,
33 const string& databaseName
34) : myDatabaseFile(databaseDirectory + SEPARATOR + databaseName + ".sqlite3"),
35 myHandle(nullptr)
36{}
37
38// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
39SqliteDatabase::~SqliteDatabase()
40{
41 if (myHandle) sqlite3_close_v2(myHandle);
42}
43
44// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
45void SqliteDatabase::initialize()
46{
47 if (myHandle) return;
48
49 bool dbInitialized = false;
50
51 for (int tries = 1; tries < 3 && !dbInitialized; tries++) {
52 dbInitialized = (sqlite3_open(myDatabaseFile.c_str(), &myHandle) == SQLITE_OK);
53
54 if (dbInitialized)
55 dbInitialized = sqlite3_exec(myHandle, "PRAGMA schema_version", nullptr, nullptr, nullptr) == SQLITE_OK;
56
57 if (!dbInitialized && tries == 1) {
58 Logger::info("sqlite DB " + myDatabaseFile + " seems to be corrupt, removing and retrying...");
59
60 remove(myDatabaseFile.c_str());
61 if (myHandle) sqlite3_close_v2(myHandle);
62 }
63 }
64
65 if (!dbInitialized) {
66 if (myHandle) {
67 string emsg = sqlite3_errmsg(myHandle);
68
69 sqlite3_close_v2(myHandle);
70 myHandle = nullptr;
71
72 throw SqliteError(emsg);
73 }
74
75 throw SqliteError("unable to initialize sqlite DB for unknown reason");
76 };
77
78 Logger::debug("successfully opened " + myDatabaseFile);
79
80 exec("PRAGMA journal_mode=WAL");
81
82 switch (sqlite3_wal_checkpoint_v2(myHandle, nullptr, SQLITE_CHECKPOINT_TRUNCATE, nullptr, nullptr)) {
83 case SQLITE_OK:
84 break;
85
86 case SQLITE_MISUSE:
87 Logger::info("failed to checkpoint WAL on " + myDatabaseFile + " - WAL probably unavailable");
88 break;
89
90 default:
91 Logger::info("failed to checkpoint WAL on " + myDatabaseFile + " : " + sqlite3_errmsg(myHandle));
92 break;
93 }
94}
95
96// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
97void SqliteDatabase::exec(const string& sql) const
98{
99 if (sqlite3_exec(myHandle, sql.c_str(), nullptr, nullptr, nullptr) != SQLITE_OK)
100 throw SqliteError(myHandle);
101}
102