void Database_SQLite3::openDatabase() { if (m_database) return; std::string dbp = m_savedir + DIR_DELIM + "map.sqlite"; // Open the database connection if (!fs::CreateAllDirs(m_savedir)) { infostream << "Database_SQLite3: Failed to create directory \"" << m_savedir << "\"" << std::endl; throw FileNotGoodException("Failed to create database " "save directory"); } bool needs_create = !fs::PathExists(dbp); SQLOK(sqlite3_open_v2(dbp.c_str(), &m_database, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL), std::string("Failed to open SQLite3 database file ") + dbp); SQLOK(sqlite3_busy_handler(m_database, Database_SQLite3::busyHandler, m_busy_handler_data), "Failed to set SQLite3 busy handler"); if (needs_create) { createDatabase(); } std::string query_str = std::string("PRAGMA synchronous = ") + itos(g_settings->getU16("sqlite_synchronous")); SQLOK(sqlite3_exec(m_database, query_str.c_str(), NULL, NULL, NULL), "Failed to modify sqlite3 synchronous mode"); }
void PlayerDatabaseSQLite3::createDatabase() { assert(m_database); // Pre-condition SQLOK(sqlite3_exec(m_database, "CREATE TABLE IF NOT EXISTS `player` (" "`name` VARCHAR(50) NOT NULL," "`pitch` NUMERIC(11, 4) NOT NULL," "`yaw` NUMERIC(11, 4) NOT NULL," "`posX` NUMERIC(11, 4) NOT NULL," "`posY` NUMERIC(11, 4) NOT NULL," "`posZ` NUMERIC(11, 4) NOT NULL," "`hp` INT NOT NULL," "`breath` INT NOT NULL," "`creation_date` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP," "`modification_date` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP," "PRIMARY KEY (`name`));", NULL, NULL, NULL), "Failed to create player table"); SQLOK(sqlite3_exec(m_database, "CREATE TABLE IF NOT EXISTS `player_metadata` (" " `player` VARCHAR(50) NOT NULL," " `metadata` VARCHAR(256) NOT NULL," " `value` TEXT," " PRIMARY KEY(`player`, `metadata`)," " FOREIGN KEY (`player`) REFERENCES player (`name`) ON DELETE CASCADE );", NULL, NULL, NULL), "Failed to create player metadata table"); SQLOK(sqlite3_exec(m_database, "CREATE TABLE IF NOT EXISTS `player_inventories` (" " `player` VARCHAR(50) NOT NULL," " `inv_id` INT NOT NULL," " `inv_width` INT NOT NULL," " `inv_name` TEXT NOT NULL DEFAULT ''," " `inv_size` INT NOT NULL," " PRIMARY KEY(player, inv_id)," " FOREIGN KEY (`player`) REFERENCES player (`name`) ON DELETE CASCADE );", NULL, NULL, NULL), "Failed to create player inventory table"); SQLOK(sqlite3_exec(m_database, "CREATE TABLE `player_inventory_items` (" " `player` VARCHAR(50) NOT NULL," " `inv_id` INT NOT NULL," " `slot_id` INT NOT NULL," " `item` TEXT NOT NULL DEFAULT ''," " PRIMARY KEY(player, inv_id, slot_id)," " FOREIGN KEY (`player`) REFERENCES player (`name`) ON DELETE CASCADE );", NULL, NULL, NULL), "Failed to create player inventory items table"); }
void Database_SQLite3::openDatabase() { if (m_database) return; std::string dbp = m_savedir + DIR_DELIM + "map.sqlite"; // Open the database connection if (!fs::CreateAllDirs(m_savedir)) { infostream << "Database_SQLite3: Failed to create directory \"" << m_savedir << "\"" << std::endl; throw FileNotGoodException("Failed to create database " "save directory"); } bool needs_create = !fs::PathExists(dbp); if (sqlite3_open_v2(dbp.c_str(), &m_database, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL) != SQLITE_OK) { errorstream << "SQLite3 database failed to open: " << sqlite3_errmsg(m_database) << std::endl; throw FileNotGoodException("Cannot open database file"); } if (needs_create) { createDatabase(); } std::string query_str = std::string("PRAGMA synchronous = ") + itos(g_settings->getU16("sqlite_synchronous")); SQLOK(sqlite3_exec(m_database, query_str.c_str(), NULL, NULL, NULL)); }
bool Database_SQLite3::saveBlock(const v3s16 &pos, const std::string &data) { std::lock_guard<std::mutex> lock(mutex); verifyDatabase(); #ifdef __ANDROID__ /** * Note: For some unknown reason SQLite3 fails to REPLACE blocks on Android, * deleting them and then inserting works. */ bindPos(m_stmt_read, pos); if (sqlite3_step(m_stmt_read) == SQLITE_ROW) { deleteBlock(pos); } sqlite3_reset(m_stmt_read); #endif bindPos(m_stmt_write, pos); SQLOK(sqlite3_bind_blob(m_stmt_write, 2, data.data(), data.size(), NULL)); SQLRES(sqlite3_step(m_stmt_write), SQLITE_DONE) sqlite3_reset(m_stmt_write); return true; }
Network * DB::addNetwork(Network &net) { int res; SQLOK(bind_text(stmt_add_network, 1, net.name.data(), net.name.size(), NULL), "binding network name"); SQLRES(step(stmt_add_network), SQLITE_DONE, "running network insertion statement"); SQLOK(reset(stmt_add_network), "reseting network insertion statement"); net.id = sqlite3_last_insert_rowid(dbh); networks.push_back(net); return &networks[networks.size() - 1]; }
bool Database_SQLite3::saveBlock(const v3s16 &pos, const std::string &data) { verifyDatabase(); #ifdef __ANDROID__ /** * Note: For some unknown reason SQLite3 fails to REPLACE blocks on Android, * deleting them and then inserting works. */ bindPos(m_stmt_read, pos); if (sqlite3_step(m_stmt_read) == SQLITE_ROW) { deleteBlock(pos); } sqlite3_reset(m_stmt_read); #endif bindPos(m_stmt_write, pos); SQLOK(sqlite3_bind_blob(m_stmt_write, 2, data.data(), data.size(), NULL), "Internal error: failed to bind query at " __FILE__ ":" TOSTRING(__LINE__)); SQLRES(sqlite3_step(m_stmt_write), SQLITE_DONE, "Failed to save block") sqlite3_reset(m_stmt_write); return true; }
int RollbackManager::getNodeId(const std::string &name) { for (std::vector<Entity>::const_iterator iter = knownNodes.begin(); iter != knownNodes.end(); ++iter) { if (iter->name == name) { return iter->id; } } SQLOK(sqlite3_bind_text(stmt_knownNode_insert, 1, name.c_str(), name.size(), NULL)); SQLRES(sqlite3_step(stmt_knownNode_insert), SQLITE_DONE); SQLOK(sqlite3_reset(stmt_knownNode_insert)); int id = sqlite3_last_insert_rowid(db); registerNewNode(id, name); return id; }
Buffer * DB::addBuffer(Buffer &buf) { int res; SQLOK(bind_int (stmt_add_buffer, 1, buf.networkid), "binding buffer networkid"); SQLOK(bind_text(stmt_add_buffer, 2, buf.name.data(), buf.name.size(), NULL), "binding buffer name"); SQLRES(step(stmt_add_buffer), SQLITE_DONE, "running buffer insertion statement"); SQLOK(reset(stmt_add_buffer), "reseting buffer insertion statement"); buf.id = sqlite3_last_insert_rowid(dbh); buffers.push_back(buf); return &buffers[buffers.size() - 1]; }
void Database_SQLite3::createDatabase() { assert(m_database); // Pre-condition SQLOK(sqlite3_exec(m_database, "CREATE TABLE IF NOT EXISTS `blocks` (\n" " `pos` INT PRIMARY KEY,\n" " `data` BLOB\n" ");\n", NULL, NULL, NULL)); }
Database_SQLite3::~Database_SQLite3() { FINALIZE_STATEMENT(m_stmt_read) FINALIZE_STATEMENT(m_stmt_write) FINALIZE_STATEMENT(m_stmt_list) FINALIZE_STATEMENT(m_stmt_begin) FINALIZE_STATEMENT(m_stmt_end) FINALIZE_STATEMENT(m_stmt_delete) SQLOK(sqlite3_close(m_database), "Failed to close database"); }
Sender * DB::addSender(Sender &snd) { int res; SQLOK(bind_text(stmt_add_sender, 1, snd.nick.data(), snd.nick.size(), NULL), "binding sender nick"); SQLOK(bind_text(stmt_add_sender, 2, snd.user.data(), snd.user.size(), NULL), "binding sender ident"); SQLOK(bind_text(stmt_add_sender, 3, snd.host.data(), snd.host.size(), NULL), "binding sender host"); SQLRES(step(stmt_add_sender), SQLITE_DONE, "running sender insertion statement"); SQLOK(reset(stmt_add_sender), "reseting sender insertion statement"); snd.id = sqlite3_last_insert_rowid(dbh); senders.push_back(snd); return &senders[senders.size() - 1]; }
bool WordInsertQuery::execute() { int err = WordsQuery::execute(); if ( !err ) { #ifdef FIRU_USE_SQLITE m_record.id = sqlite3_last_insert_rowid( m_db ); return SQLOK( err ) == SQLITE_OK; #else m_record.id = m_query.lastInsertId().toLongLong(); #endif } return false; }
DB::~DB() { int res; try { FINALIZE_STMT(stmt_add_message, "message insertion"); FINALIZE_STMT(stmt_add_buffer, "buffer insertion"); FINALIZE_STMT(stmt_add_network, "network insertion"); FINALIZE_STMT(stmt_add_sender, "sender insertion"); FINALIZE_STMT(stmt_begin, "begin"); FINALIZE_STMT(stmt_commit, "commit"); SQLOK(close(dbh), "closing database"); } catch (std::exception &e) { std::cerr << "Failed to close database: " << e.what() << std::endl; } }
bool RollbackManager::createTables() { #if USE_SQLITE3 SQLOK(sqlite3_exec(db, "CREATE TABLE IF NOT EXISTS `actor` (\n" " `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n" " `name` TEXT NOT NULL\n" ");\n" "CREATE TABLE IF NOT EXISTS `node` (\n" " `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n" " `name` TEXT NOT NULL\n" ");\n" "CREATE TABLE IF NOT EXISTS `action` (\n" " `id` INTEGER PRIMARY KEY AUTOINCREMENT,\n" " `actor` INTEGER NOT NULL,\n" " `timestamp` TIMESTAMP NOT NULL,\n" " `type` INTEGER NOT NULL,\n" " `list` TEXT,\n" " `index` INTEGER,\n" " `add` INTEGER,\n" " `stackNode` INTEGER,\n" " `stackQuantity` INTEGER,\n" " `nodeMeta` INTEGER,\n" " `x` INT,\n" " `y` INT,\n" " `z` INT,\n" " `oldNode` INTEGER,\n" " `oldParam1` INTEGER,\n" " `oldParam2` INTEGER,\n" " `oldMeta` TEXT,\n" " `newNode` INTEGER,\n" " `newParam1` INTEGER,\n" " `newParam2` INTEGER,\n" " `newMeta` TEXT,\n" " `guessedActor` INTEGER,\n" " FOREIGN KEY (`actor`) REFERENCES `actor`(`id`),\n" " FOREIGN KEY (`stackNode`) REFERENCES `node`(`id`),\n" " FOREIGN KEY (`oldNode`) REFERENCES `node`(`id`),\n" " FOREIGN KEY (`newNode`) REFERENCES `node`(`id`)\n" ");\n" "CREATE INDEX IF NOT EXISTS `actionIndex` ON `action`(`x`,`y`,`z`,`timestamp`,`actor`);\n", NULL, NULL, NULL)); verbosestream << "SQL Rollback: SQLite3 database structure was created" << std::endl; #endif return true; }
void DB::addMessage(Message &msg) { int res; SQLOK(bind_int64(stmt_add_message, 1, msg.time), "binding message time"); SQLOK(bind_int (stmt_add_message, 2, (int) msg.type), "binding message type"); SQLOK(bind_int (stmt_add_message, 3, msg.bufferid), "binding message bufferid"); SQLOK(bind_int (stmt_add_message, 4, msg.senderid), "binding message senderid"); SQLOK(bind_text (stmt_add_message, 5, msg.text.data(), msg.text.size(), NULL), "binding message text"); SQLRES(step(stmt_add_message), SQLITE_DONE, "running message insertion statement"); SQLOK(reset(stmt_add_message), "reseting message insertion statement"); }
bool RollbackManager::initDatabase() { verbosestream << "RollbackManager: Database connection setup" << std::endl; bool needs_create = !fs::PathExists(database_path); SQLOK(sqlite3_open_v2(database_path.c_str(), &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL)); if (needs_create) { createTables(); } SQLOK(sqlite3_prepare_v2(db, "INSERT INTO `action` (\n" " `actor`, `timestamp`, `type`,\n" " `list`, `index`, `add`, `stackNode`, `stackQuantity`, `nodeMeta`,\n" " `x`, `y`, `z`,\n" " `oldNode`, `oldParam1`, `oldParam2`, `oldMeta`,\n" " `newNode`, `newParam1`, `newParam2`, `newMeta`,\n" " `guessedActor`\n" ") VALUES (\n" " ?, ?, ?,\n" " ?, ?, ?, ?, ?, ?,\n" " ?, ?, ?,\n" " ?, ?, ?, ?,\n" " ?, ?, ?, ?,\n" " ?" ");", -1, &stmt_insert, NULL)); SQLOK(sqlite3_prepare_v2(db, "REPLACE INTO `action` (\n" " `actor`, `timestamp`, `type`,\n" " `list`, `index`, `add`, `stackNode`, `stackQuantity`, `nodeMeta`,\n" " `x`, `y`, `z`,\n" " `oldNode`, `oldParam1`, `oldParam2`, `oldMeta`,\n" " `newNode`, `newParam1`, `newParam2`, `newMeta`,\n" " `guessedActor`, `id`\n" ") VALUES (\n" " ?, ?, ?,\n" " ?, ?, ?, ?, ?, ?,\n" " ?, ?, ?,\n" " ?, ?, ?, ?,\n" " ?, ?, ?, ?,\n" " ?, ?\n" ");", -1, &stmt_replace, NULL)); SQLOK(sqlite3_prepare_v2(db, "SELECT\n" " `actor`, `timestamp`, `type`,\n" " `list`, `index`, `add`, `stackNode`, `stackQuantity`, `nodemeta`,\n" " `x`, `y`, `z`,\n" " `oldNode`, `oldParam1`, `oldParam2`, `oldMeta`,\n" " `newNode`, `newParam1`, `newParam2`, `newMeta`,\n" " `guessedActor`\n" " FROM `action`\n" " WHERE `timestamp` >= ?\n" " ORDER BY `timestamp` DESC, `id` DESC", -1, &stmt_select, NULL)); SQLOK(sqlite3_prepare_v2(db, "SELECT\n" " `actor`, `timestamp`, `type`,\n" " `list`, `index`, `add`, `stackNode`, `stackQuantity`, `nodemeta`,\n" " `x`, `y`, `z`,\n" " `oldNode`, `oldParam1`, `oldParam2`, `oldMeta`,\n" " `newNode`, `newParam1`, `newParam2`, `newMeta`,\n" " `guessedActor`\n" "FROM `action`\n" "WHERE `timestamp` >= ?\n" " AND `x` IS NOT NULL\n" " AND `y` IS NOT NULL\n" " AND `z` IS NOT NULL\n" " AND `x` BETWEEN ? AND ?\n" " AND `y` BETWEEN ? AND ?\n" " AND `z` BETWEEN ? AND ?\n" "ORDER BY `timestamp` DESC, `id` DESC\n" "LIMIT 0,?", -1, &stmt_select_range, NULL)); SQLOK(sqlite3_prepare_v2(db, "SELECT\n" " `actor`, `timestamp`, `type`,\n" " `list`, `index`, `add`, `stackNode`, `stackQuantity`, `nodemeta`,\n" " `x`, `y`, `z`,\n" " `oldNode`, `oldParam1`, `oldParam2`, `oldMeta`,\n" " `newNode`, `newParam1`, `newParam2`, `newMeta`,\n" " `guessedActor`\n" "FROM `action`\n" "WHERE `timestamp` >= ?\n" " AND `actor` = ?\n" "ORDER BY `timestamp` DESC, `id` DESC\n", -1, &stmt_select_withActor, NULL)); SQLOK(sqlite3_prepare_v2(db, "SELECT `id`, `name` FROM `actor`", -1, &stmt_knownActor_select, NULL)); SQLOK(sqlite3_prepare_v2(db, "INSERT INTO `actor` (`name`) VALUES (?)", -1, &stmt_knownActor_insert, NULL)); SQLOK(sqlite3_prepare_v2(db, "SELECT `id`, `name` FROM `node`", -1, &stmt_knownNode_select, NULL)); SQLOK(sqlite3_prepare_v2(db, "INSERT INTO `node` (`name`) VALUES (?)", -1, &stmt_knownNode_insert, NULL)); verbosestream << "SQL prepared statements setup correctly" << std::endl; while (sqlite3_step(stmt_knownActor_select) == SQLITE_ROW) { registerNewActor( sqlite3_column_int(stmt_knownActor_select, 0), reinterpret_cast<const char *>(sqlite3_column_text(stmt_knownActor_select, 1)) ); } SQLOK(sqlite3_reset(stmt_knownActor_select)); while (sqlite3_step(stmt_knownNode_select) == SQLITE_ROW) { registerNewNode( sqlite3_column_int(stmt_knownNode_select, 0), reinterpret_cast<const char *>(sqlite3_column_text(stmt_knownNode_select, 1)) ); } SQLOK(sqlite3_reset(stmt_knownNode_select)); return needs_create; }
void DB::endSave() { int res; SQLRES(step(stmt_commit), SQLITE_DONE, "running commit statement"); SQLOK(reset(stmt_commit), "reseting commit statement"); }
void DB::beginSave() { int res; SQLRES(step(stmt_begin), SQLITE_DONE, "running begin statement"); SQLOK(reset(stmt_begin), "reseting begin statement"); }
inline void Database_SQLite3::bindPos(sqlite3_stmt *stmt, const v3s16 &pos, int index) { SQLOK(sqlite3_bind_int64(stmt, index, getBlockAsInteger(pos)), "Internal error: failed to bind query at " __FILE__ ":" TOSTRING(__LINE__)); }
DB::DB(const std::string & filename) { int res; SQLOK(open(filename.c_str(), &dbh), "opening database"); SQLOK(exec(dbh, "PRAGMA synchronous=0;\n" "BEGIN;\n" "CREATE TABLE IF NOT EXISTS \"sender\" (\n" " \"id\" INTEGER NOT NULL,\n" " \"nick\" VARCHAR,\n" " \"user\" VARCHAR,\n" " \"host\" VARCHAR,\n" " PRIMARY KEY (\"id\")\n" ");\n" "CREATE TABLE IF NOT EXISTS \"network\" (\n" " \"id\" INTEGER NOT NULL,\n" " \"name\" VARCHAR,\n" " PRIMARY KEY (\"id\")\n" ");\n" "CREATE TABLE IF NOT EXISTS \"buffer\" (\n" " \"id\" INTEGER NOT NULL,\n" " \"networkid\" INTEGER NOT NULL,\n" " \"name\" VARCHAR,\n" " PRIMARY KEY (\"id\"),\n" " FOREIGN KEY (\"networkid\") REFERENCES \"network\" (\"id\")\n" ");\n" "CREATE TABLE IF NOT EXISTS \"log\" (\n" " \"id\" INTEGER NOT NULL,\n" " \"type\" INTEGER NOT NULL,\n" " \"timestamp\" INTEGER NOT NULL,\n" " \"bufferid\" INTEGER NOT NULL,\n" " \"senderid\" INTEGER NOT NULL,\n" " \"message\" VARCHAR,\n" " PRIMARY KEY (\"id\"),\n" " FOREIGN KEY (\"bufferid\") REFERENCES \"buffer\" (\"id\"),\n" " FOREIGN KEY (\"senderid\") REFERENCES \"sender\" (\"id\")\n" ");\n" "CREATE INDEX IF NOT EXISTS \"logBufferTimestamp\" ON \"log\" (\"bufferid\", \"timestamp\");\n" "CREATE INDEX IF NOT EXISTS \"logTimestamp\" ON \"log\" (\"timestamp\");\n" "COMMIT;\n", NULL, NULL, NULL), "initializing database"); PREPARE_STMT(stmt_add_message, "message insertion", "INSERT INTO \"log\"" " (\"timestamp\", \"type\", \"bufferid\", \"senderid\", \"message\")" " VALUES (?, ?, ?, ?, ?)"); PREPARE_STMT(stmt_add_buffer, "buffer insertion", "INSERT INTO \"buffer\" (\"networkid\", \"name\") " "VALUES (?, ?)"); PREPARE_STMT(stmt_add_network, "network insertion", "INSERT INTO \"network\" (\"name\") " "VALUES (?)"); PREPARE_STMT(stmt_add_sender, "sender insertion", "INSERT INTO \"sender\" (\"nick\", \"user\", \"host\") " "VALUES (?, ?, ?)"); PREPARE_STMT(stmt_begin, "begin", "BEGIN"); PREPARE_STMT(stmt_commit, "commit", "COMMIT"); loadNetworks(); loadBuffers(); loadSenders(); }
inline void Database_SQLite3::bindPos(sqlite3_stmt *stmt, const v3s16 &pos, int index) { SQLOK(sqlite3_bind_int64(stmt, index, getBlockAsInteger(pos))); }
void RollbackManager::migrate(const std::string & file_path) { std::cout << "Migrating from rollback.txt to rollback.sqlite." << std::endl; std::ifstream fh(file_path.c_str(), std::ios::in | std::ios::ate); if (!fh.good()) { throw FileNotGoodException("Unable to open rollback.txt"); } std::streampos file_size = fh.tellg(); if (file_size < 10) { errorstream << "Empty rollback log." << std::endl; return; } fh.seekg(0); sqlite3_stmt *stmt_begin; sqlite3_stmt *stmt_commit; SQLOK(sqlite3_prepare_v2(db, "BEGIN", -1, &stmt_begin, NULL)); SQLOK(sqlite3_prepare_v2(db, "COMMIT", -1, &stmt_commit, NULL)); std::string bit; int i = 0; time_t start = time(0); time_t t = start; SQLRES(sqlite3_step(stmt_begin), SQLITE_DONE); sqlite3_reset(stmt_begin); do { ActionRow row; row.id = 0; // Get the timestamp std::getline(fh, bit, ' '); bit = trim(bit); if (!atoi(bit.c_str())) { std::getline(fh, bit); continue; } row.timestamp = atoi(bit.c_str()); // Get the actor row.actor = getActorId(deSerializeJsonString(fh)); // Get the action type std::getline(fh, bit, '['); std::getline(fh, bit, ' '); if (bit == "modify_inventory_stack") { row.type = RollbackAction::TYPE_MODIFY_INVENTORY_STACK; row.location = trim(deSerializeJsonString(fh)); std::getline(fh, bit, ' '); row.list = trim(deSerializeJsonString(fh)); std::getline(fh, bit, ' '); std::getline(fh, bit, ' '); row.index = atoi(trim(bit).c_str()); std::getline(fh, bit, ' '); row.add = (int)(trim(bit) == "add"); row.stack.deSerialize(deSerializeJsonString(fh)); row.stack.id = getNodeId(row.stack.name); std::getline(fh, bit); } else if (bit == "set_node") { row.type = RollbackAction::TYPE_SET_NODE; std::getline(fh, bit, '('); std::getline(fh, bit, ','); row.x = atoi(trim(bit).c_str()); std::getline(fh, bit, ','); row.y = atoi(trim(bit).c_str()); std::getline(fh, bit, ')'); row.z = atoi(trim(bit).c_str()); std::getline(fh, bit, ' '); row.oldNode = getNodeId(trim(deSerializeJsonString(fh))); std::getline(fh, bit, ' '); std::getline(fh, bit, ' '); row.oldParam1 = atoi(trim(bit).c_str()); std::getline(fh, bit, ' '); row.oldParam2 = atoi(trim(bit).c_str()); row.oldMeta = trim(deSerializeJsonString(fh)); std::getline(fh, bit, ' '); row.newNode = getNodeId(trim(deSerializeJsonString(fh))); std::getline(fh, bit, ' '); std::getline(fh, bit, ' '); row.newParam1 = atoi(trim(bit).c_str()); std::getline(fh, bit, ' '); row.newParam2 = atoi(trim(bit).c_str()); row.newMeta = trim(deSerializeJsonString(fh)); std::getline(fh, bit, ' '); std::getline(fh, bit, ' '); std::getline(fh, bit); row.guessed = (int)(trim(bit) == "actor_is_guess"); } else { errorstream << "Unrecognized rollback action type \"" << bit << "\"!" << std::endl; continue; } registerRow(row); ++i; if (time(0) - t >= 1) { SQLRES(sqlite3_step(stmt_commit), SQLITE_DONE); sqlite3_reset(stmt_commit); t = time(0); std::cout << " Done: " << static_cast<int>((static_cast<float>(fh.tellg()) / static_cast<float>(file_size)) * 100) << "%" << " Speed: " << i / (t - start) << "/second \r" << std::flush; SQLRES(sqlite3_step(stmt_begin), SQLITE_DONE); sqlite3_reset(stmt_begin); } } while (fh.good()); SQLRES(sqlite3_step(stmt_commit), SQLITE_DONE); sqlite3_reset(stmt_commit); SQLOK(sqlite3_finalize(stmt_begin)); SQLOK(sqlite3_finalize(stmt_commit)); std::cout << " Done: 100% " << std::endl << "Now you can delete the old rollback.txt file." << std::endl; }
const std::list<ActionRow> RollbackManager::actionRowsFromSelect(sqlite3_stmt* stmt) { std::list<ActionRow> rows; const unsigned char * text; size_t size; while (sqlite3_step(stmt) == SQLITE_ROW) { ActionRow row; row.actor = sqlite3_column_int (stmt, 0); row.timestamp = sqlite3_column_int64(stmt, 1); row.type = sqlite3_column_int (stmt, 2); if (row.type == RollbackAction::TYPE_MODIFY_INVENTORY_STACK) { text = sqlite3_column_text (stmt, 3); size = sqlite3_column_bytes(stmt, 3); row.list = std::string(reinterpret_cast<const char*>(text), size); row.index = sqlite3_column_int(stmt, 4); row.add = sqlite3_column_int(stmt, 5); row.stack.id = sqlite3_column_int(stmt, 6); row.stack.count = sqlite3_column_int(stmt, 7); row.nodeMeta = sqlite3_column_int(stmt, 8); } if (row.type == RollbackAction::TYPE_SET_NODE || row.nodeMeta) { row.x = sqlite3_column_int(stmt, 9); row.y = sqlite3_column_int(stmt, 10); row.z = sqlite3_column_int(stmt, 11); } if (row.type == RollbackAction::TYPE_SET_NODE) { row.oldNode = sqlite3_column_int(stmt, 12); row.oldParam1 = sqlite3_column_int(stmt, 13); row.oldParam2 = sqlite3_column_int(stmt, 14); text = sqlite3_column_text (stmt, 15); size = sqlite3_column_bytes(stmt, 15); row.oldMeta = std::string(reinterpret_cast<const char*>(text), size); row.newNode = sqlite3_column_int(stmt, 16); row.newParam1 = sqlite3_column_int(stmt, 17); row.newParam2 = sqlite3_column_int(stmt, 18); text = sqlite3_column_text(stmt, 19); size = sqlite3_column_bytes(stmt, 19); row.newMeta = std::string(reinterpret_cast<const char*>(text), size); row.guessed = sqlite3_column_int(stmt, 20); } if (row.nodeMeta) { row.location = "nodemeta:"; row.location += itos(row.x); row.location += ','; row.location += itos(row.y); row.location += ','; row.location += itos(row.z); } else { row.location = getActorName(row.actor); } rows.push_back(row); } SQLOK(sqlite3_reset(stmt)); return rows; }
bool RollbackManager::registerRow(const ActionRow & row) { sqlite3_stmt * stmt_do = (row.id) ? stmt_replace : stmt_insert; bool nodeMeta = false; SQLOK(sqlite3_bind_int (stmt_do, 1, row.actor)); SQLOK(sqlite3_bind_int64(stmt_do, 2, row.timestamp)); SQLOK(sqlite3_bind_int (stmt_do, 3, row.type)); if (row.type == RollbackAction::TYPE_MODIFY_INVENTORY_STACK) { const std::string & loc = row.location; nodeMeta = (loc.substr(0, 9) == "nodemeta:"); SQLOK(sqlite3_bind_text(stmt_do, 4, row.list.c_str(), row.list.size(), NULL)); SQLOK(sqlite3_bind_int (stmt_do, 5, row.index)); SQLOK(sqlite3_bind_int (stmt_do, 6, row.add)); SQLOK(sqlite3_bind_int (stmt_do, 7, row.stack.id)); SQLOK(sqlite3_bind_int (stmt_do, 8, row.stack.count)); SQLOK(sqlite3_bind_int (stmt_do, 9, (int) nodeMeta)); if (nodeMeta) { std::string::size_type p1, p2; p1 = loc.find(':') + 1; p2 = loc.find(','); std::string x = loc.substr(p1, p2 - p1); p1 = p2 + 1; p2 = loc.find(',', p1); std::string y = loc.substr(p1, p2 - p1); std::string z = loc.substr(p2 + 1); SQLOK(sqlite3_bind_int(stmt_do, 10, atoi(x.c_str()))); SQLOK(sqlite3_bind_int(stmt_do, 11, atoi(y.c_str()))); SQLOK(sqlite3_bind_int(stmt_do, 12, atoi(z.c_str()))); } } else { SQLOK(sqlite3_bind_null(stmt_do, 4)); SQLOK(sqlite3_bind_null(stmt_do, 5)); SQLOK(sqlite3_bind_null(stmt_do, 6)); SQLOK(sqlite3_bind_null(stmt_do, 7)); SQLOK(sqlite3_bind_null(stmt_do, 8)); SQLOK(sqlite3_bind_null(stmt_do, 9)); } if (row.type == RollbackAction::TYPE_SET_NODE) { SQLOK(sqlite3_bind_int (stmt_do, 10, row.x)); SQLOK(sqlite3_bind_int (stmt_do, 11, row.y)); SQLOK(sqlite3_bind_int (stmt_do, 12, row.z)); SQLOK(sqlite3_bind_int (stmt_do, 13, row.oldNode)); SQLOK(sqlite3_bind_int (stmt_do, 14, row.oldParam1)); SQLOK(sqlite3_bind_int (stmt_do, 15, row.oldParam2)); SQLOK(sqlite3_bind_text(stmt_do, 16, row.oldMeta.c_str(), row.oldMeta.size(), NULL)); SQLOK(sqlite3_bind_int (stmt_do, 17, row.newNode)); SQLOK(sqlite3_bind_int (stmt_do, 18, row.newParam1)); SQLOK(sqlite3_bind_int (stmt_do, 19, row.newParam2)); SQLOK(sqlite3_bind_text(stmt_do, 20, row.newMeta.c_str(), row.newMeta.size(), NULL)); SQLOK(sqlite3_bind_int (stmt_do, 21, row.guessed ? 1 : 0)); } else { if (!nodeMeta) { SQLOK(sqlite3_bind_null(stmt_do, 10)); SQLOK(sqlite3_bind_null(stmt_do, 11)); SQLOK(sqlite3_bind_null(stmt_do, 12)); } SQLOK(sqlite3_bind_null(stmt_do, 13)); SQLOK(sqlite3_bind_null(stmt_do, 14)); SQLOK(sqlite3_bind_null(stmt_do, 15)); SQLOK(sqlite3_bind_null(stmt_do, 16)); SQLOK(sqlite3_bind_null(stmt_do, 17)); SQLOK(sqlite3_bind_null(stmt_do, 18)); SQLOK(sqlite3_bind_null(stmt_do, 19)); SQLOK(sqlite3_bind_null(stmt_do, 20)); SQLOK(sqlite3_bind_null(stmt_do, 21)); } if (row.id) { SQLOK(sqlite3_bind_int(stmt_do, 22, row.id)); } int written = sqlite3_step(stmt_do); SQLOK(sqlite3_reset(stmt_do)); return written == SQLITE_DONE; }