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"
48 Database_SQLite3::Database_SQLite3(ServerMap *map, std::string savedir)
51 m_database_read = NULL;
52 m_database_write = NULL;
53 m_database_list = NULL;
58 int Database_SQLite3::Initialized(void)
60 return m_database ? 1 : 0;
63 void Database_SQLite3::beginSave() {
65 if(sqlite3_exec(m_database, "BEGIN;", NULL, NULL, NULL) != SQLITE_OK)
66 errorstream<<"WARNING: beginSave() failed, saving might be slow.";
69 void Database_SQLite3::endSave() {
71 if(sqlite3_exec(m_database, "COMMIT;", NULL, NULL, NULL) != SQLITE_OK)
72 errorstream<<"WARNING: endSave() failed, map might not have saved.";
75 void Database_SQLite3::createDirs(std::string path)
77 if(fs::CreateAllDirs(path) == false)
79 infostream<<DTIME<<"Database_SQLite3: Failed to create directory "
80 <<"\""<<path<<"\""<<std::endl;
81 throw BaseException("Database_SQLite3 failed to create directory");
85 void Database_SQLite3::verifyDatabase() {
89 std::string dbp = m_savedir + DIR_DELIM "map.sqlite";
90 bool needs_create = false;
93 // Open the database connection
95 createDirs(m_savedir); // ?
97 if(!fs::PathExists(dbp))
100 d = sqlite3_open_v2(dbp.c_str(), &m_database, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
102 errorstream<<"SQLite3 database failed to open: "<<sqlite3_errmsg(m_database)<<std::endl;
103 throw FileNotGoodException("Cannot open database file");
109 std::string querystr = std::string("PRAGMA synchronous = ")
110 + itos(g_settings->getU16("sqlite_synchronous"));
111 d = sqlite3_exec(m_database, querystr.c_str(), NULL, NULL, NULL);
113 errorstream<<"Database pragma set failed: "
114 <<sqlite3_errmsg(m_database)<<std::endl;
115 throw FileNotGoodException("Cannot set pragma");
118 d = sqlite3_prepare(m_database, "SELECT `data` FROM `blocks` WHERE `pos`=? LIMIT 1", -1, &m_database_read, NULL);
120 errorstream<<"SQLite3 read statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
121 throw FileNotGoodException("Cannot prepare read statement");
124 d = sqlite3_prepare(m_database, "INSERT INTO `blocks` VALUES(?, ?);", -1, &m_database_write, NULL);
126 d = sqlite3_prepare(m_database, "REPLACE INTO `blocks` VALUES(?, ?);", -1, &m_database_write, NULL);
129 errorstream<<"SQLite3 write statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
130 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");
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::saveBlock(v3s16 blockpos, std::string &data)
156 * Note: For some unknown reason sqlite3 fails to REPLACE blocks on android,
157 * deleting them and inserting first works.
159 if (sqlite3_bind_int64(m_database_read, 1, getBlockAsInteger(blockpos)) != SQLITE_OK) {
160 infostream << "WARNING: Could not bind block position for load: "
161 << sqlite3_errmsg(m_database)<<std::endl;
164 if (sqlite3_step(m_database_read) == SQLITE_ROW) {
165 if (sqlite3_bind_int64(m_database_delete, 1, getBlockAsInteger(blockpos)) != SQLITE_OK) {
166 infostream << "WARNING: Could not bind block position for delete: "
167 << sqlite3_errmsg(m_database)<<std::endl;
170 if (sqlite3_step(m_database_delete) != SQLITE_DONE) {
171 errorstream << "WARNING: saveBlock: Block failed to delete "
172 << PP(blockpos) << ": " << sqlite3_errmsg(m_database) << std::endl;
175 sqlite3_reset(m_database_delete);
177 sqlite3_reset(m_database_read);
180 if (sqlite3_bind_int64(m_database_write, 1, getBlockAsInteger(blockpos)) != SQLITE_OK) {
181 errorstream << "WARNING: saveBlock: Block position failed to bind: "
182 << PP(blockpos) << ": " << sqlite3_errmsg(m_database) << std::endl;
183 sqlite3_reset(m_database_write);
187 if (sqlite3_bind_blob(m_database_write, 2, (void *) data.c_str(), data.size(), NULL) != SQLITE_OK) {
188 errorstream << "WARNING: saveBlock: Block data failed to bind: "
189 << PP(blockpos) << ": " << sqlite3_errmsg(m_database) << std::endl;
190 sqlite3_reset(m_database_write);
194 if (sqlite3_step(m_database_write) != SQLITE_DONE) {
195 errorstream << "WARNING: saveBlock: Block failed to save "
196 << PP(blockpos) << ": " << sqlite3_errmsg(m_database) << std::endl;
197 sqlite3_reset(m_database_write);
201 sqlite3_reset(m_database_write);
206 std::string Database_SQLite3::loadBlock(v3s16 blockpos)
210 if (sqlite3_bind_int64(m_database_read, 1, getBlockAsInteger(blockpos)) != SQLITE_OK) {
211 errorstream << "Could not bind block position for load: "
212 << sqlite3_errmsg(m_database)<<std::endl;
215 if (sqlite3_step(m_database_read) == SQLITE_ROW) {
216 const char *data = (const char *) sqlite3_column_blob(m_database_read, 0);
217 size_t len = sqlite3_column_bytes(m_database_read, 0);
221 s = std::string(data, len);
223 sqlite3_step(m_database_read);
224 // We should never get more than 1 row, so ok to reset
225 sqlite3_reset(m_database_read);
230 sqlite3_reset(m_database_read);
234 void Database_SQLite3::createDatabase()
238 e = sqlite3_exec(m_database,
239 "CREATE TABLE IF NOT EXISTS `blocks` ("
240 "`pos` INT NOT NULL PRIMARY KEY,"
245 throw FileNotGoodException("Could not create sqlite3 database structure");
247 infostream<<"ServerMap: SQLite3 database structure was created";
251 void Database_SQLite3::listAllLoadableBlocks(std::list<v3s16> &dst)
255 while(sqlite3_step(m_database_list) == SQLITE_ROW)
257 sqlite3_int64 block_i = sqlite3_column_int64(m_database_list, 0);
258 v3s16 p = getIntegerAsBlock(block_i);
259 //dstream<<"block_i="<<block_i<<" p="<<PP(p)<<std::endl;
265 #define FINALIZE_STATEMENT(statement) \
267 rc = sqlite3_finalize(statement); \
268 if ( rc != SQLITE_OK ) \
269 errorstream << "Database_SQLite3::~Database_SQLite3():" \
270 << "Failed to finalize: " << #statement << ": rc=" << rc << std::endl;
272 Database_SQLite3::~Database_SQLite3()
276 FINALIZE_STATEMENT(m_database_read)
277 FINALIZE_STATEMENT(m_database_write)
278 FINALIZE_STATEMENT(m_database_list)
281 rc = sqlite3_close(m_database);
283 if (rc != SQLITE_OK) {
284 errorstream << "Database_SQLite3::~Database_SQLite3(): "
285 << "Failed to close database: rc=" << rc << std::endl;