aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsapier <Sapier at GMX dot net>2014-07-07 22:57:11 +0200
committersapier <Sapier at GMX dot net>2014-08-16 12:28:07 +0200
commitfa427d641b687dd8585adced708510b94588cf51 (patch)
tree8fcb8c926f9054daa593c9a0d10782661731d8e4
parent6c5f79fee90ca0f0b971ec2a0e33d0e8f57616cb (diff)
downloadminetest-fa427d641b687dd8585adced708510b94588cf51.tar.gz
minetest-fa427d641b687dd8585adced708510b94588cf51.tar.bz2
minetest-fa427d641b687dd8585adced708510b94588cf51.zip
Add sqlite3 backend hack for android
-rw-r--r--src/database-sqlite3.cpp44
-rw-r--r--src/database-sqlite3.h3
-rw-r--r--src/subgame.cpp7
3 files changed, 45 insertions, 9 deletions
diff --git a/src/database-sqlite3.cpp b/src/database-sqlite3.cpp
index 7e1767a8f..4d48796fc 100644
--- a/src/database-sqlite3.cpp
+++ b/src/database-sqlite3.cpp
@@ -120,13 +120,24 @@ void Database_SQLite3::verifyDatabase() {
errorstream<<"SQLite3 read statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
throw FileNotGoodException("Cannot prepare read statement");
}
-
- d = sqlite3_prepare(m_database, "REPLACE INTO `blocks` VALUES(?, ?)", -1, &m_database_write, NULL);
+#ifdef __ANDROID__
+ d = sqlite3_prepare(m_database, "INSERT INTO `blocks` VALUES(?, ?);", -1, &m_database_write, NULL);
+#else
+ d = sqlite3_prepare(m_database, "REPLACE INTO `blocks` VALUES(?, ?);", -1, &m_database_write, NULL);
+#endif
if(d != SQLITE_OK) {
errorstream<<"SQLite3 write statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
throw FileNotGoodException("Cannot prepare write statement");
}
+#ifdef __ANDROID__
+ d = sqlite3_prepare(m_database, "DELETE FROM `blocks` WHERE `pos`=?;", -1, &m_database_delete, NULL);
+ if(d != SQLITE_OK) {
+ infostream<<"WARNING: SQLite3 database delete statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
+ throw FileNotGoodException("Cannot prepare delete statement");
+ }
+#endif
+
d = sqlite3_prepare(m_database, "SELECT `pos` FROM `blocks`", -1, &m_database_list, NULL);
if(d != SQLITE_OK) {
infostream<<"SQLite3 list statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
@@ -140,6 +151,32 @@ bool Database_SQLite3::saveBlock(v3s16 blockpos, std::string &data)
{
verifyDatabase();
+#ifdef __ANDROID__
+ /**
+ * Note: For some unknown reason sqlite3 fails to REPLACE blocks on android,
+ * deleting them and inserting first works.
+ */
+ if (sqlite3_bind_int64(m_database_read, 1, getBlockAsInteger(blockpos)) != SQLITE_OK) {
+ infostream << "WARNING: Could not bind block position for load: "
+ << sqlite3_errmsg(m_database)<<std::endl;
+ }
+
+ if (sqlite3_step(m_database_read) == SQLITE_ROW) {
+ if (sqlite3_bind_int64(m_database_delete, 1, getBlockAsInteger(blockpos)) != SQLITE_OK) {
+ infostream << "WARNING: Could not bind block position for delete: "
+ << sqlite3_errmsg(m_database)<<std::endl;
+ }
+
+ if (sqlite3_step(m_database_delete) != SQLITE_DONE) {
+ errorstream << "WARNING: saveBlock: Block failed to delete "
+ << PP(blockpos) << ": " << sqlite3_errmsg(m_database) << std::endl;
+ return false;
+ }
+ sqlite3_reset(m_database_delete);
+ }
+ sqlite3_reset(m_database_read);
+#endif
+
if (sqlite3_bind_int64(m_database_write, 1, getBlockAsInteger(blockpos)) != SQLITE_OK) {
errorstream << "WARNING: saveBlock: Block position failed to bind: "
<< PP(blockpos) << ": " << sqlite3_errmsg(m_database) << std::endl;
@@ -162,6 +199,7 @@ bool Database_SQLite3::saveBlock(v3s16 blockpos, std::string &data)
}
sqlite3_reset(m_database_write);
+
return true;
}
@@ -203,7 +241,7 @@ void Database_SQLite3::createDatabase()
"`data` BLOB"
");"
, NULL, NULL, NULL);
- if(e == SQLITE_ABORT)
+ if(e != SQLITE_OK)
throw FileNotGoodException("Could not create sqlite3 database structure");
else
infostream<<"ServerMap: SQLite3 database structure was created";
diff --git a/src/database-sqlite3.h b/src/database-sqlite3.h
index 81f7d459d..45619b885 100644
--- a/src/database-sqlite3.h
+++ b/src/database-sqlite3.h
@@ -47,6 +47,9 @@ private:
sqlite3 *m_database;
sqlite3_stmt *m_database_read;
sqlite3_stmt *m_database_write;
+#ifdef __ANDROID__
+ sqlite3_stmt *m_database_delete;
+#endif
sqlite3_stmt *m_database_list;
// Create the database structure
diff --git a/src/subgame.cpp b/src/subgame.cpp
index 1030d535a..f2465c93e 100644
--- a/src/subgame.cpp
+++ b/src/subgame.cpp
@@ -242,12 +242,7 @@ bool initializeWorld(const std::string &path, const std::string &gameid)
infostream<<"Creating world.mt ("<<worldmt_path<<")"<<std::endl;
fs::CreateAllDirs(path);
std::ostringstream ss(std::ios_base::binary);
- ss<<"gameid = "<<gameid<<
-#ifdef __ANDROID__
- "\nbackend = leveldb\n";
-#else
- "\nbackend = sqlite3\n";
-#endif
+ ss<<"gameid = "<<gameid<< "\nbackend = sqlite3\n";
fs::safeWriteToFile(worldmt_path, ss.str());
}
return true;
kwa">this); } const char *getName() { return "TestSchematic"; } void runTests(IGameDef *gamedef); void testMtsSerializeDeserialize(INodeDefManager *ndef); void testLuaTableSerialize(INodeDefManager *ndef); void testFileSerializeDeserialize(INodeDefManager *ndef); static const content_t test_schem1_data[7 * 6 * 4]; static const content_t test_schem2_data[3 * 3 * 3]; static const u8 test_schem2_prob[3 * 3 * 3]; static const char *expected_lua_output; }; static TestSchematic g_test_instance; void TestSchematic::runTests(IGameDef *gamedef) { IWritableNodeDefManager *ndef = (IWritableNodeDefManager *)gamedef->getNodeDefManager(); ndef->setNodeRegistrationStatus(true); TEST(testMtsSerializeDeserialize, ndef); TEST(testLuaTableSerialize, ndef); TEST(testFileSerializeDeserialize, ndef); ndef->resetNodeResolveState(); } //////////////////////////////////////////////////////////////////////////////// void TestSchematic::testMtsSerializeDeserialize(INodeDefManager *ndef) { static const v3s16 size(7, 6, 4); static const u32 volume = size.X * size.Y * size.Z; std::stringstream ss(std::ios_base::binary | std::ios_base::in | std::ios_base::out); std::vector<std::string> names; names.push_back("foo"); names.push_back("bar"); names.push_back("baz"); names.push_back("qux"); Schematic schem, schem2; schem.flags = 0; schem.size = size; schem.schemdata = new MapNode[volume]; schem.slice_probs = new u8[size.Y]; for (size_t i = 0; i != volume; i++) schem.schemdata[i] = MapNode(test_schem1_data[i], MTSCHEM_PROB_ALWAYS, 0); for (s16 y = 0; y != size.Y; y++) schem.slice_probs[y] = MTSCHEM_PROB_ALWAYS; UASSERT(schem.serializeToMts(&ss, names)); ss.seekg(0); names.clear(); UASSERT(schem2.deserializeFromMts(&ss, &names)); UASSERTEQ(size_t, names.size(), 4); UASSERTEQ(std::string, names[0], "foo"); UASSERTEQ(std::string, names[1], "bar"); UASSERTEQ(std::string, names[2], "baz"); UASSERTEQ(std::string, names[3], "qux"); UASSERT(schem2.size == size); for (size_t i = 0; i != volume; i++) UASSERT(schem2.schemdata[i] == schem.schemdata[i]); for (s16 y = 0; y != size.Y; y++) UASSERTEQ(u8, schem2.slice_probs[y], schem.slice_probs[y]); } void TestSchematic::testLuaTableSerialize(INodeDefManager *ndef) { static const v3s16 size(3, 3, 3); static const u32 volume = size.X * size.Y * size.Z; Schematic schem; schem.flags = 0; schem.size = size; schem.schemdata = new MapNode[volume]; schem.slice_probs = new u8[size.Y]; for (size_t i = 0; i != volume; i++) schem.schemdata[i] = MapNode(test_schem2_data[i], test_schem2_prob[i], 0); for (s16 y = 0; y != size.Y; y++) schem.slice_probs[y] = MTSCHEM_PROB_ALWAYS; std::vector<std::string> names; names.push_back("air"); names.push_back("default:lava_source"); names.push_back("default:glass"); std::ostringstream ss(std::ios_base::binary); UASSERT(schem.serializeToLua(&ss, names, false, 0)); UASSERTEQ(std::string, ss.str(), expected_lua_output); } void TestSchematic::testFileSerializeDeserialize(INodeDefManager *ndef) { static const v3s16 size(3, 3, 3); static const u32 volume = size.X * size.Y * size.Z; static const content_t content_map[] = { CONTENT_AIR, t_CONTENT_STONE, t_CONTENT_LAVA, }; static const content_t content_map2[] = { CONTENT_AIR, t_CONTENT_STONE, t_CONTENT_WATER, }; StringMap replace_names; replace_names["default:lava"] = "default:water"; Schematic schem1, schem2; //// Construct the schematic to save schem1.flags = 0; schem1.size = size; schem1.schemdata = new MapNode[volume]; schem1.slice_probs = new u8[size.Y]; schem1.slice_probs[0] = 80; schem1.slice_probs[1] = 160; schem1.slice_probs[2] = 240; for (size_t i = 0; i != volume; i++) { content_t c = content_map[test_schem2_data[i]]; schem1.schemdata[i] = MapNode(c, test_schem2_prob[i], 0); } std::string temp_file = getTestTempFile(); UASSERT(schem1.saveSchematicToFile(temp_file, ndef)); UASSERT(schem2.loadSchematicFromFile(temp_file, ndef, &replace_names)); UASSERT(schem2.size == size); UASSERT(schem2.slice_probs[0] == 80); UASSERT(schem2.slice_probs[1] == 160); UASSERT(schem2.slice_probs[2] == 240); for (size_t i = 0; i != volume; i++) { content_t c = content_map2[test_schem2_data[i]]; UASSERT(schem2.schemdata[i] == MapNode(c, test_schem2_prob[i], 0)); } } // Should form a cross-shaped-thing...? const content_t TestSchematic::test_schem1_data[7 * 6 * 4] = { 3, 3, 1, 1, 1, 3, 3, // Y=0, Z=0 3, 0, 1, 2, 1, 0, 3, // Y=1, Z=0 3, 0, 1, 2, 1, 0, 3, // Y=2, Z=0 3, 1, 1, 2, 1, 1, 3, // Y=3, Z=0 3, 2, 2, 2, 2, 2, 3, // Y=4, Z=0 3, 1, 1, 2, 1, 1, 3, // Y=5, Z=0 0, 0, 1, 1, 1, 0, 0, // Y=0, Z=1