Stroika Library 3.0d18
 
Loading...
Searching...
No Matches
SQL/SQLite.h
Go to the documentation of this file.
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#ifndef _Stroika_Foundation_Database_SQL_SQLite_h_
5#define _Stroika_Foundation_Database_SQL_SQLite_h_ 1
6
7#include "Stroika/Foundation/StroikaPreComp.h"
8
9#include <filesystem>
10#include <optional>
11
12#if qStroika_HasComponent_sqlite
13#include <sqlite/sqlite3.h>
14#endif
15
17#include "Stroika/Foundation/Common/Property.h"
18#include "Stroika/Foundation/Containers/Mapping.h"
19#include "Stroika/Foundation/Containers/Sequence.h"
27
28/**
29 * \file
30 *
31 * \note Code-Status: <a href="Code-Status.md#Beta">Beta</a>
32 *
33 * TODO
34 * @todo Create SQLite Exception class and use sqlite3_errstr () to generate good string
35 * message (that seems to return threadsafe static const strings)
36 */
37
38namespace Stroika::Foundation::Database::SQL::SQLite {
39
40 using Characters::String;
41 using Containers::Mapping;
42 using Containers::Sequence;
43 using DataExchange::VariantValue;
44 using IO::Network::URI;
45 using Time::Duration;
46
47#if qStroika_HasComponent_sqlite
48
49 /**
50 * This defines what options sqlite was compiled with.
51 *
52 * For a full list of possible options, see <https://www.sqlite.org/compile.html>
53 * (though we only capture a limited subset of these). To check the rest, callers
54 * can use ::sqlite3_compileoption_used ()
55 *
56 * Fields correspond to names looked up with ::sqlite3_compileoption_used () - only this is constexpr (and an incomplete replica).
57 * This is checked to correspond to the sqlite3_compileoption_used() values at startup with assertions.
58 *
59 * \todo Find a better way to define! We want this to be available as a constexpr object. But the defines
60 * are just done in the .c file that gets defined and the API to lookup values is very non-constexpr.
61 *
62 * So instead we take a good guess at the values (based on defaults and #defines done in this file)
63 * and check with asserts we got the right value.
64 */
65 class CompiledOptions final {
66 public:
67 /**
68 * c++ #define SQLITE_ENABLE_NORMALIZE (not in docs file but does appear as a compile time option - we need to check)
69 */
70 bool ENABLE_NORMALIZE;
71
72 /**
73 * SQLITE_THREADSAFE = 0, 1, 2 (0 means no)
74 */
75 uint8_t THREADSAFE;
76
77 /**
78 * SQLITE_ENABLE_JSON1 = true (for now required)
79 */
80 bool ENABLE_JSON1;
81
82 /**
83 * Defined constexpr
84 */
85 static const CompiledOptions kThe;
86 };
87
88 /**
89 * https://www.sqlite.org/pragma.html#pragma_journal_mode
90 *
91 * In my experience, it appears WAL provides the best performance, for multithreaded applications.
92 * \see https://sqlite.org/wal.html
93 * "WAL provides more concurrency as readers do not block writers and a writer"
94 * "does not block readers. Reading and writing can proceed concurrently."
95 */
96 enum JournalModeType {
97 eDelete,
98 eTruncate,
99 ePersist,
100 eMemory,
101 eWAL,
102 eWAL2,
103 eOff
104 };
105
106 class Statement;
107
108 /**
109 * \brief SQLite::Connection namespace contains SQL::Connection::Ptr subclass, specific to SQLite, and ::New function factory.
110 */
111 namespace Connection {
112
113 using namespace SQL::Connection;
114
115 class IRep;
116
117 /**
118 * These are options used to create a database Connection::Ptr object (with Connection::New).
119 *
120 * Since this is also how you create a database, in a sense, its those options too.
121 */
122 struct Options final {
123 /**
124 * NOTE - we choose to only support a PATH, and not the URI syntax, because the URI syntax is used to pass
125 * extra parameters (as from a GUI) and those can conflict with what is specified here (making it unclear or
126 * surprising how to interpret). @todo perhaps provide an API to 'parse' an sqlite URI into one of these Stroika
127 * SQLite options objects?
128 *
129 * \note - fInMemoryDB and fDBPath and fTemporaryDB are mutually exclusive options.
130 */
131 optional<filesystem::path> fDBPath;
132
133 /**
134 * This option only applies if fDBPath is set.
135 * \pre fCreateDBPathIfDoesNotExist => not fReadOnly
136 */
137 bool fCreateDBPathIfDoesNotExist{true};
138
139 /**
140 * fTemporaryDB is just like fInMemoryDB, except that it will be written to disk. But its like temporaryDB in that
141 * it will be automatically deleted when this connection (that created it) closes.
142 *
143 * \note - fInMemoryDB and fDBPath and fTemporaryDB are mutually exclusive options.
144 */
145 optional<String> fTemporaryDB;
146
147 /**
148 * If provided, the database will not be stored to disk, but just saved in memory. The name still must be provided to allow
149 * for sharing the same (in memory) database between different connections). If the name is the empty string (String{}) then
150 * it is guaranteed unique.
151 *
152 * \note - fInMemoryDB and fDBPath and fTemporaryDB are mutually exclusive options.
153 *
154 * \note using a named in-memory-db allows two separate threads in the same process, to share the same database.
155 */
156 optional<String> fInMemoryDB;
157
158 /**
159 * @see https://www.sqlite.org/compile.html#threadsafe
160 *
161 * Note this refers to the threading mode for the underlying database. A Connection object is always single-threaded/externally
162 * synchronized.
163 */
164 enum class ThreadingMode {
165 /**
166 * SQLITE_OPEN_FULLMUTEX
167 * In this mode, all mutexes are disabled and SQLite is unsafe to use in more than a single thread at once
168 */
169 eSingleThread,
170
171 /**
172 * SQLITE_OPEN_NOMUTEX
173 * In this mode, SQLite can be safely used by multiple threads provided that no single database connection is used simultaneously in two or more threads.
174 * (Stroika Debug::AssertExternallySynchronizedMutex enforces this)
175 *
176 * This may not always be available depending on how sqlite was compiled, but we dont have access to SQLITE_THREADSAFE at compile time
177 * (since just defined in C file from Stroika/ThirdPartyComponents/sqlite/Makefile);
178 * call sqlite3_threadsafe, to see if this is enabled
179 */
180 eMultiThread,
181
182 /**
183 * SQLITE_OPEN_FULLMUTEX
184 * In serialized mode, SQLite can be safely used by multiple threads with no restriction.
185 * (note even in this mode, each connection is Debug::AssertExternallySynchronizedMutex)
186 *
187 * This may not always be available depending on how sqlite was compiled, but we dont have access to SQLITE_THREADSAFE at compile time
188 * (since just defined in C file from Stroika/ThirdPartyComponents/sqlite/Makefile);
189 * call sqlite3_threadsafe, to see if this is enabled
190 *
191 * \note Use of this API, as of Stroika 2.1b12, may result in poor error messages, due to how errors are stored (and maybe other such
192 * issues - maybe we need to do lock around call to each function to avoid making this mode nearly pointless).
193 */
194 eSerialized,
195 };
196 optional<ThreadingMode> fThreadingMode;
197
198 /**
199 * I'm quite unsure I have this right, since seems to work so badly (frequent busy timeouts) - but from the docs this seems
200 * clear to be the best answer (best fit with the rest of how Stroika works).
201 */
202 static inline constexpr auto kDefault_ThreadingMode = ThreadingMode::eMultiThread;
203
204 /**
205 * This can generally be ignored, and primarily affects low level OS interface locking choices.
206 * @see https://www.sqlite.org/vfs.html
207 */
208 optional<String> fVFS;
209
210 /**
211 * If a database is opened readonly, updates will fail, and if the database doesn't exist, it will not be automatically created.
212 */
213 bool fReadOnly{false};
214
215 /**
216 * The immutable query parameter is a boolean that signals to SQLite that the underlying database file is held on read-only media and
217 * cannot be modified, even by another process with elevated privileges.
218 *
219 * \pre fImmutable ==> fReadOnly
220 */
221 bool fImmutable{false};
222
223 /**
224 * This is only useful if the database can be opened by multiple threads of control (multiple threads with connections
225 * within the same app, or multiple applications).
226 *
227 * @see also https://www.sqlite.org/c3ref/busy_timeout.html
228 *
229 * This seems black magic. I try different values at random, and get inscrutable results when used (or not used).
230 * Example in sqlite docs says 100ms. It turns out, in my limited testing, that appears to work best. But what makes
231 * no sense, is that I generally get MORE busy timeout errors if I use a much larger value (like 500ms, or 5000ms).
232 * Its ALMOST as if the database was holding a lock (one connection) while retrying?
233 */
234 optional<Duration> fBusyTimeout;
235
236 /**
237 * \note - see JournalModeType and Connection::Ptr::journalMode
238 */
239 optional<JournalModeType> fJournalMode;
240 };
241
242 /**
243 * Connection provides an API for accessing an SQLite database.
244 *
245 * A new Connection::Ptr is typically created SQLite::Connection::New()
246 *
247 * \note \em Thread-Safety <a href="Thread-Safety.md#C++-Standard-Thread-Safety-For-Envelope-Plus-Must-Externally-Synchronize-Letter">C++-Standard-Thread-Safety-For-Envelope-Plus-Must-Externally-Synchronize-Letter</a>
248 * But though each connection can only be accessed from a single thread at a time, the underlying database may be
249 * threadsafe (even if accessed across processes) - depending on its construction OPtions::ThreadSafety
250 *
251 * The Connection itself is standardC++ thread safety. The thread-safety of the underlying database depends on the setting
252 * of Options::fThreadingMode when the database is constructed.
253 *
254 * @see https://www.sqlite.org/threadsafe.html
255 * We set SQLITE_OPEN_NOMUTEX on open (so mode Multi-thread, but not Serialized).
256 *
257 * NOTE - two Connection::Ptr objects refering to the same underlying REP is NOT (probably) safe with SQLITE. But referring
258 * to the same database is safe.
259 *
260 */
261 class Ptr : public SQL::Connection::Ptr {
262 private:
263 using inherited = SQL::Connection::Ptr;
264
265 public:
266 /**
267 */
268 Ptr (const Ptr& src);
269 Ptr (const shared_ptr<IRep>& src = nullptr);
270
271 public:
272 ~Ptr () = default;
273
274 public:
275 /**
276 */
277 nonvirtual Ptr& operator= (const Ptr& src);
278 nonvirtual Ptr& operator= (Ptr&& src) noexcept;
279
280 public:
281 /**
282 */
283 nonvirtual IRep* operator->() const noexcept;
284
285 public:
286 /**
287 * Use of Peek () is discouraged, and unsafe, but allowed for now because we don't have a full wrapper on the sqlite API.
288 */
289 nonvirtual ::sqlite3* Peek () const;
290
291 public:
292 /**
293 * When doing a query that would have failed due to SQL_BUSY timeout, sqlite will wait
294 * and retry up to this long, to avoid the timeout.
295 */
296 Common::Property<Duration> busyTimeout;
297
298 public:
299 /**
300 * This can significantly affect database performance, and reliability.
301 */
302 Common::Property<JournalModeType> journalMode;
303
304 private:
305 friend class Statement;
306 };
307
308 /**
309 * \brief create an SQLite database connection object, guided by argument Options.
310 */
311 Ptr New (const Options& options);
312
313 /**
314 * Connection provides an API for accessing an SQLite database.
315 *
316 * Typically don't use this directly, but use Connection::Ptr, a smart ptr wrapper on this interface.
317 *
318 * \note \em Thread-Safety <a href="Thread-Safety.md#C++-Standard-Thread-Safety">C++-Standard-Thread-Safety</a>
319 * But though each connection can only be accessed from a single thread at a time, the underlying database may be
320 * threadsafe (even if accessed across processes) - depending on its construction OPtions::ThreadSafety
321 *
322 * The Connection itself is standardC++ thread safety. The thread-safety of the underlying database depends on the setting
323 * of Options::fThreadingMode when the database is constructed.
324 *
325 * @see https://www.sqlite.org/threadsafe.html
326 * We set SQLITE_OPEN_NOMUTEX on open (so mode Multi-thread, but not Serialized).
327 *
328 * NOTE ALSO - its POSSIBLE we could lift this Debug::AssertExternallySynchronizedMutex code / restriction.
329 * But sqlite docs not super clear. Maybe I need to use thier locking APIs myself internally to use
330 * those locks to make a sequence of bindings safe? But for now just don't assume this is threadsafe and we'll be OK.
331 */
332 class IRep : public SQL::Connection::IRep {
333 public:
334 /**
335 * Use of Peek () is discouraged, and unsafe, but allowed for now because we don't have a full wrapper on the sqlite API.
336 */
337 virtual ::sqlite3* Peek () = 0;
338
339 public:
340 /**
341 * Fetched dynamically with pragma busy_timeout;
342 */
343 virtual Duration GetBusyTimeout () const = 0;
344
345 public:
346 /**
347 * \pre timeout >= 0
348 */
349 virtual void SetBusyTimeout (const Duration& timeout) = 0;
350
351 public:
352 /**
353 */
354 virtual JournalModeType GetJournalMode () const = 0;
355
356 public:
357 /**
358 */
359 virtual void SetJournalMode (JournalModeType journalMode) = 0;
360
361 public:
362 [[no_unique_address]] Debug::AssertExternallySynchronizedMutex fAssertExternallySynchronizedMutex;
363
364 private:
365 friend class Ptr;
366 };
367
368 }
369
370 /**
371 * \note \em Thread-Safety <a href="Thread-Safety.md#C++-Standard-Thread-Safety-For-Envelope-Plus-Must-Externally-Synchronize-Letter">C++-Standard-Thread-Safety-For-Envelope-Plus-Must-Externally-Synchronize-Letter</a>
372 * See notes about thread safety for Connection::Ptr - since this copies around a Connection::Ptr.
373 */
374 class Statement : public SQL::Statement {
375 private:
376 using inherited = SQL::Statement;
377
378 public:
379 /**
380 */
381 Statement () = delete;
382 Statement (const Connection::Ptr& db, const String& query);
383 Statement (const Statement&) = delete;
384
385 private:
386 struct MyRep_;
387 };
388
389 /**
390 * \see https://www.sqlite.org/lang_transaction.html
391 *
392 * \note Transactions are not required. This is for explicit transactions. If you omit
393 * using transactions, sqlite creates mini transactions automatically for each statement.
394 *
395 * \note Nested transactions not supported
396 *
397 * \todo Consider supporting SQLITE SAVEPOINT (like nested transaction)
398 */
399 class Transaction : public SQL::Transaction {
400 private:
401 using inherited = SQL::Transaction;
402
403 public:
404 enum Flag {
405 /**
406 * Don't really start the transaction until the command to read/update the database
407 */
408 eDeferred,
409
410 /**
411 * Start writing to the DB immediately (as of the transaction start); note this affects when you might
412 * get SQL_BUSY errors.
413 */
414 eImmediate,
415
416 /**
417 * Depends on WAL mode, but generally prevents other database connections from reading the
418 * database while the transaction is underway.
419 */
420 eExclusive,
421
422 eDEFAULT = eDeferred
423 };
424
425 public:
426 /**
427 */
428 Transaction () = delete;
429 Transaction (const Connection::Ptr& db, Flag f = Flag::eDEFAULT);
430 Transaction (const Transaction&) = delete;
431
432 private:
433 struct MyRep_;
434 };
435#endif
436
437}
438
439/*
440 ********************************************************************************
441 ***************************** Implementation Details ***************************
442 ********************************************************************************
443 */
444#include "SQLite.inl"
445
446#endif /*_Stroika_Foundation_Database_SQL_SQLite_h_*/