Send Position packet on event, don't check it at each AsyncRunStep.
[oweals/minetest.git] / src / database-sqlite3.cpp
index 7e1767a8fb0b7bee2d3a6765b41964a7450a06c0..2edae8be2e08216592e160b1c553631bc18bc830 100644 (file)
@@ -44,6 +44,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "main.h"
 #include "settings.h"
 #include "log.h"
+#include "filesys.h"
 
 Database_SQLite3::Database_SQLite3(ServerMap *map, std::string savedir)
 {
@@ -51,6 +52,7 @@ Database_SQLite3::Database_SQLite3(ServerMap *map, std::string savedir)
        m_database_read = NULL;
        m_database_write = NULL;
        m_database_list = NULL;
+       m_database_delete = NULL;
        m_savedir = savedir;
        srvmap = map;
 }
@@ -120,13 +122,22 @@ 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");
        }
 
+       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");
+       }
+
        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;
@@ -136,18 +147,70 @@ void Database_SQLite3::verifyDatabase() {
        infostream<<"ServerMap: SQLite3 database opened"<<std::endl;
 }
 
+bool Database_SQLite3::deleteBlock(v3s16 blockpos)
+{
+       verifyDatabase();
+
+       if (sqlite3_bind_int64(m_database_delete, 1,
+                       getBlockAsInteger(blockpos)) != SQLITE_OK) {
+               errorstream << "WARNING: Could not bind block position for delete: "
+                       << sqlite3_errmsg(m_database) << std::endl;
+       }
+
+       if (sqlite3_step(m_database_delete) != SQLITE_DONE) {
+               errorstream << "WARNING: deleteBlock: Block failed to delete "
+                       << PP(blockpos) << ": " << sqlite3_errmsg(m_database) << std::endl;
+               sqlite3_reset(m_database_delete);
+               return false;
+       }
+
+       sqlite3_reset(m_database_delete);
+       return true;
+}
+
 bool Database_SQLite3::saveBlock(v3s16 blockpos, std::string &data)
 {
        verifyDatabase();
 
-       if (sqlite3_bind_int64(m_database_write, 1, getBlockAsInteger(blockpos)) != SQLITE_OK) {
+       s64 bkey = getBlockAsInteger(blockpos);
+
+#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, bkey) != SQLITE_OK) {
+               infostream << "WARNING: Could not bind block position for load: "
+                       << sqlite3_errmsg(m_database)<<std::endl;
+       }
+
+       int step_result = sqlite3_step(m_database_read);
+       sqlite3_reset(m_database_read);
+
+       if (step_result == SQLITE_ROW) {
+               if (sqlite3_bind_int64(m_database_delete, 1, bkey) != 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);
+       }
+#endif
+
+       if (sqlite3_bind_int64(m_database_write, 1, bkey) != SQLITE_OK) {
                errorstream << "WARNING: saveBlock: Block position failed to bind: "
                        << PP(blockpos) << ": " << sqlite3_errmsg(m_database) << std::endl;
                sqlite3_reset(m_database_write);
                return false;
        }
 
-       if (sqlite3_bind_blob(m_database_write, 2, (void *) data.c_str(), data.size(), NULL) != SQLITE_OK) {
+       if (sqlite3_bind_blob(m_database_write, 2, (void *)data.c_str(),
+                       data.size(), NULL) != SQLITE_OK) {
                errorstream << "WARNING: saveBlock: Block data failed to bind: "
                        << PP(blockpos) << ": " << sqlite3_errmsg(m_database) << std::endl;
                sqlite3_reset(m_database_write);
@@ -162,6 +225,7 @@ bool Database_SQLite3::saveBlock(v3s16 blockpos, std::string &data)
        }
 
        sqlite3_reset(m_database_write);
+
        return true;
 }
 
@@ -203,19 +267,18 @@ 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";
 
 }
 
-void Database_SQLite3::listAllLoadableBlocks(std::list<v3s16> &dst)
+void Database_SQLite3::listAllLoadableBlocks(std::vector<v3s16> &dst)
 {
        verifyDatabase();
 
-       while(sqlite3_step(m_database_list) == SQLITE_ROW)
-       {
+       while(sqlite3_step(m_database_list) == SQLITE_ROW) {
                sqlite3_int64 block_i = sqlite3_column_int64(m_database_list, 0);
                v3s16 p = getIntegerAsBlock(block_i);
                //dstream<<"block_i="<<block_i<<" p="<<PP(p)<<std::endl;
@@ -238,6 +301,7 @@ Database_SQLite3::~Database_SQLite3()
        FINALIZE_STATEMENT(m_database_read)
        FINALIZE_STATEMENT(m_database_write)
        FINALIZE_STATEMENT(m_database_list)
+       FINALIZE_STATEMENT(m_database_delete)
 
        if(m_database)
                rc = sqlite3_close(m_database);