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");
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");
142 d = sqlite3_prepare(m_database, "SELECT `pos` FROM `blocks`", -1, &m_database_list, NULL);
144 infostream<<"SQLite3 list statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
145 throw FileNotGoodException("Cannot prepare read statement");
148 infostream<<"ServerMap: SQLite3 database opened"<<std::endl;
151 bool Database_SQLite3::saveBlock(v3s16 blockpos, std::string &data)
157 * Note: For some unknown reason sqlite3 fails to REPLACE blocks on android,
158 * deleting them and inserting first works.
160 if (sqlite3_bind_int64(m_database_read, 1, getBlockAsInteger(blockpos)) != SQLITE_OK) {
161 infostream << "WARNING: Could not bind block position for load: "
162 << sqlite3_errmsg(m_database)<<std::endl;
165 if (sqlite3_step(m_database_read) == SQLITE_ROW) {
166 if (sqlite3_bind_int64(m_database_delete, 1, getBlockAsInteger(blockpos)) != SQLITE_OK) {
167 infostream << "WARNING: Could not bind block position for delete: "
168 << sqlite3_errmsg(m_database)<<std::endl;
171 if (sqlite3_step(m_database_delete) != SQLITE_DONE) {
172 errorstream << "WARNING: saveBlock: Block failed to delete "
173 << PP(blockpos) << ": " << sqlite3_errmsg(m_database) << std::endl;
176 sqlite3_reset(m_database_delete);
178 sqlite3_reset(m_database_read);
181 if (sqlite3_bind_int64(m_database_write, 1, getBlockAsInteger(blockpos)) != SQLITE_OK) {
182 errorstream << "WARNING: saveBlock: Block position failed to bind: "
183 << PP(blockpos) << ": " << sqlite3_errmsg(m_database) << std::endl;
184 sqlite3_reset(m_database_write);
188 if (sqlite3_bind_blob(m_database_write, 2, (void *) data.c_str(), data.size(), NULL) != SQLITE_OK) {
189 errorstream << "WARNING: saveBlock: Block data failed to bind: "
190 << PP(blockpos) << ": " << sqlite3_errmsg(m_database) << std::endl;
191 sqlite3_reset(m_database_write);
195 if (sqlite3_step(m_database_write) != SQLITE_DONE) {
196 errorstream << "WARNING: saveBlock: Block failed to save "
197 << PP(blockpos) << ": " << sqlite3_errmsg(m_database) << std::endl;
198 sqlite3_reset(m_database_write);
202 sqlite3_reset(m_database_write);
207 std::string Database_SQLite3::loadBlock(v3s16 blockpos)
211 if (sqlite3_bind_int64(m_database_read, 1, getBlockAsInteger(blockpos)) != SQLITE_OK) {
212 errorstream << "Could not bind block position for load: "
213 << sqlite3_errmsg(m_database)<<std::endl;
216 if (sqlite3_step(m_database_read) == SQLITE_ROW) {
217 const char *data = (const char *) sqlite3_column_blob(m_database_read, 0);
218 size_t len = sqlite3_column_bytes(m_database_read, 0);
222 s = std::string(data, len);
224 sqlite3_step(m_database_read);
225 // We should never get more than 1 row, so ok to reset
226 sqlite3_reset(m_database_read);
231 sqlite3_reset(m_database_read);
235 void Database_SQLite3::createDatabase()
239 e = sqlite3_exec(m_database,
240 "CREATE TABLE IF NOT EXISTS `blocks` ("
241 "`pos` INT NOT NULL PRIMARY KEY,"
246 throw FileNotGoodException("Could not create sqlite3 database structure");
248 infostream<<"ServerMap: SQLite3 database structure was created";
252 void Database_SQLite3::listAllLoadableBlocks(std::list<v3s16> &dst)
256 while(sqlite3_step(m_database_list) == SQLITE_ROW)
258 sqlite3_int64 block_i = sqlite3_column_int64(m_database_list, 0);
259 v3s16 p = getIntegerAsBlock(block_i);
260 //dstream<<"block_i="<<block_i<<" p="<<PP(p)<<std::endl;
266 #define FINALIZE_STATEMENT(statement) \
268 rc = sqlite3_finalize(statement); \
269 if ( rc != SQLITE_OK ) \
270 errorstream << "Database_SQLite3::~Database_SQLite3():" \
271 << "Failed to finalize: " << #statement << ": rc=" << rc << std::endl;
273 Database_SQLite3::~Database_SQLite3()
277 FINALIZE_STATEMENT(m_database_read)
278 FINALIZE_STATEMENT(m_database_write)
279 FINALIZE_STATEMENT(m_database_list)
282 rc = sqlite3_close(m_database);
284 if (rc != SQLITE_OK) {
285 errorstream << "Database_SQLite3::~Database_SQLite3(): "
286 << "Failed to close database: rc=" << rc << std::endl;