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, "REPLACE INTO `blocks` VALUES(?, ?)", -1, &m_database_write, NULL);
126 errorstream<<"SQLite3 write statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
127 throw FileNotGoodException("Cannot prepare write statement");
130 d = sqlite3_prepare(m_database, "SELECT `pos` FROM `blocks`", -1, &m_database_list, NULL);
132 infostream<<"SQLite3 list statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
133 throw FileNotGoodException("Cannot prepare read statement");
136 infostream<<"ServerMap: SQLite3 database opened"<<std::endl;
139 bool Database_SQLite3::saveBlock(v3s16 blockpos, std::string &data)
143 if (sqlite3_bind_int64(m_database_write, 1, getBlockAsInteger(blockpos)) != SQLITE_OK) {
144 errorstream << "WARNING: saveBlock: Block position failed to bind: "
145 << PP(blockpos) << ": " << sqlite3_errmsg(m_database) << std::endl;
146 sqlite3_reset(m_database_write);
150 if (sqlite3_bind_blob(m_database_write, 2, (void *) data.c_str(), data.size(), NULL) != SQLITE_OK) {
151 errorstream << "WARNING: saveBlock: Block data failed to bind: "
152 << PP(blockpos) << ": " << sqlite3_errmsg(m_database) << std::endl;
153 sqlite3_reset(m_database_write);
157 if (sqlite3_step(m_database_write) != SQLITE_DONE) {
158 errorstream << "WARNING: saveBlock: Block failed to save "
159 << PP(blockpos) << ": " << sqlite3_errmsg(m_database) << std::endl;
160 sqlite3_reset(m_database_write);
164 sqlite3_reset(m_database_write);
168 std::string Database_SQLite3::loadBlock(v3s16 blockpos)
172 if (sqlite3_bind_int64(m_database_read, 1, getBlockAsInteger(blockpos)) != SQLITE_OK) {
173 errorstream << "Could not bind block position for load: "
174 << sqlite3_errmsg(m_database)<<std::endl;
177 if (sqlite3_step(m_database_read) == SQLITE_ROW) {
178 const char *data = (const char *) sqlite3_column_blob(m_database_read, 0);
179 size_t len = sqlite3_column_bytes(m_database_read, 0);
183 s = std::string(data, len);
185 sqlite3_step(m_database_read);
186 // We should never get more than 1 row, so ok to reset
187 sqlite3_reset(m_database_read);
192 sqlite3_reset(m_database_read);
196 void Database_SQLite3::createDatabase()
200 e = sqlite3_exec(m_database,
201 "CREATE TABLE IF NOT EXISTS `blocks` ("
202 "`pos` INT NOT NULL PRIMARY KEY,"
206 if(e == SQLITE_ABORT)
207 throw FileNotGoodException("Could not create sqlite3 database structure");
209 infostream<<"ServerMap: SQLite3 database structure was created";
213 void Database_SQLite3::listAllLoadableBlocks(std::list<v3s16> &dst)
217 while(sqlite3_step(m_database_list) == SQLITE_ROW)
219 sqlite3_int64 block_i = sqlite3_column_int64(m_database_list, 0);
220 v3s16 p = getIntegerAsBlock(block_i);
221 //dstream<<"block_i="<<block_i<<" p="<<PP(p)<<std::endl;
227 #define FINALIZE_STATEMENT(statement) \
229 rc = sqlite3_finalize(statement); \
230 if ( rc != SQLITE_OK ) \
231 errorstream << "Database_SQLite3::~Database_SQLite3():" \
232 << "Failed to finalize: " << #statement << ": rc=" << rc << std::endl;
234 Database_SQLite3::~Database_SQLite3()
238 FINALIZE_STATEMENT(m_database_read)
239 FINALIZE_STATEMENT(m_database_write)
240 FINALIZE_STATEMENT(m_database_list)
243 rc = sqlite3_close(m_database);
245 if (rc != SQLITE_OK) {
246 errorstream << "Database_SQLite3::~Database_SQLite3(): "
247 << "Failed to close database: rc=" << rc << std::endl;