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;
59 int Database_SQLite3::Initialized(void)
61 return m_database ? 1 : 0;
64 void Database_SQLite3::beginSave() {
66 if(sqlite3_exec(m_database, "BEGIN;", NULL, NULL, NULL) != SQLITE_OK)
67 errorstream<<"WARNING: beginSave() failed, saving might be slow.";
70 void Database_SQLite3::endSave() {
72 if(sqlite3_exec(m_database, "COMMIT;", NULL, NULL, NULL) != SQLITE_OK)
73 errorstream<<"WARNING: endSave() failed, map might not have saved.";
76 void Database_SQLite3::createDirs(std::string path)
78 if(fs::CreateAllDirs(path) == false)
80 infostream<<DTIME<<"Database_SQLite3: Failed to create directory "
81 <<"\""<<path<<"\""<<std::endl;
82 throw BaseException("Database_SQLite3 failed to create directory");
86 void Database_SQLite3::verifyDatabase() {
90 std::string dbp = m_savedir + DIR_DELIM "map.sqlite";
91 bool needs_create = false;
94 // Open the database connection
96 createDirs(m_savedir); // ?
98 if(!fs::PathExists(dbp))
101 d = sqlite3_open_v2(dbp.c_str(), &m_database, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
103 errorstream<<"SQLite3 database failed to open: "<<sqlite3_errmsg(m_database)<<std::endl;
104 throw FileNotGoodException("Cannot open database file");
110 std::string querystr = std::string("PRAGMA synchronous = ")
111 + itos(g_settings->getU16("sqlite_synchronous"));
112 d = sqlite3_exec(m_database, querystr.c_str(), NULL, NULL, NULL);
114 errorstream<<"Database pragma set failed: "
115 <<sqlite3_errmsg(m_database)<<std::endl;
116 throw FileNotGoodException("Cannot set pragma");
119 d = sqlite3_prepare(m_database, "SELECT `data` FROM `blocks` WHERE `pos`=? LIMIT 1", -1, &m_database_read, NULL);
121 errorstream<<"SQLite3 read statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
122 throw FileNotGoodException("Cannot prepare read statement");
125 d = sqlite3_prepare(m_database, "INSERT INTO `blocks` VALUES(?, ?);", -1, &m_database_write, NULL);
127 d = sqlite3_prepare(m_database, "REPLACE INTO `blocks` VALUES(?, ?);", -1, &m_database_write, NULL);
130 errorstream<<"SQLite3 write statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
131 throw FileNotGoodException("Cannot prepare write statement");
134 d = sqlite3_prepare(m_database, "DELETE FROM `blocks` WHERE `pos`=?;", -1, &m_database_delete, NULL);
136 infostream<<"WARNING: SQLite3 database delete statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
137 throw FileNotGoodException("Cannot prepare delete statement");
140 d = sqlite3_prepare(m_database, "SELECT `pos` FROM `blocks`", -1, &m_database_list, NULL);
142 infostream<<"SQLite3 list statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
143 throw FileNotGoodException("Cannot prepare read statement");
146 infostream<<"ServerMap: SQLite3 database opened"<<std::endl;
149 bool Database_SQLite3::deleteBlock(v3s16 blockpos)
153 if (sqlite3_bind_int64(m_database_delete, 1,
154 getBlockAsInteger(blockpos)) != SQLITE_OK) {
155 errorstream << "WARNING: Could not bind block position for delete: "
156 << sqlite3_errmsg(m_database) << std::endl;
159 if (sqlite3_step(m_database_delete) != SQLITE_DONE) {
160 errorstream << "WARNING: deleteBlock: Block failed to delete "
161 << PP(blockpos) << ": " << sqlite3_errmsg(m_database) << std::endl;
162 sqlite3_reset(m_database_delete);
166 sqlite3_reset(m_database_delete);
170 bool Database_SQLite3::saveBlock(v3s16 blockpos, std::string &data)
174 s64 bkey = getBlockAsInteger(blockpos);
178 * Note: For some unknown reason sqlite3 fails to REPLACE blocks on android,
179 * deleting them and inserting first works.
181 if (sqlite3_bind_int64(m_database_read, 1, bkey) != SQLITE_OK) {
182 infostream << "WARNING: Could not bind block position for load: "
183 << sqlite3_errmsg(m_database)<<std::endl;
186 int step_result = sqlite3_step(m_database_read);
187 sqlite3_reset(m_database_read);
189 if (step_result == SQLITE_ROW) {
190 if (sqlite3_bind_int64(m_database_delete, 1, bkey) != SQLITE_OK) {
191 infostream << "WARNING: Could not bind block position for delete: "
192 << sqlite3_errmsg(m_database)<<std::endl;
195 if (sqlite3_step(m_database_delete) != SQLITE_DONE) {
196 errorstream << "WARNING: saveBlock: Block failed to delete "
197 << PP(blockpos) << ": " << sqlite3_errmsg(m_database) << std::endl;
200 sqlite3_reset(m_database_delete);
204 if (sqlite3_bind_int64(m_database_write, 1, bkey) != SQLITE_OK) {
205 errorstream << "WARNING: saveBlock: Block position failed to bind: "
206 << PP(blockpos) << ": " << sqlite3_errmsg(m_database) << std::endl;
207 sqlite3_reset(m_database_write);
211 if (sqlite3_bind_blob(m_database_write, 2, (void *)data.c_str(),
212 data.size(), NULL) != SQLITE_OK) {
213 errorstream << "WARNING: saveBlock: Block data failed to bind: "
214 << PP(blockpos) << ": " << sqlite3_errmsg(m_database) << std::endl;
215 sqlite3_reset(m_database_write);
219 if (sqlite3_step(m_database_write) != SQLITE_DONE) {
220 errorstream << "WARNING: saveBlock: Block failed to save "
221 << PP(blockpos) << ": " << sqlite3_errmsg(m_database) << std::endl;
222 sqlite3_reset(m_database_write);
226 sqlite3_reset(m_database_write);
231 std::string Database_SQLite3::loadBlock(v3s16 blockpos)
235 if (sqlite3_bind_int64(m_database_read, 1, getBlockAsInteger(blockpos)) != SQLITE_OK) {
236 errorstream << "Could not bind block position for load: "
237 << sqlite3_errmsg(m_database)<<std::endl;
240 if (sqlite3_step(m_database_read) == SQLITE_ROW) {
241 const char *data = (const char *) sqlite3_column_blob(m_database_read, 0);
242 size_t len = sqlite3_column_bytes(m_database_read, 0);
246 s = std::string(data, len);
248 sqlite3_step(m_database_read);
249 // We should never get more than 1 row, so ok to reset
250 sqlite3_reset(m_database_read);
255 sqlite3_reset(m_database_read);
259 void Database_SQLite3::createDatabase()
263 e = sqlite3_exec(m_database,
264 "CREATE TABLE IF NOT EXISTS `blocks` ("
265 "`pos` INT NOT NULL PRIMARY KEY,"
270 throw FileNotGoodException("Could not create sqlite3 database structure");
272 infostream<<"ServerMap: SQLite3 database structure was created";
276 void Database_SQLite3::listAllLoadableBlocks(std::list<v3s16> &dst)
280 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;