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