include/simdb/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
275 / 281
97.9%
Branches:
382 / 508
75.2%
Functions:
32 / 32
100.0%

sqlite/DatabaseManager.hpp
Line Branch Exec Source
1 // <DatabaseManager.hpp> -*- C++ -*-
2
3 #pragma once
4
5 #include "simdb/Assert.hpp"
6 #include "simdb/schema/SchemaDef.hpp"
7 #include "simdb/sqlite/Connection.hpp"
8 #include "simdb/sqlite/PreparedINSERT.hpp"
9 #include "simdb/sqlite/Query.hpp"
10 #include "simdb/sqlite/Table.hpp"
11 #include <filesystem>
12 #include <set>
13
14 namespace simdb {
15
16 enum class JournalMode {
17 // PRAGMA journal_mode = OFF
18 // PRAGMA synchronous = OFF
19 FASTEST,
20
21 // PRAGMA journal_mode = DELETE;
22 // PRAGMA synchronous = FULL;
23 SAFEST,
24
25 // PRAGMA journal_mode = WAL;
26 // PRAGMA synchronous = NORMAL;
27 BALANCED
28 };
29
30 using PragmaPairs = std::vector<std::pair<std::string, std::string>>;
31
32 inline PragmaPairs getPragmas(JournalMode mode)
33 {
34 switch (mode)
35 {
36 case JournalMode::FASTEST:
37 return {{"journal_mode", "OFF"}, {"synchronous", "OFF"}};
38 case JournalMode::SAFEST:
39 return {{"journal_mode", "DELETE"}, {"synchronous", "FULL"}};
40 case JournalMode::BALANCED:
41 return {{"journal_mode", "WAL"}, {"synchronous", "NORMAL"}};
42 }
43
44 // Unreachable
45 simdb_assert(false);
46 return {};
47 }
48
49 /*!
50 * \class DatabaseManager
51 *
52 * \brief This class is the primary "entry point" into SimDB connections,
53 * including instantiating schemas, creating records, querying
54 * records, and accessing the underlying Connection.
55 */
56 class DatabaseManager
57 {
58 public:
59 /// \brief Construct a DatabaseManager
60 /// \param db_file Name of the database file, typically with .db extension
61 /// \param force_new_file Force the <db_file> to be overwritten if it
62 /// exists.
63 /// If the file already existed and this flag is
64 /// false, then you will not be able to call
65 /// appendSchema() on this DatabaseManager as the
66 /// schema is fixed.
67 /// \param pragmas Pragmas to set on the database as soon as it is opened.
68 28 DatabaseManager(const std::string& db_file = "sim.db", const bool force_new_file = false,
69 28 const PragmaPairs& pragmas = {}) :
70
2/2
✓ Branch 3 → 4 taken 28 times.
✓ Branch 4 → 5 taken 28 times.
28 db_file_(db_file)
71 {
72
2/2
✓ Branch 6 → 7 taken 28 times.
✓ Branch 7 → 8 taken 28 times.
28 auto db_file_exists = std::filesystem::exists(db_file);
73
4/4
✓ Branch 9 → 10 taken 5 times.
✓ Branch 9 → 16 taken 23 times.
✓ Branch 10 → 11 taken 1 time.
✓ Branch 10 → 16 taken 4 times.
28 if (db_file_exists && force_new_file)
74 {
75
1/1
✓ Branch 11 → 12 taken 1 time.
1 const auto cmd = "rm -f " + db_file;
76
1/1
✓ Branch 13 → 14 taken 1 time.
1 auto rc = system(cmd.c_str());
77 (void)rc;
78 1 }
79
80
2/4
✓ Branch 16 → 17 taken 28 times.
✓ Branch 18 → 19 taken 28 times.
✗ Branch 107 → 108 not taken.
✗ Branch 107 → 109 not taken.
28 db_conn_.reset(new Connection);
81
1/1
✓ Branch 19 → 20 taken 28 times.
28 openDatabaseFile_(pragmas);
82
83
4/4
✓ Branch 20 → 21 taken 5 times.
✓ Branch 20 → 23 taken 23 times.
✓ Branch 21 → 22 taken 4 times.
✓ Branch 21 → 23 taken 1 time.
28 if (db_file_exists && !force_new_file)
84 {
85 try
86 {
87
1/1
✓ Branch 22 → 23 taken 3 times.
4 connectToExistingDatabase_();
88
1/2
✗ Branch 110 → 111 not taken.
✓ Branch 110 → 112 taken 1 time.
1 } catch (const std::exception& ex)
89 {
90
1/1
✓ Branch 115 → 116 taken 1 time.
1 throw DBException("Unable to connect to database file: ")
91
4/4
✓ Branch 116 → 117 taken 1 time.
✓ Branch 117 → 118 taken 1 time.
✓ Branch 119 → 120 taken 1 time.
✓ Branch 120 → 121 taken 1 time.
2 << db_file << "\n *** error message: " << ex.what();
92 1 }
93 }
94
95
3/3
✓ Branch 25 → 26 taken 27 times.
✓ Branch 29 → 30 taken 24 times.
✓ Branch 29 → 100 taken 3 times.
81 if (!schema_.hasTable("internal$SchemaTables"))
96 {
97 using dt = SqlDataType;
98
1/1
✓ Branch 30 → 31 taken 24 times.
24 Schema schema;
99
100
2/2
✓ Branch 33 → 34 taken 24 times.
✓ Branch 34 → 35 taken 24 times.
48 auto& schema_tables = schema.addTable("internal$SchemaTables");
101
2/2
✓ Branch 39 → 40 taken 24 times.
✓ Branch 40 → 41 taken 24 times.
48 schema_tables.addColumn("TableName", dt::string_t);
102
2/2
✓ Branch 45 → 46 taken 24 times.
✓ Branch 46 → 47 taken 24 times.
48 schema_tables.addColumn("IndexedColumns", dt::string_t);
103
2/2
✓ Branch 51 → 52 taken 24 times.
✓ Branch 52 → 53 taken 24 times.
48 schema_tables.addColumn("PrimaryKey", dt::string_t);
104
2/2
✓ Branch 57 → 58 taken 24 times.
✓ Branch 58 → 59 taken 24 times.
48 schema_tables.setColumnDefaultValue("PrimaryKey", "Id");
105
106
2/2
✓ Branch 63 → 64 taken 24 times.
✓ Branch 64 → 65 taken 24 times.
48 auto& schema_columns = schema.addTable("internal$SchemaColumns");
107
2/2
✓ Branch 69 → 70 taken 24 times.
✓ Branch 70 → 71 taken 24 times.
48 schema_columns.addColumn("TableName", dt::string_t);
108
2/2
✓ Branch 75 → 76 taken 24 times.
✓ Branch 76 → 77 taken 24 times.
48 schema_columns.addColumn("ColumnName", dt::string_t);
109
2/2
✓ Branch 81 → 82 taken 24 times.
✓ Branch 82 → 83 taken 24 times.
48 schema_columns.addColumn("ColumnDType", dt::string_t);
110
2/2
✓ Branch 87 → 88 taken 24 times.
✓ Branch 88 → 89 taken 24 times.
48 schema_columns.addColumn("ColumnDefaultVal", dt::string_t);
111
2/2
✓ Branch 93 → 94 taken 24 times.
✓ Branch 94 → 95 taken 24 times.
24 schema_columns.createIndexOn("TableName");
112
113
1/1
✓ Branch 97 → 98 taken 24 times.
24 appendSchema(schema);
114 24 }
115 31 }
116
117 /// \brief Add one or more tables to the existing schema.
118 ///
119 /// \throws This will throw an exception for DatabaseManager's
120 /// whose connection was initialized with a previously
121 /// existing file.
122 ///
123 /// \return Returns true if successful, false otherwise.
124 60 void appendSchema(const Schema& schema)
125 {
126 60 schema_.appendSchema(schema);
127 60 db_conn_->realizeSchema(schema);
128 60 serializeSchema_();
129 60 }
130
131 /// Get the schema for this database.
132 19 const Schema& getSchema() const { return schema_; }
133
134 /// Get the full database file path.
135 12229 const std::string& getDatabaseFilePath() const { return db_filepath_; }
136
137 /// Execute the functor inside BEGIN/COMMIT TRANSACTION.
138 11238 void safeTransaction(const TransactionFunc& func, uint64_t num_retries = std::numeric_limits<uint64_t>::max()) const
139 {
140 11238 db_conn_->safeTransaction(func, num_retries);
141 11237 }
142
143 /// For debug purposes only.
144 bool isInTransaction() const { return db_conn_ && db_conn_->isInTransaction(); }
145
146 /// \brief Perform INSERT operation on this database.
147 ///
148 /// \note The way to call this method is:
149 /// db_mgr.INSERT(SQL_TABLE("TableName"),
150 /// SQL_COLUMNS("ColA", "ColB"),
151 /// SQL_VALUES(3.14, "foo"));
152 ///
153 /// \note You may also provide ValueContainerBase subclasses in the
154 /// SQL_VALUES.
155 ///
156 /// \return SqlRecord which wraps the table and the ID of its record.
157 200092 std::unique_ptr<SqlRecord> INSERT(SqlTable&& table, SqlColumns&& cols, SqlValues&& vals)
158 {
159
12/12
✓ Branch 4 → 5 taken 1 time.
✓ Branch 4 → 23 taken 200091 times.
✓ Branch 7 → 8 taken 1 time.
✓ Branch 8 → 9 taken 1 time.
✓ Branch 10 → 11 taken 1 time.
✓ Branch 14 → 15 taken 1 time.
✓ Branch 15 → 16 taken 1 time.
✓ Branch 16 → 17 taken 1 time.
✓ Branch 17 → 18 taken 1 time.
✓ Branch 18 → 19 taken 1 time.
✓ Branch 19 → 20 taken 1 time.
✓ Branch 21 → 22 taken 1 time.
200094 simdb_assert(table.getName().find("internal$") != 0, "Cannot perform INSERT. This is an internal table.");
160 200091 return INSERT_(std::move(table), std::move(cols), std::move(vals));
161 }
162
163 /// \brief INSERT into a table with values for all columns, in schema order.
164 /// Equivalent to INSERT(table, SQL_COLUMNS(...), vals) with every
165 /// column of the table. The number and order of values must match
166 /// the table's columns.
167 10277 std::unique_ptr<SqlRecord> INSERT(SqlTable&& table, SqlValues&& vals)
168 {
169
12/12
✓ Branch 4 → 5 taken 1 time.
✓ Branch 4 → 23 taken 10276 times.
✓ Branch 7 → 8 taken 1 time.
✓ Branch 8 → 9 taken 1 time.
✓ Branch 10 → 11 taken 1 time.
✓ Branch 14 → 15 taken 1 time.
✓ Branch 15 → 16 taken 1 time.
✓ Branch 16 → 17 taken 1 time.
✓ Branch 17 → 18 taken 1 time.
✓ Branch 18 → 19 taken 1 time.
✓ Branch 19 → 20 taken 1 time.
✓ Branch 21 → 22 taken 1 time.
10279 simdb_assert(table.getName().find("internal$") != 0, "Cannot perform INSERT. This is an internal table.");
170 10276 std::vector<std::string> col_names;
171
3/3
✓ Branch 25 → 26 taken 10276 times.
✓ Branch 35 → 29 taken 17544 times.
✓ Branch 35 → 36 taken 10276 times.
27820 for (const auto& col : schema_.getTable(table.getName()).getColumns())
172 {
173
1/1
✓ Branch 32 → 33 taken 17544 times.
17544 col_names.push_back(col->getName());
174 }
175
1/1
✓ Branch 36 → 37 taken 10276 times.
10276 SqlColumns cols(col_names);
176
1/1
✓ Branch 40 → 41 taken 10275 times.
20551 return INSERT_(std::move(table), std::move(cols), std::move(vals));
177 10277 }
178
179 /// This INSERT() overload is to be used for tables that were defined with
180 /// at least one default value for its column(s).
181 2 std::unique_ptr<SqlRecord> INSERT(SqlTable&& table)
182 {
183
12/12
✓ Branch 4 → 5 taken 1 time.
✓ Branch 4 → 23 taken 1 time.
✓ Branch 7 → 8 taken 1 time.
✓ Branch 8 → 9 taken 1 time.
✓ Branch 10 → 11 taken 1 time.
✓ Branch 14 → 15 taken 1 time.
✓ Branch 15 → 16 taken 1 time.
✓ Branch 16 → 17 taken 1 time.
✓ Branch 17 → 18 taken 1 time.
✓ Branch 18 → 19 taken 1 time.
✓ Branch 19 → 20 taken 1 time.
✓ Branch 21 → 22 taken 1 time.
4 simdb_assert(table.getName().find("internal$") != 0, "Cannot perform INSERT. This is an internal table.");
184 1 return INSERT_(std::move(table));
185 }
186
187 /// \brief Create a prepared statement for faster record creation
188 /// when you are creating many of the same table records.
189 59 std::unique_ptr<PreparedINSERT> prepareINSERT(SqlTable&& table, SqlColumns&& cols)
190 {
191
12/12
✓ Branch 4 → 5 taken 1 time.
✓ Branch 4 → 23 taken 58 times.
✓ Branch 7 → 8 taken 1 time.
✓ Branch 8 → 9 taken 1 time.
✓ Branch 10 → 11 taken 1 time.
✓ Branch 14 → 15 taken 1 time.
✓ Branch 15 → 16 taken 1 time.
✓ Branch 16 → 17 taken 1 time.
✓ Branch 17 → 18 taken 1 time.
✓ Branch 18 → 19 taken 1 time.
✓ Branch 19 → 20 taken 1 time.
✓ Branch 21 → 22 taken 1 time.
61 simdb_assert(table.getName().find("internal$") != 0, "Cannot perform INSERT. This is an internal table.");
192 58 return prepareINSERT_(std::move(table), std::move(cols));
193 }
194
195 /// \brief Create a prepared statement for inserting into all columns of a table.
196 /// Equivalent to prepareINSERT(table, SQL_COLUMNS(...)) with every column
197 /// of the table, in schema order.
198 41 std::unique_ptr<PreparedINSERT> prepareINSERT(SqlTable&& table)
199 {
200
12/12
✓ Branch 4 → 5 taken 1 time.
✓ Branch 4 → 23 taken 40 times.
✓ Branch 7 → 8 taken 1 time.
✓ Branch 8 → 9 taken 1 time.
✓ Branch 10 → 11 taken 1 time.
✓ Branch 14 → 15 taken 1 time.
✓ Branch 15 → 16 taken 1 time.
✓ Branch 16 → 17 taken 1 time.
✓ Branch 17 → 18 taken 1 time.
✓ Branch 18 → 19 taken 1 time.
✓ Branch 19 → 20 taken 1 time.
✓ Branch 21 → 22 taken 1 time.
43 simdb_assert(table.getName().find("internal$") != 0, "Cannot perform INSERT. This is an internal table.");
201 40 std::vector<std::string> col_names;
202
3/3
✓ Branch 25 → 26 taken 40 times.
✓ Branch 35 → 29 taken 115 times.
✓ Branch 35 → 36 taken 40 times.
155 for (const auto& col : schema_.getTable(table.getName()).getColumns())
203 {
204
1/1
✓ Branch 32 → 33 taken 115 times.
115 col_names.push_back(col->getName());
205 }
206
1/1
✓ Branch 36 → 37 taken 40 times.
40 SqlColumns cols(col_names);
207
1/1
✓ Branch 39 → 40 taken 40 times.
80 return prepareINSERT_(std::move(table), std::move(cols));
208 40 }
209
210 /// \brief Execute an arbitrary SQL command on this database.
211 5 void EXECUTE(const std::string& sql_cmd, bool in_transaction = true)
212 {
213 5 std::vector<std::string> args;
214
2/2
✓ Branch 3 → 4 taken 5 times.
✓ Branch 4 → 5 taken 5 times.
5 boost::split(args, sql_cmd, boost::is_any_of(" "));
215
1/2
✓ Branch 7 → 8 taken 5 times.
✗ Branch 7 → 56 not taken.
5 if (args.size() >= 3)
216 {
217 5 std::transform(args[0].begin(), args[0].end(), args[0].begin(),
218 30 [](unsigned char ch) { return std::tolower(ch); });
219
220 5 std::transform(args[1].begin(), args[1].end(), args[1].begin(),
221 84 [](unsigned char ch) { return std::tolower(ch); });
222
223
21/23
✓ Branch 23 → 24 taken 5 times.
✓ Branch 24 → 25 taken 1 time.
✓ Branch 24 → 29 taken 4 times.
✓ Branch 26 → 27 taken 1 time.
✓ Branch 27 → 28 taken 1 time.
✗ Branch 27 → 29 not taken.
✓ Branch 30 → 31 taken 1 time.
✓ Branch 30 → 35 taken 4 times.
✓ Branch 33 → 34 taken 1 time.
✗ Branch 33 → 35 not taken.
✓ Branch 36 → 37 taken 1 time.
✓ Branch 36 → 56 taken 4 times.
✓ Branch 39 → 40 taken 1 time.
✓ Branch 40 → 41 taken 1 time.
✓ Branch 42 → 43 taken 1 time.
✓ Branch 46 → 47 taken 1 time.
✓ Branch 47 → 48 taken 1 time.
✓ Branch 48 → 49 taken 1 time.
✓ Branch 49 → 50 taken 1 time.
✓ Branch 50 → 51 taken 1 time.
✓ Branch 51 → 52 taken 1 time.
✓ Branch 52 → 53 taken 1 time.
✓ Branch 54 → 55 taken 1 time.
7 simdb_assert(!(args[0] == "insert" && args[1] == "into" && args[2].find("internal$") == 0),
224 "Invalid command. Cannot write to internal tables. Command: " << sql_cmd);
225 }
226
227
1/2
✓ Branch 56 → 57 taken 4 times.
✗ Branch 56 → 63 not taken.
4 if (in_transaction)
228 {
229
1/1
✓ Branch 60 → 61 taken 4 times.
4 db_conn_->safeTransaction([&]() {
230 auto rc =
231
2/2
✓ Branch 5 → 6 taken 4 times.
✓ Branch 6 → 7 taken 4 times.
4 SQLiteReturnCode(sqlite3_exec(db_conn_->getDatabase(), sql_cmd.c_str(), nullptr, nullptr, nullptr));
232
1/13
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 30 taken 4 times.
✗ Branch 11 → 12 not taken.
✗ Branch 12 → 13 not taken.
✗ Branch 14 → 15 not taken.
✗ Branch 20 → 21 not taken.
✗ Branch 21 → 22 not taken.
✗ Branch 22 → 23 not taken.
✗ Branch 23 → 24 not taken.
✗ Branch 24 → 25 not taken.
✗ Branch 25 → 26 not taken.
✗ Branch 26 → 27 not taken.
✗ Branch 28 → 29 not taken.
4 simdb_assert(!rc, sqlite3_errmsg(db_conn_->getDatabase()));
233 4 });
234 } else
235 {
236 auto rc =
237
0/2
✗ Branch 66 → 67 not taken.
✗ Branch 67 → 68 not taken.
✗ SQLiteReturnCode(sqlite3_exec(db_conn_->getDatabase(), sql_cmd.c_str(), nullptr, nullptr, nullptr));
238
0/13
✗ Branch 69 → 70 not taken.
✗ Branch 69 → 91 not taken.
✗ Branch 72 → 73 not taken.
✗ Branch 73 → 74 not taken.
✗ Branch 75 → 76 not taken.
✗ Branch 81 → 82 not taken.
✗ Branch 82 → 83 not taken.
✗ Branch 83 → 84 not taken.
✗ Branch 84 → 85 not taken.
✗ Branch 85 → 86 not taken.
✗ Branch 86 → 87 not taken.
✗ Branch 87 → 88 not taken.
✗ Branch 89 → 90 not taken.
✗ simdb_assert(!rc, sqlite3_errmsg(db_conn_->getDatabase()));
239 }
240 5 }
241
242 /// \brief Get a SqlRecord from a database ID for the given table.
243 ///
244 /// \return Returns the record wrapper if found, or nullptr if not.
245 16 std::unique_ptr<SqlRecord> findRecord(const char* table_name, const int db_id) const
246 {
247 16 return findRecord_(table_name, db_id, false);
248 }
249
250 /// \brief Get a SqlRecord from a database ID for the given table.
251 ///
252 /// \throws Throws an exception if this database ID is not found in the
253 /// given table.
254 std::unique_ptr<SqlRecord> getRecord(const char* table_name, const int db_id) const
255 {
256 return findRecord_(table_name, db_id, true);
257 }
258
259 /// \brief Delete one record from the given table with the given ID.
260 ///
261 /// \return Returns true if successful, false otherwise.
262 2 bool removeRecordFromTable(const char* table_name, const int db_id)
263 {
264
2/2
✓ Branch 4 → 5 taken 2 times.
✓ Branch 5 → 6 taken 2 times.
2 db_conn_->safeTransaction([&]() {
265
1/1
✓ Branch 2 → 3 taken 2 times.
2 std::ostringstream oss;
266
4/4
✓ Branch 3 → 4 taken 2 times.
✓ Branch 4 → 5 taken 2 times.
✓ Branch 5 → 6 taken 2 times.
✓ Branch 6 → 7 taken 2 times.
2 oss << "DELETE FROM " << table_name << " WHERE Id=" << db_id;
267
1/1
✓ Branch 7 → 8 taken 2 times.
2 const auto cmd = oss.str();
268
269
2/2
✓ Branch 11 → 12 taken 2 times.
✓ Branch 12 → 13 taken 2 times.
2 auto rc = SQLiteReturnCode(sqlite3_exec(db_conn_->getDatabase(), cmd.c_str(), nullptr, nullptr, nullptr));
270
1/13
✗ Branch 14 → 15 not taken.
✓ Branch 14 → 36 taken 2 times.
✗ Branch 17 → 18 not taken.
✗ Branch 18 → 19 not taken.
✗ Branch 20 → 21 not taken.
✗ Branch 26 → 27 not taken.
✗ Branch 27 → 28 not taken.
✗ Branch 28 → 29 not taken.
✗ Branch 29 → 30 not taken.
✗ Branch 30 → 31 not taken.
✗ Branch 31 → 32 not taken.
✗ Branch 32 → 33 not taken.
✗ Branch 34 → 35 not taken.
2 simdb_assert(!rc, sqlite3_errmsg(db_conn_->getDatabase()));
271 2 });
272
273 2 return sqlite3_changes(db_conn_->getDatabase()) == 1;
274 }
275
276 /// \brief Delete every record from the given table.
277 ///
278 /// \return Returns the total number of deleted records.
279 122 uint32_t removeAllRecordsFromTable(const char* table_name)
280 {
281
1/1
✓ Branch 5 → 6 taken 122 times.
122 db_conn_->safeTransaction([&]() {
282
1/1
✓ Branch 2 → 3 taken 122 times.
122 std::ostringstream oss;
283
2/2
✓ Branch 3 → 4 taken 122 times.
✓ Branch 4 → 5 taken 122 times.
122 oss << "DELETE FROM " << table_name;
284
1/1
✓ Branch 5 → 6 taken 122 times.
122 const auto cmd = oss.str();
285
286
2/2
✓ Branch 9 → 10 taken 122 times.
✓ Branch 10 → 11 taken 122 times.
122 auto rc = SQLiteReturnCode(sqlite3_exec(db_conn_->getDatabase(), cmd.c_str(), nullptr, nullptr, nullptr));
287
1/13
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 34 taken 122 times.
✗ Branch 15 → 16 not taken.
✗ Branch 16 → 17 not taken.
✗ Branch 18 → 19 not taken.
✗ Branch 24 → 25 not taken.
✗ Branch 25 → 26 not taken.
✗ Branch 26 → 27 not taken.
✗ Branch 27 → 28 not taken.
✗ Branch 28 → 29 not taken.
✗ Branch 29 → 30 not taken.
✗ Branch 30 → 31 not taken.
✗ Branch 32 → 33 not taken.
122 simdb_assert(!rc, sqlite3_errmsg(db_conn_->getDatabase()));
288 122 });
289
290 122 return sqlite3_changes(db_conn_->getDatabase());
291 }
292
293 /// \brief Issue "DELETE FROM TableName" to clear out the given table.
294 ///
295 /// \return Returns the total number of deleted records across all tables.
296 uint32_t removeAllRecordsFromAllTables()
297 {
298 uint32_t count = 0;
299
300 db_conn_->safeTransaction([&]() {
301 const char* cmd = "SELECT name FROM sqlite_master WHERE type='table'";
302 auto stmt = db_conn_->prepareStatement(cmd);
303
304 while (true)
305 {
306 auto rc = SQLiteReturnCode(sqlite3_step(stmt));
307 if (rc != SQLITE_ROW)
308 {
309 break;
310 }
311
312 auto table_name = sqlite3_column_text(stmt, 0);
313 count += removeAllRecordsFromTable((const char*)table_name);
314 }
315 });
316
317 return count;
318 }
319
320 /// Get a query object to issue SELECT statements with constraints.
321 19423 std::unique_ptr<SqlQuery> createQuery(const char* table_name)
322 {
323
1/3
✓ Branch 5 → 6 taken 19423 times.
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 10 not taken.
19423 return std::unique_ptr<SqlQuery>(new SqlQuery(table_name, db_conn_->getDatabase()));
324 }
325
326 private:
327 /// \brief Open a database connection to an existing database file.
328 ///
329 /// \param db_fpath Full path to the database including the ".db"
330 /// extension, e.g. "/path/to/my/dir/statistics.db"
331 ///
332 /// \note The 'db_fpath' is typically one that was given to us
333 /// from a previous call to getDatabaseFilePath()
334 ///
335 /// \return Returns error message if failed to connect
336 4 void connectToExistingDatabase_()
337 {
338
1/9
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 14 taken 4 times.
✗ Branch 5 → 6 not taken.
✗ Branch 6 → 7 not taken.
✗ Branch 7 → 8 not taken.
✗ Branch 8 → 9 not taken.
✗ Branch 9 → 10 not taken.
✗ Branch 10 → 11 not taken.
✗ Branch 12 → 13 not taken.
4 simdb_assert(db_conn_ != nullptr);
339 4 reconstituteSchema_();
340 3 db_filepath_ = db_conn_->getDatabaseFilePath();
341 3 }
342
343 /// \brief Regenerate the Schema object when attaching to an existing database file.
344 4 void reconstituteSchema_()
345 {
346
1/9
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 15 taken 4 times.
✗ Branch 6 → 7 not taken.
✗ Branch 7 → 8 not taken.
✗ Branch 8 → 9 not taken.
✗ Branch 9 → 10 not taken.
✗ Branch 10 → 11 not taken.
✗ Branch 11 → 12 not taken.
✗ Branch 13 → 14 not taken.
4 simdb_assert(schema_.getTables().empty());
347
348
1/1
✓ Branch 15 → 16 taken 4 times.
4 auto tbl_query = createQuery("internal$SchemaTables");
349
350 4 std::string table_name, indexed_columns, primary_key;
351
1/1
✓ Branch 20 → 21 taken 4 times.
4 tbl_query->select("TableName", table_name);
352
1/1
✓ Branch 22 → 23 taken 4 times.
4 tbl_query->select("IndexedColumns", indexed_columns);
353
1/1
✓ Branch 24 → 25 taken 4 times.
4 tbl_query->select("PrimaryKey", primary_key);
354
355
1/1
✓ Branch 26 → 27 taken 3 times.
4 auto tbl_results = tbl_query->getResultSet();
356
3/3
✓ Branch 135 → 136 taken 22 times.
✓ Branch 136 → 28 taken 19 times.
✓ Branch 136 → 137 taken 3 times.
22 while (tbl_results.getNextRecord())
357 {
358
1/1
✓ Branch 28 → 29 taken 19 times.
19 auto& tbl = schema_.addTable(table_name);
359
360
1/1
✓ Branch 29 → 30 taken 19 times.
19 auto col_query = createQuery("internal$SchemaColumns");
361
1/1
✓ Branch 31 → 32 taken 19 times.
19 col_query->addConstraintForString("TableName", Constraints::EQUAL, table_name);
362
363 19 std::string col_name, dtype_str, default_val_str;
364
1/1
✓ Branch 36 → 37 taken 19 times.
19 col_query->select("ColumnName", col_name);
365
1/1
✓ Branch 38 → 39 taken 19 times.
19 col_query->select("ColumnDType", dtype_str);
366
1/1
✓ Branch 40 → 41 taken 19 times.
19 col_query->select("ColumnDefaultVal", default_val_str);
367
368
1/1
✓ Branch 42 → 43 taken 19 times.
19 auto col_results = col_query->getResultSet();
369
3/3
✓ Branch 102 → 103 taken 78 times.
✓ Branch 103 → 44 taken 59 times.
✓ Branch 103 → 104 taken 19 times.
97 while (col_results.getNextRecord())
370 {
371 using dt = SqlDataType;
372
3/4
✓ Branch 44 → 45 taken 3 times.
✓ Branch 44 → 50 taken 56 times.
✓ Branch 46 → 47 taken 3 times.
✗ Branch 46 → 50 not taken.
77 static std::unordered_map<std::string, dt> dtypes;
373
2/2
✓ Branch 51 → 52 taken 3 times.
✓ Branch 51 → 95 taken 56 times.
59 if (dtypes.empty())
374 {
375
2/2
✓ Branch 54 → 55 taken 3 times.
✓ Branch 55 → 56 taken 3 times.
6 dtypes["int32_t"] = dt::int32_t;
376
2/2
✓ Branch 60 → 61 taken 3 times.
✓ Branch 61 → 62 taken 3 times.
6 dtypes["uint32_t"] = dt::uint32_t;
377
2/2
✓ Branch 66 → 67 taken 3 times.
✓ Branch 67 → 68 taken 3 times.
6 dtypes["int64_t"] = dt::int64_t;
378
2/2
✓ Branch 72 → 73 taken 3 times.
✓ Branch 73 → 74 taken 3 times.
6 dtypes["uint64_t"] = dt::uint64_t;
379
2/2
✓ Branch 78 → 79 taken 3 times.
✓ Branch 79 → 80 taken 3 times.
6 dtypes["double_t"] = dt::double_t;
380
2/2
✓ Branch 84 → 85 taken 3 times.
✓ Branch 85 → 86 taken 3 times.
6 dtypes["string_t"] = dt::string_t;
381
2/2
✓ Branch 90 → 91 taken 3 times.
✓ Branch 91 → 92 taken 3 times.
6 dtypes["blob_t"] = dt::blob_t;
382 }
383
384
2/2
✓ Branch 95 → 96 taken 59 times.
✓ Branch 96 → 97 taken 59 times.
59 tbl.addColumn(col_name, dtypes.at(dtype_str));
385
2/2
✓ Branch 98 → 99 taken 15 times.
✓ Branch 98 → 102 taken 44 times.
59 if (!default_val_str.empty())
386 {
387
2/2
✓ Branch 99 → 100 taken 15 times.
✓ Branch 100 → 101 taken 15 times.
15 tbl.getColumn_(col_name).setDefaultValueStr_(default_val_str);
388 }
389 }
390
391 // Indexed columns could be:
392 // foo,bar|biz
393 // Which means:
394 // tbl.createCompoundIndexOn({"foo","bar"});
395 // tbl.createIndexOn("biz");
396
2/2
✓ Branch 105 → 106 taken 5 times.
✓ Branch 105 → 128 taken 14 times.
19 if (!indexed_columns.empty())
397 {
398 5 std::vector<std::string> index_strs;
399
2/2
✓ Branch 107 → 108 taken 5 times.
✓ Branch 108 → 109 taken 5 times.
5 boost::split(index_strs, indexed_columns, boost::is_any_of("|"));
400
2/2
✓ Branch 125 → 112 taken 6 times.
✓ Branch 125 → 126 taken 5 times.
11 for (const auto& index_str : index_strs)
401 {
402 6 std::vector<std::string> index_cols;
403
2/2
✓ Branch 114 → 115 taken 6 times.
✓ Branch 115 → 116 taken 6 times.
6 boost::split(index_cols, index_str, boost::is_any_of(","));
404
2/2
✓ Branch 118 → 119 taken 4 times.
✓ Branch 118 → 121 taken 2 times.
6 if (index_cols.size() == 1)
405 {
406
1/1
✓ Branch 120 → 122 taken 4 times.
4 tbl.createIndexOn(index_cols[0]);
407 } else
408 {
409
1/1
✓ Branch 121 → 122 taken 2 times.
2 tbl.createCompoundIndexOn(index_cols);
410 }
411 6 }
412 5 }
413
414
1/1
✓ Branch 128 → 129 taken 19 times.
19 tbl.setPrimaryKey(primary_key);
415 19 }
416 7 }
417
418 /// Open the given database file.
419 28 bool openDatabaseFile_(const PragmaPairs& pragmas)
420 {
421
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 28 times.
28 if (!db_conn_)
422 {
423 ✗ return false;
424 }
425
426
1/1
✓ Branch 6 → 7 taken 28 times.
28 auto db_filename = db_conn_->openDbFile_(db_file_);
427
2/2
✓ Branch 8 → 9 taken 27 times.
✓ Branch 8 → 26 taken 1 time.
28 if (!db_filename.empty())
428 {
429 // File opened without issues. Store the full DB filename.
430
1/1
✓ Branch 9 → 10 taken 27 times.
27 db_filepath_ = db_filename;
431
432 // Issue PRAGMA's
433
1/2
✗ Branch 24 → 12 not taken.
✓ Branch 24 → 25 taken 27 times.
27 for (const auto& [name, val] : pragmas)
434 {
435
0/4
✗ Branch 15 → 16 not taken.
✗ Branch 16 → 17 not taken.
✗ Branch 17 → 18 not taken.
✗ Branch 18 → 19 not taken.
✗ EXECUTE("PRAGMA " + name + " = " + val, false);
436 }
437
438 27 return true;
439 }
440
441 1 return false;
442 28 }
443
444 /// Serialize everything we know about the schema to the database.
445 60 void serializeSchema_()
446 {
447
1/1
✓ Branch 4 → 5 taken 60 times.
60 safeTransaction([&]() {
448
1/1
✓ Branch 2 → 3 taken 60 times.
60 removeAllRecordsFromTable("internal$SchemaTables");
449
1/1
✓ Branch 3 → 4 taken 60 times.
60 removeAllRecordsFromTable("internal$SchemaColumns");
450
451
1/1
✓ Branch 6 → 7 taken 60 times.
120 auto tbls_inserter = prepareINSERT_(SQL_TABLE("internal$SchemaTables"),
452
2/2
✓ Branch 4 → 5 taken 60 times.
✓ Branch 7 → 8 taken 60 times.
180 SQL_COLUMNS("TableName", "IndexedColumns", "PrimaryKey"));
453
454 auto cols_inserter =
455
1/1
✓ Branch 12 → 13 taken 60 times.
120 prepareINSERT_(SQL_TABLE("internal$SchemaColumns"),
456
2/2
✓ Branch 10 → 11 taken 60 times.
✓ Branch 13 → 14 taken 60 times.
180 SQL_COLUMNS("TableName", "ColumnName", "ColumnDType", "ColumnDefaultVal"));
457
458 96 auto commaSepStringList = [](const std::vector<std::string>& strings) {
459
1/1
✓ Branch 2 → 3 taken 96 times.
96 std::ostringstream oss;
460
2/2
✓ Branch 11 → 4 taken 127 times.
✓ Branch 11 → 12 taken 96 times.
223 for (size_t i = 0; i < strings.size(); ++i)
461 {
462
1/1
✓ Branch 5 → 6 taken 127 times.
127 oss << strings[i];
463
2/2
✓ Branch 7 → 8 taken 31 times.
✓ Branch 7 → 9 taken 96 times.
127 if (i != strings.size() - 1)
464 {
465
1/1
✓ Branch 8 → 9 taken 31 times.
31 oss << ",";
466 }
467 }
468
1/1
✓ Branch 12 → 13 taken 96 times.
192 return oss.str();
469 96 };
470
471
2/2
✓ Branch 104 → 19 taken 385 times.
✓ Branch 104 → 105 taken 60 times.
445 for (const auto& table : schema_.getTables())
472 {
473 385 const auto& table_name = table.getName();
474
475
1/1
✓ Branch 21 → 22 taken 385 times.
385 std::ostringstream indexes_oss;
476
3/3
✓ Branch 22 → 23 taken 385 times.
✓ Branch 32 → 25 taken 96 times.
✓ Branch 32 → 33 taken 385 times.
481 for (const auto& index_cols : table.getTableIndexes())
477 {
478
3/3
✓ Branch 26 → 27 taken 96 times.
✓ Branch 27 → 28 taken 96 times.
✓ Branch 28 → 29 taken 96 times.
96 indexes_oss << commaSepStringList(index_cols) << "|";
479 385 }
480
481
1/1
✓ Branch 34 → 35 taken 385 times.
385 auto indexed_cols = indexes_oss.str();
482
2/2
✓ Branch 36 → 37 taken 95 times.
✓ Branch 36 → 38 taken 290 times.
385 if (!indexed_cols.empty())
483 {
484 95 indexed_cols.pop_back();
485 }
486
487
1/1
✓ Branch 39 → 40 taken 385 times.
385 auto primary_key = table.getPrimaryKey();
488
489
1/1
✓ Branch 41 → 42 taken 385 times.
385 tbls_inserter->setColumnValue(0, table_name);
490
1/1
✓ Branch 43 → 44 taken 385 times.
385 tbls_inserter->setColumnValue(1, indexed_cols);
491
1/1
✓ Branch 45 → 46 taken 385 times.
385 tbls_inserter->setColumnValue(2, primary_key);
492
1/1
✓ Branch 47 → 48 taken 385 times.
385 tbls_inserter->createRecord();
493
494
2/2
✓ Branch 98 → 51 taken 1104 times.
✓ Branch 98 → 99 taken 385 times.
1489 for (const auto& column : table.getColumns())
495 {
496 using dt = SqlDataType;
497
3/4
✓ Branch 52 → 53 taken 14 times.
✓ Branch 52 → 58 taken 1090 times.
✓ Branch 54 → 55 taken 14 times.
✗ Branch 54 → 58 not taken.
1104 static std::unordered_map<dt, std::string> dtype_strs;
498
2/2
✓ Branch 59 → 60 taken 14 times.
✓ Branch 59 → 75 taken 1090 times.
1104 if (dtype_strs.empty())
499 {
500
2/2
✓ Branch 60 → 61 taken 14 times.
✓ Branch 61 → 62 taken 14 times.
14 dtype_strs[dt::int32_t] = "int32_t";
501
2/2
✓ Branch 62 → 63 taken 14 times.
✓ Branch 63 → 64 taken 14 times.
14 dtype_strs[dt::uint32_t] = "uint32_t";
502
2/2
✓ Branch 64 → 65 taken 14 times.
✓ Branch 65 → 66 taken 14 times.
14 dtype_strs[dt::int64_t] = "int64_t";
503
2/2
✓ Branch 66 → 67 taken 14 times.
✓ Branch 67 → 68 taken 14 times.
14 dtype_strs[dt::uint64_t] = "uint64_t";
504
2/2
✓ Branch 68 → 69 taken 14 times.
✓ Branch 69 → 70 taken 14 times.
14 dtype_strs[dt::double_t] = "double_t";
505
2/2
✓ Branch 70 → 71 taken 14 times.
✓ Branch 71 → 72 taken 14 times.
14 dtype_strs[dt::string_t] = "string_t";
506
2/2
✓ Branch 72 → 73 taken 14 times.
✓ Branch 73 → 74 taken 14 times.
14 dtype_strs[dt::blob_t] = "blob_t";
507 }
508
509 1104 const auto& column_name = column->getName();
510
2/2
✓ Branch 79 → 80 taken 1104 times.
✓ Branch 80 → 81 taken 1104 times.
1104 const auto column_dtype_str = dtype_strs.at(column->getDataType());
511
1/1
✓ Branch 83 → 84 taken 1104 times.
1104 const auto column_default_str = column->getDefaultValueAsString();
512
513
1/1
✓ Branch 85 → 86 taken 1104 times.
1104 cols_inserter->setColumnValue(0, table_name);
514
1/1
✓ Branch 87 → 88 taken 1104 times.
1104 cols_inserter->setColumnValue(1, column_name);
515
1/1
✓ Branch 89 → 90 taken 1104 times.
1104 cols_inserter->setColumnValue(2, column_dtype_str);
516
1/1
✓ Branch 91 → 92 taken 1104 times.
1104 cols_inserter->setColumnValue(3, column_default_str);
517
1/1
✓ Branch 93 → 94 taken 1104 times.
1104 cols_inserter->createRecord();
518 1104 }
519 385 }
520 60 });
521 60 }
522
523 /// \see See public INSERT() method for details on how to call this method.
524 210367 std::unique_ptr<SqlRecord> INSERT_(SqlTable&& table, SqlColumns&& cols, SqlValues&& vals)
525 {
526 210367 std::unique_ptr<SqlRecord> record;
527
528
2/2
✓ Branch 4 → 5 taken 210367 times.
✓ Branch 5 → 6 taken 210364 times.
210370 db_conn_->safeTransaction([&]() {
529
1/1
✓ Branch 2 → 3 taken 210367 times.
210367 std::ostringstream oss;
530
2/2
✓ Branch 3 → 4 taken 210367 times.
✓ Branch 5 → 6 taken 210367 times.
210367 oss << "INSERT INTO " << table.getName();
531
1/1
✓ Branch 6 → 7 taken 210367 times.
210367 cols.writeColsForINSERT(oss);
532
1/1
✓ Branch 7 → 8 taken 210367 times.
210367 vals.writeValsForINSERT(oss);
533
534
1/1
✓ Branch 8 → 9 taken 210367 times.
210367 std::string cmd = oss.str();
535
1/1
✓ Branch 11 → 12 taken 210365 times.
210367 auto stmt = db_conn_->prepareStatement(cmd);
536
1/1
✓ Branch 13 → 14 taken 210365 times.
210365 vals.bindValsForINSERT(stmt);
537
538
2/2
✓ Branch 15 → 16 taken 210365 times.
✓ Branch 16 → 17 taken 210365 times.
210365 auto rc = SQLiteReturnCode(sqlite3_step(stmt));
539
14/14
✓ Branch 18 → 19 taken 1 time.
✓ Branch 18 → 41 taken 210364 times.
✓ Branch 21 → 22 taken 1 time.
✓ Branch 22 → 23 taken 1 time.
✓ Branch 24 → 25 taken 1 time.
✓ Branch 28 → 29 taken 1 time.
✓ Branch 31 → 32 taken 1 time.
✓ Branch 32 → 33 taken 1 time.
✓ Branch 33 → 34 taken 1 time.
✓ Branch 34 → 35 taken 1 time.
✓ Branch 35 → 36 taken 1 time.
✓ Branch 36 → 37 taken 1 time.
✓ Branch 37 → 38 taken 1 time.
✓ Branch 39 → 40 taken 1 time.
210367 simdb_assert(rc == SQLITE_DONE,
540 "Could not perform INSERT. Error: " << sqlite3_errmsg(db_conn_->getDatabase()));
541
542
1/1
✓ Branch 42 → 43 taken 210364 times.
210364 auto db_id = db_conn_->getLastInsertRowId();
543
2/4
✓ Branch 43 → 44 taken 210364 times.
✓ Branch 48 → 49 taken 210364 times.
✗ Branch 70 → 71 not taken.
✗ Branch 70 → 72 not taken.
210364 record.reset(new SqlRecord(table.getName(), db_id, db_conn_->getDatabase(), db_conn_.get()));
544 210371 });
545
546 210364 return record;
547 3 }
548
549 /// \see See public INSERT() method for details on how to call this method.
550 1 std::unique_ptr<SqlRecord> INSERT_(SqlTable&& table)
551 {
552 1 std::unique_ptr<SqlRecord> record;
553
554
2/2
✓ Branch 4 → 5 taken 1 time.
✓ Branch 5 → 6 taken 1 time.
1 db_conn_->safeTransaction([&]() {
555
2/2
✓ Branch 3 → 4 taken 1 time.
✓ Branch 4 → 5 taken 1 time.
1 const std::string cmd = "INSERT INTO " + table.getName() + " DEFAULT VALUES";
556
1/1
✓ Branch 8 → 9 taken 1 time.
1 auto stmt = db_conn_->prepareStatement(cmd);
557
558
2/2
✓ Branch 10 → 11 taken 1 time.
✓ Branch 11 → 12 taken 1 time.
1 auto rc = SQLiteReturnCode(sqlite3_step(stmt));
559
1/14
✗ Branch 13 → 14 not taken.
✓ Branch 13 → 36 taken 1 time.
✗ Branch 16 → 17 not taken.
✗ Branch 17 → 18 not taken.
✗ Branch 19 → 20 not taken.
✗ Branch 23 → 24 not taken.
✗ Branch 26 → 27 not taken.
✗ Branch 27 → 28 not taken.
✗ Branch 28 → 29 not taken.
✗ Branch 29 → 30 not taken.
✗ Branch 30 → 31 not taken.
✗ Branch 31 → 32 not taken.
✗ Branch 32 → 33 not taken.
✗ Branch 34 → 35 not taken.
1 simdb_assert(rc == SQLITE_DONE,
560 "Could not perform INSERT. Error: " << sqlite3_errmsg(db_conn_->getDatabase()));
561
562
1/1
✓ Branch 37 → 38 taken 1 time.
1 auto db_id = db_conn_->getLastInsertRowId();
563
2/4
✓ Branch 38 → 39 taken 1 time.
✓ Branch 43 → 44 taken 1 time.
✗ Branch 67 → 68 not taken.
✗ Branch 67 → 69 not taken.
1 record.reset(new SqlRecord(table.getName(), db_id, db_conn_->getDatabase(), db_conn_.get()));
564 1 });
565
566 1 return record;
567 ✗ }
568
569 /// \see See public prepareINSERT() method for details on how to call this method.
570 218 std::unique_ptr<PreparedINSERT> prepareINSERT_(SqlTable&& table, SqlColumns&& cols)
571 {
572
1/1
✓ Branch 6 → 7 taken 218 times.
218 const std::set<std::string> col_names(cols.getColNames().begin(), cols.getColNames().end());
573
574 218 std::vector<SqlDataType> col_dtypes;
575
3/3
✓ Branch 9 → 10 taken 218 times.
✓ Branch 24 → 13 taken 680 times.
✓ Branch 24 → 25 taken 218 times.
898 for (const auto& col : schema_.getTable(table.getName()).getColumns())
576 {
577
2/3
✓ Branch 16 → 17 taken 680 times.
✓ Branch 17 → 18 taken 680 times.
✗ Branch 17 → 22 not taken.
680 if (col_names.count(col->getName()))
578 {
579
1/1
✓ Branch 20 → 21 taken 680 times.
680 col_dtypes.push_back(col->getDataType());
580 }
581 }
582
583
1/1
✓ Branch 25 → 26 taken 218 times.
218 std::ostringstream oss;
584
3/3
✓ Branch 26 → 27 taken 218 times.
✓ Branch 28 → 29 taken 218 times.
✓ Branch 29 → 30 taken 218 times.
218 oss << "INSERT INTO " << table.getName() << " (";
585
586 218 auto it = cols.getColNames().begin();
587 while (true)
588 {
589
1/1
✓ Branch 33 → 34 taken 680 times.
680 oss << *it;
590
2/2
✓ Branch 38 → 39 taken 462 times.
✓ Branch 38 → 40 taken 218 times.
680 if (++it != cols.getColNames().end())
591 {
592
1/1
✓ Branch 39 → 41 taken 462 times.
462 oss << ",";
593 } else
594 {
595 218 break;
596 }
597 }
598
599
1/1
✓ Branch 42 → 43 taken 218 times.
218 oss << ") VALUES (";
600
2/2
✓ Branch 52 → 44 taken 680 times.
✓ Branch 52 → 53 taken 218 times.
898 for (size_t i = 0; i < col_dtypes.size(); ++i)
601 {
602
4/4
✓ Branch 44 → 45 taken 680 times.
✓ Branch 46 → 47 taken 462 times.
✓ Branch 46 → 48 taken 218 times.
✓ Branch 49 → 50 taken 680 times.
680 oss << "?" << (i != col_dtypes.size() - 1 ? "," : "");
603 }
604
1/1
✓ Branch 53 → 54 taken 218 times.
218 oss << ")";
605
606
1/1
✓ Branch 54 → 55 taken 218 times.
218 std::string cmd = oss.str();
607
1/1
✓ Branch 57 → 58 taken 218 times.
218 auto stmt = db_conn_->prepareStatement(cmd);
608
609
1/1
✓ Branch 59 → 60 taken 218 times.
436 return std::make_unique<PreparedINSERT>(std::move(stmt), col_dtypes, db_conn_);
610 218 }
611
612 /// Get a SqlRecord from a database ID for the given table.
613 16 std::unique_ptr<SqlRecord> findRecord_(const char* table_name, const int db_id, const bool must_exist) const
614 {
615
1/1
✓ Branch 2 → 3 taken 16 times.
16 std::ostringstream oss;
616
4/4
✓ Branch 3 → 4 taken 16 times.
✓ Branch 4 → 5 taken 16 times.
✓ Branch 5 → 6 taken 16 times.
✓ Branch 6 → 7 taken 16 times.
16 oss << "SELECT * FROM " << table_name << " WHERE Id=" << db_id;
617
1/1
✓ Branch 7 → 8 taken 16 times.
16 const auto cmd = oss.str();
618
619
1/1
✓ Branch 11 → 12 taken 16 times.
16 auto stmt = SQLitePreparedStatement(db_conn_->getDatabase(), cmd);
620
2/2
✓ Branch 13 → 14 taken 16 times.
✓ Branch 14 → 15 taken 16 times.
16 auto rc = SQLiteReturnCode(sqlite3_step(stmt));
621
622
2/19
✗ Branch 15 → 16 not taken.
✓ Branch 15 → 19 taken 16 times.
✗ Branch 17 → 18 not taken.
✗ Branch 17 → 19 not taken.
✗ Branch 20 → 21 not taken.
✓ Branch 20 → 42 taken 16 times.
✗ Branch 23 → 24 not taken.
✗ Branch 24 → 25 not taken.
✗ Branch 26 → 27 not taken.
✗ Branch 30 → 31 not taken.
✗ Branch 31 → 32 not taken.
✗ Branch 32 → 33 not taken.
✗ Branch 33 → 34 not taken.
✗ Branch 34 → 35 not taken.
✗ Branch 35 → 36 not taken.
✗ Branch 36 → 37 not taken.
✗ Branch 37 → 38 not taken.
✗ Branch 38 → 39 not taken.
✗ Branch 40 → 41 not taken.
16 simdb_assert(!(must_exist && rc == SQLITE_DONE),
623 "Record not found with ID " << db_id << " in table " << table_name);
624
2/2
✓ Branch 43 → 44 taken 2 times.
✓ Branch 43 → 45 taken 14 times.
16 if (rc == SQLITE_DONE)
625 {
626 2 return nullptr;
627 }
628
1/2
✓ Branch 46 → 47 taken 14 times.
✗ Branch 46 → 59 not taken.
14 if (rc == SQLITE_ROW)
629 {
630 return std::unique_ptr<SqlRecord>(
631
3/5
✓ Branch 47 → 48 taken 14 times.
✓ Branch 53 → 54 taken 14 times.
✓ Branch 54 → 55 taken 14 times.
✗ Branch 95 → 96 not taken.
✗ Branch 95 → 97 not taken.
42 new SqlRecord(table_name, db_id, db_conn_->getDatabase(), db_conn_.get()));
632 }
633
0/4
✗ Branch 61 → 62 not taken.
✗ Branch 64 → 65 not taken.
✗ Branch 65 → 66 not taken.
✗ Branch 66 → 67 not taken.
✗ throw DBException("Internal error has occured: ") << sqlite3_errmsg(db_conn_->getDatabase());
634 16 }
635
636 /// Database connection.
637 std::shared_ptr<Connection> db_conn_;
638
639 /// Schema for this database.
640 Schema schema_;
641
642 /// Name of the database file.
643 const std::string db_file_;
644
645 /// Full database file name, including the database path
646 /// and file extension
647 std::string db_filepath_;
648 };
649
650 } // namespace simdb
651