forked from Nozbe/WatermelonDB
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSqlite.cpp
More file actions
111 lines (94 loc) · 3.95 KB
/
Sqlite.cpp
File metadata and controls
111 lines (94 loc) · 3.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#include "Sqlite.h"
#include "DatabasePlatform.h"
#include <cassert>
namespace watermelondb {
using platform::consoleError;
using platform::consoleLog;
std::string resolveDatabasePath(std::string path) {
if (path == "" || path == ":memory:" || path.rfind("file:", 0) == 0 || path.rfind("/", 0) == 0) {
// These seem like paths/sqlite path-like strings
return path;
} else {
// path is a name to be resolved based on platform preferences
return platform::resolveDatabasePath(path);
}
}
SqliteDb::SqliteDb(std::string path, const char *password) {
consoleLog("Will open database...");
platform::initializeSqlite();
#ifndef ANDROID
assert(sqlite3_threadsafe());
#endif
auto resolvedPath = resolveDatabasePath(path);
int openResult = sqlite3_open(resolvedPath.c_str(), &sqlite);
if (openResult != SQLITE_OK) {
if (sqlite) {
auto error = std::string(sqlite3_errmsg(sqlite));
throw new std::runtime_error("Error while trying to open database - " + error);
} else {
// whoa, sqlite couldn't allocate memory
throw new std::runtime_error("Error while trying to open database, sqlite is null - " + std::to_string(openResult));
}
}
assert(sqlite != nullptr);
#ifdef SQLITE_HAS_CODEC
if (password != nullptr && strlen(password) > 0) {
consoleLog("##### Will set key...");
sqlite3_key(sqlite, password, (int)strlen(password));
int rc = sqlite3_exec(sqlite, "SELECT count(*) FROM sqlite_master;", NULL, NULL, NULL);
if (rc != SQLITE_OK) {
consoleError("Failed to open encrypted database - " + std::string(sqlite3_errmsg(sqlite)));
sqlite3_close(sqlite);
sqlite = nullptr;
throw new std::runtime_error("Failed to open encrypted database - " + std::string(sqlite3_errmsg(sqlite)));
}
consoleLog("##### Key set!");
}
#endif
assert(sqlite != nullptr);
consoleLog("Opened database at " + resolvedPath);
}
void SqliteDb::destroy() {
if (isDestroyed_) {
return;
}
consoleLog("Closing database...");
isDestroyed_ = true;
assert(sqlite != nullptr);
// Find and finalize all prepared statements
sqlite3_stmt *stmt;
while ((stmt = sqlite3_next_stmt(sqlite, nullptr))) {
consoleError("Leak detected! Finalized a statement when closing database - this means that there were dangling "
"statements not held by cachedStatements, or handling of cachedStatements is broken. Please "
"collect as much information as possible and file an issue with WatermelonDB repository!");
sqlite3_finalize(stmt);
}
// Close connection
// NOTE: Applications should finalize all prepared statements, close all BLOB handles, and finish all sqlite3_backup objects
int closeResult = sqlite3_close(sqlite);
if (closeResult != SQLITE_OK) {
// NOTE: We're just gonna log an error. We can't throw an exception here. We could crash, but most likely we're
// only leaking memory/resources
consoleError("Failed to close sqlite database - " + std::string(sqlite3_errmsg(sqlite)));
}
consoleLog("Database closed.");
}
SqliteDb::~SqliteDb() {
destroy();
}
SqliteStatement::SqliteStatement(sqlite3_stmt *statement) : stmt(statement) {
}
SqliteStatement::~SqliteStatement() {
reset();
}
void SqliteStatement::reset() {
if (stmt) {
// TODO: I'm confused by whether or not the return value of reset is relevant:
// If the most recent call to sqlite3_step(S) for the prepared statement S indicated an error, then
// sqlite3_reset(S) returns an appropriate error code. https://sqlite.org/c3ref/reset.html
sqlite3_reset(stmt);
sqlite3_clear_bindings(stmt); // might matter if storing a huge string/blob
// consoleLog("statement has been reset!");
}
}
} // namespace watermelondb