1 /**
2  * @file    Database.h
3  * @ingroup SQLiteCpp
4  * @brief   Management of a SQLite Database Connection.
5  *
6  * Copyright (c) 2012-2020 Sebastien Rombauts (sebastien.rombauts@gmail.com)
7  *
8  * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
9  * or copy at http://opensource.org/licenses/MIT)
10  */
11 #pragma once
12 
13 #include <SQLiteCpp/Column.h>
14 
15 // c++17: MinGW GCC version > 8
16 // c++17: Visual Studio 2017 version 15.7
17 #if ((__cplusplus >= 201703L) && ((!defined(__MINGW32__) && !defined(__MINGW64__)) || (__GNUC__ > 8))) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201703L))
18 #include  <filesystem>
19 #endif // c++17
20 
21 #include <memory>
22 #include <string.h>
23 
24 // Forward declarations to avoid inclusion of <sqlite3.h> in a header
25 struct sqlite3;
26 struct sqlite3_context;
27 
28 #ifndef SQLITE_USE_LEGACY_STRUCT // Since SQLITE 3.19 (used by default since SQLiteCpp 2.1.0)
29 typedef struct sqlite3_value sqlite3_value;
30 #else // Before SQLite 3.19 (legacy struct forward declaration can be activated with CMake SQLITECPP_LEGACY_STRUCT var)
31 struct Mem;
32 typedef struct Mem sqlite3_value;
33 #endif
34 
35 
36 namespace SQLite
37 {
38 
39 // Those public constants enable most usages of SQLiteCpp without including <sqlite3.h> in the client application.
40 
41 /// The database is opened in read-only mode. If the database does not already exist, an error is returned.
42 extern const int OPEN_READONLY;     // SQLITE_OPEN_READONLY
43 /// The database is opened for reading and writing if possible, or reading only if the file is write protected
44 /// by the operating system. In either case the database must already exist, otherwise an error is returned.
45 extern const int OPEN_READWRITE;    // SQLITE_OPEN_READWRITE
46 /// With OPEN_READWRITE: The database is opened for reading and writing, and is created if it does not already exist.
47 extern const int OPEN_CREATE;       // SQLITE_OPEN_CREATE
48 /// Enable URI filename interpretation, parsed according to RFC 3986 (ex. "file:data.db?mode=ro&cache=private")
49 extern const int OPEN_URI;          // SQLITE_OPEN_URI
50 /// Open in memory database
51 extern const int OPEN_MEMORY;       // SQLITE_OPEN_MEMORY
52 /// Open database in multi-thread threading mode
53 extern const int OPEN_NOMUTEX;      // SQLITE_OPEN_NOMUTEX
54 /// Open database with thread-safety in serialized threading mode
55 extern const int OPEN_FULLMUTEX;    // SQLITE_OPEN_FULLMUTEX
56 /// Open database with shared cache enabled
57 extern const int OPEN_SHAREDCACHE;  // SQLITE_OPEN_SHAREDCACHE
58 /// Open database with shared cache disabled
59 extern const int OPEN_PRIVATECACHE; // SQLITE_OPEN_PRIVATECACHE
60 /// Database filename is not allowed to be a symbolic link (Note: only since SQlite 3.31.0 from 2020-01-22)
61 extern const int OPEN_NOFOLLOW;     // SQLITE_OPEN_NOFOLLOW
62 
63 
64 extern const int OK;                ///< SQLITE_OK (used by check() bellow)
65 
66 extern const char*  VERSION;        ///< SQLITE_VERSION string from the sqlite3.h used at compile time
67 extern const int    VERSION_NUMBER; ///< SQLITE_VERSION_NUMBER from the sqlite3.h used at compile time
68 
69 /// Return SQLite version string using runtime call to the compiled library
70 const char* getLibVersion() noexcept;
71 /// Return SQLite version number using runtime call to the compiled library
72 int   getLibVersionNumber() noexcept;
73 
74 // Public structure for representing all fields contained within the SQLite header.
75 // Official documentation for fields: https://www.sqlite.org/fileformat.html#the_database_header
76 struct Header {
77     unsigned char headerStr[16];
78     unsigned int pageSizeBytes;
79     unsigned char fileFormatWriteVersion;
80     unsigned char fileFormatReadVersion;
81     unsigned char reservedSpaceBytes;
82     unsigned char maxEmbeddedPayloadFrac;
83     unsigned char minEmbeddedPayloadFrac;
84     unsigned char leafPayloadFrac;
85     unsigned long fileChangeCounter;
86     unsigned long  databaseSizePages;
87     unsigned long firstFreelistTrunkPage;
88     unsigned long totalFreelistPages;
89     unsigned long schemaCookie;
90     unsigned long schemaFormatNumber;
91     unsigned long defaultPageCacheSizeBytes;
92     unsigned long largestBTreePageNumber;
93     unsigned long databaseTextEncoding;
94     unsigned long userVersion;
95     unsigned long incrementalVaccumMode;
96     unsigned long applicationId;
97     unsigned long versionValidFor;
98     unsigned long sqliteVersion;
99 };
100 
101 /**
102  * @brief RAII management of a SQLite Database Connection.
103  *
104  * A Database object manage a list of all SQLite Statements associated with the
105  * underlying SQLite 3 database connection.
106  *
107  * Resource Acquisition Is Initialization (RAII) means that the Database Connection
108  * is opened in the constructor and closed in the destructor, so that there is
109  * no need to worry about memory management or the validity of the underlying SQLite Connection.
110  *
111  * Thread-safety: a Database object shall not be shared by multiple threads, because :
112  * 1) in the SQLite "Thread Safe" mode, "SQLite can be safely used by multiple threads
113  *    provided that no single database connection is used simultaneously in two or more threads."
114  * 2) the SQLite "Serialized" mode is not supported by SQLiteC++,
115  *    because of the way it shares the underling SQLite precompiled statement
116  *    in a custom shared pointer (See the inner class "Statement::Ptr").
117  */
118 class Database
119 {
120     friend class Statement; // Give Statement constructor access to the mSQLitePtr Connection Handle
121 
122 public:
123     /**
124      * @brief Open the provided database UTF-8 filename.
125      *
126      * Uses sqlite3_open_v2() with readonly default flag, which is the opposite behavior
127      * of the old sqlite3_open() function (READWRITE+CREATE).
128      * This makes sense if you want to use it on a readonly filesystem
129      * or to prevent creation of a void file when a required file is missing.
130      *
131      * Exception is thrown in case of error, then the Database object is NOT constructed.
132      *
133      * @param[in] apFilename        UTF-8 path/uri to the database file ("filename" sqlite3 parameter)
134      * @param[in] aFlags            SQLite::OPEN_READONLY/SQLite::OPEN_READWRITE/SQLite::OPEN_CREATE...
135      * @param[in] aBusyTimeoutMs    Amount of milliseconds to wait before returning SQLITE_BUSY (see setBusyTimeout())
136      * @param[in] apVfs             UTF-8 name of custom VFS to use, or nullptr for sqlite3 default
137      *
138      * @throw SQLite::Exception in case of error
139      */
140     Database(const char* apFilename,
141              const int   aFlags         = SQLite::OPEN_READONLY,
142              const int   aBusyTimeoutMs = 0,
143              const char* apVfs          = nullptr);
144 
145     /**
146      * @brief Open the provided database UTF-8 filename.
147      *
148      * Uses sqlite3_open_v2() with readonly default flag, which is the opposite behavior
149      * of the old sqlite3_open() function (READWRITE+CREATE).
150      * This makes sense if you want to use it on a readonly filesystem
151      * or to prevent creation of a void file when a required file is missing.
152      *
153      * Exception is thrown in case of error, then the Database object is NOT constructed.
154      *
155      * @param[in] aFilename         UTF-8 path/uri to the database file ("filename" sqlite3 parameter)
156      * @param[in] aFlags            SQLite::OPEN_READONLY/SQLite::OPEN_READWRITE/SQLite::OPEN_CREATE...
157      * @param[in] aBusyTimeoutMs    Amount of milliseconds to wait before returning SQLITE_BUSY (see setBusyTimeout())
158      * @param[in] aVfs              UTF-8 name of custom VFS to use, or empty string for sqlite3 default
159      *
160      * @throw SQLite::Exception in case of error
161      */
162     Database(const std::string& aFilename,
163              const int          aFlags          = SQLite::OPEN_READONLY,
164              const int          aBusyTimeoutMs  = 0,
165              const std::string& aVfs            = "") :
166         Database(aFilename.c_str(), aFlags, aBusyTimeoutMs, aVfs.empty() ? nullptr : aVfs.c_str())
167     {
168     }
169 
170     // c++17: MinGW GCC version > 8
171     // c++17: Visual Studio 2017 version 15.7
172     #if ((__cplusplus >= 201703L) && ((!defined(__MINGW32__) && !defined(__MINGW64__)) || (__GNUC__ > 8))) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201703L))
173 
174     /**
175      * @brief Open the provided database std::filesystem::path.
176      *
177      * @note This feature requires std=C++17
178      *
179      * Uses sqlite3_open_v2() with readonly default flag, which is the opposite behavior
180      * of the old sqlite3_open() function (READWRITE+CREATE).
181      * This makes sense if you want to use it on a readonly filesystem
182      * or to prevent creation of a void file when a required file is missing.
183      *
184      * Exception is thrown in case of error, then the Database object is NOT constructed.
185      *
186      * @param[in] apFilename        Path/uri to the database file ("filename" sqlite3 parameter)
187      * @param[in] aFlags            SQLite::OPEN_READONLY/SQLite::OPEN_READWRITE/SQLite::OPEN_CREATE...
188      * @param[in] aBusyTimeoutMs    Amount of milliseconds to wait before returning SQLITE_BUSY (see setBusyTimeout())
189      * @param[in] apVfs             UTF-8 name of custom VFS to use, or nullptr for sqlite3 default
190      *
191      * @throw SQLite::Exception in case of error
192      */
193     Database(const std::filesystem::path& apFilename,
194              const int   aFlags         = SQLite::OPEN_READONLY,
195              const int   aBusyTimeoutMs = 0,
196              const std::string& aVfs            = "") :
197         Database(reinterpret_cast<const char*>(apFilename.u8string().c_str()),
198                  aFlags, aBusyTimeoutMs, aVfs.empty() ? nullptr : aVfs.c_str())
199     {
200     }
201 
202     #endif // c++17
203 
204     // Database is non-copyable
205     Database(const Database&) = delete;
206     Database& operator=(const Database&) = delete;
207 
208     // Database is movable
209     Database(Database&& aDatabase) = default;
210     Database& operator=(Database&& aDatabase) = default;
211 
212     /**
213      * @brief Close the SQLite database connection.
214      *
215      * All SQLite statements must have been finalized before,
216      * so all Statement objects must have been unregistered.
217      *
218      * @warning assert in case of error
219      */
220     ~Database() = default;
221 
222     // Deleter functor to use with smart pointers to close the SQLite database connection in an RAII fashion.
223     struct Deleter
224     {
225         void operator()(sqlite3* apSQLite);
226     };
227 
228     /**
229      * @brief Set a busy handler that sleeps for a specified amount of time when a table is locked.
230      *
231      *  This is useful in multithreaded program to handle case where a table is locked for writing by a thread.
232      * Any other thread cannot access the table and will receive a SQLITE_BUSY error:
233      * setting a timeout will wait and retry up to the time specified before returning this SQLITE_BUSY error.
234      *  Reading the value of timeout for current connection can be done with SQL query "PRAGMA busy_timeout;".
235      *  Default busy timeout is 0ms.
236      *
237      * @param[in] aBusyTimeoutMs    Amount of milliseconds to wait before returning SQLITE_BUSY
238      *
239      * @throw SQLite::Exception in case of error
240      */
241     void setBusyTimeout(const int aBusyTimeoutMs);
242 
243     /**
244      * @brief Shortcut to execute one or multiple statements without results.
245      *
246      *  This is useful for any kind of statements other than the Data Query Language (DQL) "SELECT" :
247      *  - Data Manipulation Language (DML) statements "INSERT", "UPDATE" and "DELETE"
248      *  - Data Definition Language (DDL) statements "CREATE", "ALTER" and "DROP"
249      *  - Data Control Language (DCL) statements "GRANT", "REVOKE", "COMMIT" and "ROLLBACK"
250      *
251      * @see Database::tryExec() to execute, returning the sqlite result code
252      * @see Statement::exec() to handle precompiled statements (for better performances) without results
253      * @see Statement::executeStep() to handle "SELECT" queries with results
254      *
255      * @param[in] apQueries  one or multiple UTF-8 encoded, semicolon-separate SQL statements
256      *
257      * @return number of rows modified by the *last* INSERT, UPDATE or DELETE statement (beware of multiple statements)
258      * @warning undefined for CREATE or DROP table: returns the value of a previous INSERT, UPDATE or DELETE statement.
259      *
260      * @throw SQLite::Exception in case of error
261      */
262     int exec(const char* apQueries);
263 
264     /**
265      * @brief Shortcut to execute one or multiple statements without results.
266      *
267      *  This is useful for any kind of statements other than the Data Query Language (DQL) "SELECT" :
268      *  - Data Manipulation Language (DML) statements "INSERT", "UPDATE" and "DELETE"
269      *  - Data Definition Language (DDL) statements "CREATE", "ALTER" and "DROP"
270      *  - Data Control Language (DCL) statements "GRANT", "REVOKE", "COMMIT" and "ROLLBACK"
271      *
272      * @see Database::tryExec() to execute, returning the sqlite result code
273      * @see Statement::exec() to handle precompiled statements (for better performances) without results
274      * @see Statement::executeStep() to handle "SELECT" queries with results
275      *
276      * @param[in] aQueries  one or multiple UTF-8 encoded, semicolon-separate SQL statements
277      *
278      * @return number of rows modified by the *last* INSERT, UPDATE or DELETE statement (beware of multiple statements)
279      * @warning undefined for CREATE or DROP table: returns the value of a previous INSERT, UPDATE or DELETE statement.
280      *
281      * @throw SQLite::Exception in case of error
282      */
exec(const std::string & aQueries)283     int exec(const std::string& aQueries)
284     {
285         return exec(aQueries.c_str());
286     }
287 
288     /**
289      * @brief Try to execute one or multiple statements, returning the sqlite result code.
290      *
291      *  This is useful for any kind of statements other than the Data Query Language (DQL) "SELECT" :
292      *  - Data Manipulation Language (DML) statements "INSERT", "UPDATE" and "DELETE"
293      *  - Data Definition Language (DDL) statements "CREATE", "ALTER" and "DROP"
294      *  - Data Control Language (DCL) statements "GRANT", "REVOKE", "COMMIT" and "ROLLBACK"
295      *
296      * @see exec() to execute, returning number of rows modified
297      *
298      * @param[in] aQueries  one or multiple UTF-8 encoded, semicolon-separate SQL statements
299      *
300      * @return the sqlite result code.
301      */
302     int tryExec(const char* apQueries) noexcept;
303 
304     /**
305      * @brief Try to execute one or multiple statements, returning the sqlite result code.
306      *
307      *  This is useful for any kind of statements other than the Data Query Language (DQL) "SELECT" :
308      *  - Data Manipulation Language (DML) statements "INSERT", "UPDATE" and "DELETE"
309      *  - Data Definition Language (DDL) statements "CREATE", "ALTER" and "DROP"
310      *  - Data Control Language (DCL) statements "GRANT", "REVOKE", "COMMIT" and "ROLLBACK"
311      *
312      * @see exec() to execute, returning number of rows modified
313      *
314      * @param[in] aQueries  one or multiple UTF-8 encoded, semicolon-separate SQL statements
315      *
316      * @return the sqlite result code.
317      */
tryExec(const std::string aQueries)318     int tryExec(const std::string aQueries) noexcept
319     {
320         return tryExec(aQueries.c_str());
321     }
322 
323     /**
324      * @brief Shortcut to execute a one step query and fetch the first column of the result.
325      *
326      *  This is a shortcut to execute a simple statement with a single result.
327      * This should be used only for non reusable queries (else you should use a Statement with bind()).
328      * This should be used only for queries with expected results (else an exception is fired).
329      *
330      * @warning WARNING: Be very careful with this dangerous method: you have to
331      *          make a COPY OF THE result, else it will be destroy before the next line
332      *          (when the underlying temporary Statement and Column objects are destroyed)
333      *
334      * @see also Statement class for handling queries with multiple results
335      *
336      * @param[in] apQuery  an UTF-8 encoded SQL query
337      *
338      * @return a temporary Column object with the first column of result.
339      *
340      * @throw SQLite::Exception in case of error
341      */
342     Column execAndGet(const char* apQuery);
343 
344     /**
345      * @brief Shortcut to execute a one step query and fetch the first column of the result.
346      *
347      *  This is a shortcut to execute a simple statement with a single result.
348      * This should be used only for non reusable queries (else you should use a Statement with bind()).
349      * This should be used only for queries with expected results (else an exception is fired).
350      *
351      * @warning WARNING: Be very careful with this dangerous method: you have to
352      *          make a COPY OF THE result, else it will be destroy before the next line
353      *          (when the underlying temporary Statement and Column objects are destroyed)
354      *
355      * @see also Statement class for handling queries with multiple results
356      *
357      * @param[in] aQuery  an UTF-8 encoded SQL query
358      *
359      * @return a temporary Column object with the first column of result.
360      *
361      * @throw SQLite::Exception in case of error
362      */
execAndGet(const std::string & aQuery)363     Column execAndGet(const std::string& aQuery)
364     {
365         return execAndGet(aQuery.c_str());
366     }
367 
368     /**
369      * @brief Shortcut to test if a table exists.
370      *
371      *  Table names are case sensitive.
372      *
373      * @param[in] apTableName an UTF-8 encoded case sensitive Table name
374      *
375      * @return true if the table exists.
376      *
377      * @throw SQLite::Exception in case of error
378      */
379     bool tableExists(const char* apTableName);
380 
381     /**
382      * @brief Shortcut to test if a table exists.
383      *
384      *  Table names are case sensitive.
385      *
386      * @param[in] aTableName an UTF-8 encoded case sensitive Table name
387      *
388      * @return true if the table exists.
389      *
390      * @throw SQLite::Exception in case of error
391      */
tableExists(const std::string & aTableName)392     bool tableExists(const std::string& aTableName)
393     {
394         return tableExists(aTableName.c_str());
395     }
396 
397     /**
398      * @brief Get the rowid of the most recent successful INSERT into the database from the current connection.
399      *
400      *  Each entry in an SQLite table always has a unique 64-bit signed integer key called the rowid.
401      * If the table has a column of type INTEGER PRIMARY KEY, then it is an alias for the rowid.
402      *
403      * @return Rowid of the most recent successful INSERT into the database, or 0 if there was none.
404      */
405     long long getLastInsertRowid() const noexcept;
406 
407     /// Get total number of rows modified by all INSERT, UPDATE or DELETE statement since connection (not DROP table).
408     int getTotalChanges() const noexcept;
409 
410     /// Return the numeric result code for the most recent failed API call (if any).
411     int getErrorCode() const noexcept;
412     /// Return the extended numeric result code for the most recent failed API call (if any).
413     int getExtendedErrorCode() const noexcept;
414     /// Return UTF-8 encoded English language explanation of the most recent failed API call (if any).
415     const char* getErrorMsg() const noexcept;
416 
417     /// Return the filename used to open the database.
getFilename()418     const std::string& getFilename() const noexcept
419     {
420         return mFilename;
421     }
422 
423     /**
424      * @brief Return raw pointer to SQLite Database Connection Handle.
425      *
426      * This is often needed to mix this wrapper with other libraries or for advance usage not supported by SQLiteCpp.
427      */
getHandle()428     sqlite3* getHandle() const noexcept
429     {
430         return mSQLitePtr.get();
431     }
432 
433     /**
434      * @brief Create or redefine a SQL function or aggregate in the sqlite database.
435      *
436      *  This is the equivalent of the sqlite3_create_function_v2 command.
437      * @see http://www.sqlite.org/c3ref/create_function.html
438      *
439      * @note UTF-8 text encoding assumed.
440      *
441      * @param[in] apFuncName    Name of the SQL function to be created or redefined
442      * @param[in] aNbArg        Number of arguments in the function
443      * @param[in] abDeterministic Optimize for deterministic functions (most are). A random number generator is not.
444      * @param[in] apApp         Arbitrary pointer of user data, accessible with sqlite3_user_data().
445      * @param[in] apFunc        Pointer to a C-function to implement a scalar SQL function (apStep & apFinal nullptr)
446      * @param[in] apStep        Pointer to a C-function to implement an aggregate SQL function (apFunc nullptr)
447      * @param[in] apFinal       Pointer to a C-function to implement an aggregate SQL function (apFunc nullptr)
448      * @param[in] apDestroy     If not nullptr, then it is the destructor for the application data pointer.
449      *
450      * @throw SQLite::Exception in case of error
451      */
452     void createFunction(const char* apFuncName,
453                         int         aNbArg,
454                         bool        abDeterministic,
455                         void*       apApp,
456                         void      (*apFunc)(sqlite3_context *, int, sqlite3_value **),
457                         void      (*apStep)(sqlite3_context *, int, sqlite3_value **) = nullptr,
458                         void      (*apFinal)(sqlite3_context *) = nullptr,  // NOLINT(readability/casting)
459                         void      (*apDestroy)(void *) = nullptr);
460 
461     /**
462      * @brief Load a module into the current sqlite database instance.
463      *
464      *  This is the equivalent of the sqlite3_load_extension call, but additionally enables
465      *  module loading support prior to loading the requested module.
466      *
467      * @see http://www.sqlite.org/c3ref/load_extension.html
468      *
469      * @note UTF-8 text encoding assumed.
470      *
471      * @param[in] apExtensionName   Name of the shared library containing extension
472      * @param[in] apEntryPointName  Name of the entry point (nullptr to let sqlite work it out)
473      *
474      * @throw SQLite::Exception in case of error
475      */
476     void loadExtension(const char* apExtensionName, const char* apEntryPointName);
477 
478     /**
479     * @brief Set the key for the current sqlite database instance.
480     *
481     *  This is the equivalent of the sqlite3_key call and should thus be called
482     *  directly after opening the database.
483     *  Open encrypted database -> call db.key("secret") -> database ready
484     *
485     * @param[in] aKey   Key to decode/encode the database
486     *
487     * @throw SQLite::Exception in case of error
488     */
489     void key(const std::string& aKey) const;
490 
491     /**
492     * @brief Reset the key for the current sqlite database instance.
493     *
494     *  This is the equivalent of the sqlite3_rekey call and should thus be called
495     *  after the database has been opened with a valid key. To decrypt a
496     *  database, call this method with an empty string.
497     *  Open normal database -> call db.rekey("secret") -> encrypted database, database ready
498     *  Open encrypted database -> call db.key("secret") -> call db.rekey("newsecret") -> change key, database ready
499     *  Open encrypted database -> call db.key("secret") -> call db.rekey("") -> decrypted database, database ready
500     *
501     * @param[in] aNewKey   New key to encode the database
502     *
503     * @throw SQLite::Exception in case of error
504     */
505     void rekey(const std::string& aNewKey) const;
506 
507     /**
508     * @brief Test if a file contains an unencrypted database.
509     *
510     *  This is a simple test that reads the first bytes of a database file and
511     *  compares them to the standard header for unencrypted databases. If the
512     *  header does not match the standard string, we assume that we have an
513     *  encrypted file.
514     *
515     * @param[in] aFilename path/uri to a file
516     *
517     * @return true if the database has the standard header.
518     *
519     * @throw SQLite::Exception in case of error
520     */
521     static bool isUnencrypted(const std::string& aFilename);
522 
523     /**
524     * @brief Parse SQLite header data from a database file.
525     *
526     *  This function reads the first 100 bytes of a SQLite database file
527     *  and reconstructs groups of individual bytes into the associated fields
528     *  in a Header object.
529     *
530     * @param[in] aFilename path/uri to a file
531     *
532     * @return Header object containing file data
533     *
534     * @throw SQLite::Exception in case of error
535     */
536     static Header getHeaderInfo(const std::string& aFilename);
537 
538     // Parse SQLite header data from a database file.
getHeaderInfo()539     Header getHeaderInfo()
540     {
541         return getHeaderInfo(mFilename);
542     }
543 
544     /**
545      * @brief BackupType for the backup() method
546      */
547     enum BackupType { Save, Load };
548 
549     /**
550      * @brief Load or save the database content.
551      *
552      * This function is used to load the contents of a database file on disk
553      * into the "main" database of open database connection, or to save the current
554      * contents of the database into a database file on disk.
555      *
556      * @throw SQLite::Exception in case of error
557      */
558     void backup(const char* apFilename, BackupType aType);
559 
560     /**
561      * @brief Check if aRet equal SQLITE_OK, else throw a SQLite::Exception with the SQLite error message
562      */
check(const int aRet)563     void check(const int aRet) const
564     {
565         if (SQLite::OK != aRet)
566         {
567             throw SQLite::Exception(getHandle(), aRet);
568         }
569     }
570 
571 private:
572     // TODO: perhaps switch to having Statement sharing a pointer to the Connexion
573     std::unique_ptr<sqlite3, Deleter> mSQLitePtr;   ///< Pointer to SQLite Database Connection Handle
574     std::string mFilename;                          ///< UTF-8 filename used to open the database
575 };
576 
577 
578 }  // namespace SQLite
579