1#include <base/str.h>
2#include <base/types.h>
3
4#include <engine/console.h>
5#include <engine/sqlite.h>
6
7#include <sqlite3.h>
8
9void CSqliteDeleter::operator()(sqlite3 *pSqlite)
10{
11 sqlite3_close(pSqlite);
12}
13
14void CSqliteStmtDeleter::operator()(sqlite3_stmt *pStmt)
15{
16 sqlite3_finalize(pStmt);
17}
18
19int SqliteHandleError(IConsole *pConsole, int Error, sqlite3 *pSqlite, const char *pContext)
20{
21 if(Error != SQLITE_OK && Error != SQLITE_DONE && Error != SQLITE_ROW)
22 {
23 char aBuf[512];
24 str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "%s at %s", sqlite3_errmsg(pSqlite), pContext);
25 pConsole->Print(Level: IConsole::OUTPUT_LEVEL_STANDARD, pFrom: "sqlite3", pStr: aBuf);
26 }
27 return Error;
28}
29
30CSqlite SqliteOpen(IConsole *pConsole, IStorage *pStorage, const char *pPath)
31{
32 char aFullPath[IO_MAX_PATH_LENGTH];
33 pStorage->GetCompletePath(Type: IStorage::TYPE_SAVE, pDir: pPath, pBuffer: aFullPath, BufferSize: sizeof(aFullPath));
34 sqlite3 *pSqlite = nullptr;
35 const bool ErrorOpening = SQLITE_HANDLE_ERROR(sqlite3_open(aFullPath, &pSqlite)) != SQLITE_OK;
36 // Even on error, the database is initialized and needs to be freed.
37 // Except on allocation failure, but then it'll be nullptr which is
38 // also fine.
39 CSqlite pResult{pSqlite};
40 if(ErrorOpening)
41 {
42 return nullptr;
43 }
44 bool Error = false;
45 Error = Error || SQLITE_HANDLE_ERROR(sqlite3_exec(pSqlite, "PRAGMA journal_mode = WAL", nullptr, nullptr, nullptr));
46 Error = Error || SQLITE_HANDLE_ERROR(sqlite3_exec(pSqlite, "PRAGMA synchronous = NORMAL", nullptr, nullptr, nullptr));
47 if(Error)
48 {
49 return nullptr;
50 }
51 return pResult;
52}
53
54CSqliteStmt SqlitePrepare(IConsole *pConsole, sqlite3 *pSqlite, const char *pStatement)
55{
56 sqlite3_stmt *pTemp;
57 if(SQLITE_HANDLE_ERROR(sqlite3_prepare_v2(pSqlite, pStatement, -1, &pTemp, nullptr)))
58 {
59 return nullptr;
60 }
61 return CSqliteStmt{pTemp};
62}
63