3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 SQLite format specification:
22 - Initially only replaces sectors/ and sectors2/
24 If map.sqlite does not exist in the save dir
25 or the block was not found in the database
26 the map will try to load from sectors folder.
27 In either case, map.sqlite will be created
28 and all future saves will save there.
30 Structure of map.sqlite:
38 #include "database-sqlite3.h"
41 #include "mapsector.h"
43 #include "serialization.h"
49 Database_SQLite3::Database_SQLite3(ServerMap *map, std::string savedir)
52 m_database_read = NULL;
53 m_database_write = NULL;
54 m_database_list = NULL;
55 m_database_delete = NULL;
60 int Database_SQLite3::Initialized(void)
62 return m_database ? 1 : 0;
65 void Database_SQLite3::beginSave() {
67 if(sqlite3_exec(m_database, "BEGIN;", NULL, NULL, NULL) != SQLITE_OK)
68 errorstream<<"WARNING: beginSave() failed, saving might be slow.";
71 void Database_SQLite3::endSave() {
73 if(sqlite3_exec(m_database, "COMMIT;", NULL, NULL, NULL) != SQLITE_OK)
74 errorstream<<"WARNING: endSave() failed, map might not have saved.";
77 void Database_SQLite3::createDirs(std::string path)
79 if(fs::CreateAllDirs(path) == false)
81 infostream<<DTIME<<"Database_SQLite3: Failed to create directory "
82 <<"\""<<path<<"\""<<std::endl;
83 throw BaseException("Database_SQLite3 failed to create directory");
87 void Database_SQLite3::verifyDatabase() {
91 std::string dbp = m_savedir + DIR_DELIM "map.sqlite";
92 bool needs_create = false;
95 // Open the database connection
97 createDirs(m_savedir); // ?
99 if(!fs::PathExists(dbp))
102 d = sqlite3_open_v2(dbp.c_str(), &m_database, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
104 errorstream<<"SQLite3 database failed to open: "<<sqlite3_errmsg(m_database)<<std::endl;
105 throw FileNotGoodException("Cannot open database file");
111 std::string querystr = std::string("PRAGMA synchronous = ")
112 + itos(g_settings->getU16("sqlite_synchronous"));
113 d = sqlite3_exec(m_database, querystr.c_str(), NULL, NULL, NULL);
115 errorstream<<"Database pragma set failed: "
116 <<sqlite3_errmsg(m_database)<<std::endl;
117 throw FileNotGoodException("Cannot set pragma");
120 d = sqlite3_prepare(m_database, "SELECT `data` FROM `blocks` WHERE `pos`=? LIMIT 1", -1, &m_database_read, NULL);
122 errorstream<<"SQLite3 read statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
123 throw FileNotGoodException("Cannot prepare read statement");
126 d = sqlite3_prepare(m_database, "INSERT INTO `blocks` VALUES(?, ?);", -1, &m_database_write, NULL);
128 d = sqlite3_prepare(m_database, "REPLACE INTO `blocks` VALUES(?, ?);", -1, &m_database_write, NULL);
131 errorstream<<"SQLite3 write statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
132 throw FileNotGoodException("Cannot prepare write statement");
135 d = sqlite3_prepare(m_database, "DELETE FROM `blocks` WHERE `pos`=?;", -1, &m_database_delete, NULL);
137 infostream<<"WARNING: SQLite3 database delete statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
138 throw FileNotGoodException("Cannot prepare delete statement");
141 d = sqlite3_prepare(m_database, "SELECT `pos` FROM `blocks`", -1, &m_database_list, NULL);
143 infostream<<"SQLite3 list statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
144 throw FileNotGoodException("Cannot prepare read statement");
147 infostream<<"ServerMap: SQLite3 database opened"<<std::endl;
150 bool Database_SQLite3::deleteBlock(v3s16 blockpos)
154 if (sqlite3_bind_int64(m_database_delete, 1,
155 getBlockAsInteger(blockpos)) != SQLITE_OK) {
156 errorstream << "WARNING: Could not bind block position for delete: "
157 << sqlite3_errmsg(m_database) << std::endl;
160 if (sqlite3_step(m_database_delete) != SQLITE_DONE) {
161 errorstream << "WARNING: deleteBlock: Block failed to delete "
162 << PP(blockpos) << ": " << sqlite3_errmsg(m_database) << std::endl;
163 sqlite3_reset(m_database_delete);
167 sqlite3_reset(m_database_delete);
171 bool Database_SQLite3::saveBlock(v3s16 blockpos, std::string &data)
175 s64 bkey = getBlockAsInteger(blockpos);
179 * Note: For some unknown reason sqlite3 fails to REPLACE blocks on android,
180 * deleting them and inserting first works.
182 if (sqlite3_bind_int64(m_database_read, 1, bkey) != SQLITE_OK) {
183 infostream << "WARNING: Could not bind block position for load: "
184 << sqlite3_errmsg(m_database)<<std::endl;
187 int step_result = sqlite3_step(m_database_read);
188 sqlite3_reset(m_database_read);
190 if (step_result == SQLITE_ROW) {
191 if (sqlite3_bind_int64(m_database_delete, 1, bkey) != SQLITE_OK) {
192 infostream << "WARNING: Could not bind block position for delete: "
193 << sqlite3_errmsg(m_database)<<std::endl;
196 if (sqlite3_step(m_database_delete) != SQLITE_DONE) {
197 errorstream << "WARNING: saveBlock: Block failed to delete "
198 << PP(blockpos) << ": " << sqlite3_errmsg(m_database) << std::endl;
201 sqlite3_reset(m_database_delete);
205 if (sqlite3_bind_int64(m_database_write, 1, bkey) != SQLITE_OK) {
206 errorstream << "WARNING: saveBlock: Block position failed to bind: "
207 << PP(blockpos) << ": " << sqlite3_errmsg(m_database) << std::endl;
208 sqlite3_reset(m_database_write);
212 if (sqlite3_bind_blob(m_database_write, 2, (void *)data.c_str(),
213 data.size(), NULL) != SQLITE_OK) {
214 errorstream << "WARNING: saveBlock: Block data failed to bind: "
215 << PP(blockpos) << ": " << sqlite3_errmsg(m_database) << std::endl;
216 sqlite3_reset(m_database_write);
220 if (sqlite3_step(m_database_write) != SQLITE_DONE) {
221 errorstream << "WARNING: saveBlock: Block failed to save "
222 << PP(blockpos) << ": " << sqlite3_errmsg(m_database) << std::endl;
223 sqlite3_reset(m_database_write);
227 sqlite3_reset(m_database_write);
232 std::string Database_SQLite3::loadBlock(v3s16 blockpos)
236 if (sqlite3_bind_int64(m_database_read, 1, getBlockAsInteger(blockpos)) != SQLITE_OK) {
237 errorstream << "Could not bind block position for load: "
238 << sqlite3_errmsg(m_database)<<std::endl;
241 if (sqlite3_step(m_database_read) == SQLITE_ROW) {
242 const char *data = (const char *) sqlite3_column_blob(m_database_read, 0);
243 size_t len = sqlite3_column_bytes(m_database_read, 0);
247 s = std::string(data, len);
249 sqlite3_step(m_database_read);
250 // We should never get more than 1 row, so ok to reset
251 sqlite3_reset(m_database_read);
256 sqlite3_reset(m_database_read);
260 void Database_SQLite3::createDatabase()
264 e = sqlite3_exec(m_database,
265 "CREATE TABLE IF NOT EXISTS `blocks` ("
266 "`pos` INT NOT NULL PRIMARY KEY,"
271 throw FileNotGoodException("Could not create sqlite3 database structure");
273 infostream<<"ServerMap: SQLite3 database structure was created";
277 void Database_SQLite3::listAllLoadableBlocks(std::vector<v3s16> &dst)
281 while(sqlite3_step(m_database_list) == SQLITE_ROW) {
282 sqlite3_int64 block_i = sqlite3_column_int64(m_database_list, 0);
283 v3s16 p = getIntegerAsBlock(block_i);
284 //dstream<<"block_i="<<block_i<<" p="<<PP(p)<<std::endl;
290 #define FINALIZE_STATEMENT(statement) \
292 rc = sqlite3_finalize(statement); \
293 if ( rc != SQLITE_OK ) \
294 errorstream << "Database_SQLite3::~Database_SQLite3():" \
295 << "Failed to finalize: " << #statement << ": rc=" << rc << std::endl;
297 Database_SQLite3::~Database_SQLite3()
301 FINALIZE_STATEMENT(m_database_read)
302 FINALIZE_STATEMENT(m_database_write)
303 FINALIZE_STATEMENT(m_database_list)
304 FINALIZE_STATEMENT(m_database_delete)
307 rc = sqlite3_close(m_database);
309 if (rc != SQLITE_OK) {
310 errorstream << "Database_SQLite3::~Database_SQLite3(): "
311 << "Failed to close database: rc=" << rc << std::endl;