mirror of
https://github.com/fabianonline/telegram_backup.git
synced 2024-12-24 22:15:33 +00:00
Moved Dabase changes into their own class.
This commit is contained in:
parent
ac67818d28
commit
0b95b42607
@ -47,8 +47,8 @@ import de.fabianonline.telegram_backup.mediafilemanager.FileManagerFactory;
|
||||
public class Database {
|
||||
private Connection conn;
|
||||
private Statement stmt;
|
||||
private UserManager user_manager;
|
||||
private TelegramClient client;
|
||||
public UserManager user_manager;
|
||||
public TelegramClient client;
|
||||
|
||||
public Database(UserManager user_manager, TelegramClient client) {
|
||||
this(user_manager, client, true);
|
||||
@ -81,176 +81,20 @@ public class Database {
|
||||
|
||||
private void init(boolean update_db) {
|
||||
if (!update_db) return;
|
||||
|
||||
try {
|
||||
int version;
|
||||
ResultSet rs = stmt.executeQuery("SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='database_versions'");
|
||||
rs.next();
|
||||
if (rs.getInt(1)==0) {
|
||||
version = 0;
|
||||
} else {
|
||||
rs.close();
|
||||
rs = stmt.executeQuery("SELECT MAX(version) FROM database_versions");
|
||||
rs.next();
|
||||
version = rs.getInt(1);
|
||||
rs.close();
|
||||
}
|
||||
System.out.println("Database version: " + version);
|
||||
|
||||
if (version==0) {
|
||||
System.out.println(" Updating to version 1...");
|
||||
stmt.executeUpdate("CREATE TABLE messages ("
|
||||
+ "id INTEGER PRIMARY KEY ASC, "
|
||||
+ "dialog_id INTEGER, "
|
||||
+ "to_id INTEGER, "
|
||||
+ "from_id INTEGER, "
|
||||
+ "from_type TEXT, "
|
||||
+ "text TEXT, "
|
||||
+ "time TEXT, "
|
||||
+ "has_media BOOLEAN, "
|
||||
+ "sticker TEXT, "
|
||||
+ "data BLOB,"
|
||||
+ "type TEXT)");
|
||||
stmt.executeUpdate("CREATE TABLE dialogs ("
|
||||
+ "id INTEGER PRIMARY KEY ASC, "
|
||||
+ "name TEXT, "
|
||||
+ "type TEXT)");
|
||||
stmt.executeUpdate("CREATE TABLE people ("
|
||||
+ "id INTEGER PRIMARY KEY ASC, "
|
||||
+ "first_name TEXT, "
|
||||
+ "last_name TEXT, "
|
||||
+ "username TEXT, "
|
||||
+ "type TEXT)");
|
||||
stmt.executeUpdate("CREATE TABLE database_versions ("
|
||||
+ "version INTEGER)");
|
||||
stmt.executeUpdate("INSERT INTO database_versions (version) VALUES (1)");
|
||||
version = 1;
|
||||
}
|
||||
if (version==1) {
|
||||
System.out.println(" Updating to version 2...");
|
||||
stmt.executeUpdate("ALTER TABLE people RENAME TO 'users'");
|
||||
stmt.executeUpdate("ALTER TABLE users ADD COLUMN phone TEXT");
|
||||
stmt.executeUpdate("INSERT INTO database_versions (version) VALUES (2)");
|
||||
version = 2;
|
||||
}
|
||||
if (version==2) {
|
||||
System.out.println(" Updating to version 3...");
|
||||
stmt.executeUpdate("ALTER TABLE dialogs RENAME TO 'chats'");
|
||||
stmt.executeUpdate("INSERT INTO database_versions (version) VALUES (3)");
|
||||
version = 3;
|
||||
}
|
||||
if (version==3) {
|
||||
System.out.println(" Updating to version 4...");
|
||||
stmt.executeUpdate("CREATE TABLE messages_new (id INTEGER PRIMARY KEY ASC, dialog_id INTEGER, to_id INTEGER, from_id INTEGER, from_type TEXT, text TEXT, time INTEGER, has_media BOOLEAN, sticker TEXT, data BLOB, type TEXT);");
|
||||
stmt.executeUpdate("INSERT INTO messages_new SELECT * FROM messages");
|
||||
stmt.executeUpdate("DROP TABLE messages");
|
||||
stmt.executeUpdate("ALTER TABLE messages_new RENAME TO 'messages'");
|
||||
stmt.executeUpdate("INSERT INTO database_versions (version) VALUES (4)");
|
||||
version = 4;
|
||||
}
|
||||
if (version==4) {
|
||||
System.out.println(" Updating to version 5...");
|
||||
stmt.executeUpdate("CREATE TABLE runs (id INTEGER PRIMARY KEY ASC, time INTEGER, start_id INTEGER, end_id INTEGER, count_missing INTEGER)");
|
||||
stmt.executeUpdate("INSERT INTO database_versions (version) VALUES (5)");
|
||||
version = 5;
|
||||
}
|
||||
if (version==5) {
|
||||
backupDatabase(5);
|
||||
System.out.println(" Updating to version 6...");
|
||||
stmt.executeUpdate(
|
||||
"CREATE TABLE messages_new (\n" +
|
||||
" id INTEGER PRIMARY KEY ASC,\n" +
|
||||
" message_type TEXT,\n" +
|
||||
" dialog_id INTEGER,\n" +
|
||||
" chat_id INTEGER,\n" +
|
||||
" sender_id INTEGER,\n" +
|
||||
" fwd_from_id INTEGER,\n" +
|
||||
" text TEXT,\n" +
|
||||
" time INTEGER,\n" +
|
||||
" has_media BOOLEAN,\n" +
|
||||
" media_type TEXT,\n" +
|
||||
" media_file TEXT,\n" +
|
||||
" media_size INTEGER,\n" +
|
||||
" media_json TEXT,\n" +
|
||||
" markup_json TEXT,\n" +
|
||||
" data BLOB)");
|
||||
LinkedHashMap<String, String> mappings = new LinkedHashMap<String, String>();
|
||||
mappings.put("id", "id");
|
||||
mappings.put("message_type", "type");
|
||||
mappings.put("dialog_id", "CASE from_type WHEN 'user' THEN dialog_id ELSE NULL END");
|
||||
mappings.put("chat_id", "CASE from_type WHEN 'chat' THEN dialog_id ELSE NULL END");
|
||||
mappings.put("sender_id", "from_id");
|
||||
mappings.put("text", "text");
|
||||
mappings.put("time", "time");
|
||||
mappings.put("has_media", "has_media");
|
||||
mappings.put("data", "data");
|
||||
StringBuilder query = new StringBuilder("INSERT INTO messages_new\n(");
|
||||
boolean first;
|
||||
first = true;
|
||||
for(String s : mappings.keySet()) {
|
||||
if (!first) query.append(", ");
|
||||
query.append(s);
|
||||
first = false;
|
||||
}
|
||||
query.append(")\nSELECT \n");
|
||||
first = true;
|
||||
for (String s : mappings.values()) {
|
||||
if (!first) query.append(", ");
|
||||
query.append(s);
|
||||
first = false;
|
||||
}
|
||||
query.append("\nFROM messages");
|
||||
stmt.executeUpdate(query.toString());
|
||||
|
||||
System.out.println(" Updating the data (this might take some time)...");
|
||||
rs = stmt.executeQuery("SELECT id, data FROM messages_new");
|
||||
PreparedStatement ps = conn.prepareStatement("UPDATE messages_new SET fwd_from_id=?, media_type=?, media_file=?, media_size=? WHERE id=?");
|
||||
while (rs.next()) {
|
||||
ps.setInt(5, rs.getInt(1));
|
||||
TLMessage msg = bytesToTLMessage(rs.getBytes(2));
|
||||
if (msg==null || msg.getFwdFromId()==null || ! (msg.getFwdFromId() instanceof TLPeerUser)) {
|
||||
ps.setNull(1, Types.INTEGER);
|
||||
} else {
|
||||
ps.setInt(1, ((TLPeerUser)msg.getFwdFromId()).getUserId());
|
||||
}
|
||||
AbstractMediaFileManager f = FileManagerFactory.getFileManager(msg, user_manager, client);
|
||||
if (f==null) {
|
||||
ps.setNull(2, Types.VARCHAR);
|
||||
ps.setNull(3, Types.VARCHAR);
|
||||
ps.setNull(4, Types.INTEGER);
|
||||
} else {
|
||||
ps.setString(2, f.getName());
|
||||
ps.setString(3, f.getTargetFilename());
|
||||
ps.setInt(4, f.getSize());
|
||||
}
|
||||
ps.addBatch();
|
||||
}
|
||||
rs.close();
|
||||
conn.setAutoCommit(false);
|
||||
ps.executeBatch();
|
||||
conn.commit();
|
||||
conn.setAutoCommit(true);
|
||||
stmt.executeUpdate("DROP TABLE messages");
|
||||
stmt.executeUpdate("ALTER TABLE messages_new RENAME TO messages");
|
||||
stmt.executeUpdate("INSERT INTO database_versions (version) VALUES (6)");
|
||||
version = 6;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} catch (SQLException e) {
|
||||
System.out.println(e.getSQLState());
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
DatabaseUpdates updates = new DatabaseUpdates(conn, this);
|
||||
updates.doUpdates();
|
||||
}
|
||||
|
||||
private void backupDatabase(int currentVersion) {
|
||||
public void backupDatabase(int currentVersion) {
|
||||
String filename = String.format(Config.FILE_NAME_DB_BACKUP, currentVersion);
|
||||
System.out.println(" Creating a backup of your database as " + filename);
|
||||
try {
|
||||
String src = user_manager.getFileBase() + Config.FILE_NAME_DB;
|
||||
String dst = user_manager.getFileBase() + filename;
|
||||
Log.debug("Copying %s to %s", src, dst);
|
||||
Files.copy(
|
||||
new File(user_manager.getFileBase() + Config.FILE_NAME_DB).toPath(),
|
||||
new File(user_manager.getFileBase() + filename).toPath(),
|
||||
new File(src).toPath(),
|
||||
new File(dst).toPath(),
|
||||
StandardCopyOption.REPLACE_EXISTING);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
|
@ -0,0 +1,296 @@
|
||||
package de.fabianonline.telegram_backup;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.sql.Types;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.PreparedStatement;
|
||||
import com.github.badoualy.telegram.tl.api.*;
|
||||
import de.fabianonline.telegram_backup.mediafilemanager.FileManagerFactory;
|
||||
import de.fabianonline.telegram_backup.mediafilemanager.AbstractMediaFileManager;
|
||||
|
||||
public class DatabaseUpdates {
|
||||
protected Connection conn;
|
||||
protected Database db;
|
||||
private static LinkedList<DatabaseUpdate> updates = new LinkedList<DatabaseUpdate>();
|
||||
|
||||
public DatabaseUpdates(Connection conn, Database db) {
|
||||
this.conn = conn;
|
||||
this.db = db;
|
||||
Log.debug("Registering Database Updates...");
|
||||
Log.up();
|
||||
register(new DB_Update_1(conn, db));
|
||||
register(new DB_Update_2(conn, db));
|
||||
register(new DB_Update_3(conn, db));
|
||||
register(new DB_Update_4(conn, db));
|
||||
register(new DB_Update_5(conn, db));
|
||||
register(new DB_Update_6(conn, db));
|
||||
Log.down();
|
||||
}
|
||||
|
||||
public void doUpdates() {
|
||||
try {
|
||||
Statement stmt = conn.createStatement();
|
||||
ResultSet rs;
|
||||
Log.debug("DatabaseUpdate.doUpdates running");
|
||||
Log.up();
|
||||
|
||||
Log.debug("Getting current database version");
|
||||
Log.up();
|
||||
int version;
|
||||
Log.debug("Checking if table database_versions exists");
|
||||
rs = stmt.executeQuery("SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='database_versions'");
|
||||
rs.next();
|
||||
if (rs.getInt(1)==0) {
|
||||
Log.debug("Table does not exist");
|
||||
version = 0;
|
||||
} else {
|
||||
Log.debug("Table exists. Checking max version");
|
||||
rs.close();
|
||||
rs = stmt.executeQuery("SELECT MAX(version) FROM database_versions");
|
||||
rs.next();
|
||||
version = rs.getInt(1);
|
||||
rs.close();
|
||||
}
|
||||
Log.debug("version: %d", version);
|
||||
Log.down();
|
||||
System.out.println("Database version: " + version);
|
||||
Log.debug("Max available database version is %d", getMaxPossibleVersion());
|
||||
|
||||
if (version < getMaxPossibleVersion()) {
|
||||
Log.debug("Update is necessary. %d => %d.", version, getMaxPossibleVersion());
|
||||
boolean backup = false;
|
||||
for (int i=version+1; i<=getMaxPossibleVersion(); i++) {
|
||||
if (getUpdateToVersion(i).needsBackup()) {
|
||||
Log.debug("Update to version %d needs a backup", i);
|
||||
backup=true;
|
||||
}
|
||||
}
|
||||
if (backup) {
|
||||
Log.debug("Performing backup");
|
||||
Log.up();
|
||||
db.backupDatabase(version);
|
||||
Log.down();
|
||||
}
|
||||
|
||||
Log.debug("Applying updates");
|
||||
Log.up();
|
||||
try {
|
||||
for (int i=version+1; i<=getMaxPossibleVersion(); i++) {
|
||||
Log.up();
|
||||
getUpdateToVersion(i).doUpdate();
|
||||
Log.down();
|
||||
}
|
||||
} catch (SQLException e) { throw new RuntimeException(e); }
|
||||
Log.down();
|
||||
} else {
|
||||
Log.debug("No update necessary.");
|
||||
}
|
||||
|
||||
Log.down();
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private DatabaseUpdate getUpdateToVersion(int i) { return updates.get(i); }
|
||||
|
||||
private int getMaxPossibleVersion() {
|
||||
return updates.size();
|
||||
}
|
||||
|
||||
private void register(DatabaseUpdate d) {
|
||||
Log.debug("Registering %s as update to version %d", d.getClass().getName(), d.getVersion());
|
||||
if (d.getVersion() != updates.size()+1) {
|
||||
throw new RuntimeException("Tried to register DB update to version " + d.getVersion() + ", but would need update to version " + (updates.size()+1));
|
||||
}
|
||||
updates.add(d);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class DatabaseUpdate {
|
||||
protected Connection conn;
|
||||
protected Statement stmt;
|
||||
protected Database db;
|
||||
public DatabaseUpdate(Connection conn, Database db) {
|
||||
this.conn = conn;
|
||||
try {
|
||||
stmt = conn.createStatement();
|
||||
} catch (SQLException e) { throw new RuntimeException(e); }
|
||||
this.db = db;
|
||||
|
||||
}
|
||||
public void doUpdate() throws SQLException {
|
||||
Log.debug("Applying update to version %d", getVersion());
|
||||
System.out.println(" Updating to version " + getVersion() + "...");
|
||||
Log.up();
|
||||
_doUpdate();
|
||||
Log.down();
|
||||
Log.debug("Saving current database version to the db");
|
||||
stmt.executeUpdate("INSERT INTO database_versions (version) VALUES (" + getVersion() + ")");
|
||||
}
|
||||
|
||||
protected abstract void _doUpdate() throws SQLException;
|
||||
public abstract int getVersion();
|
||||
public boolean needsBackup() { return false; }
|
||||
}
|
||||
|
||||
class DB_Update_1 extends DatabaseUpdate {
|
||||
public int getVersion() { return 1; }
|
||||
public DB_Update_1(Connection conn, Database db) { super(conn, db); }
|
||||
|
||||
protected void _doUpdate() throws SQLException {
|
||||
stmt.executeUpdate("CREATE TABLE messages ("
|
||||
+ "id INTEGER PRIMARY KEY ASC, "
|
||||
+ "dialog_id INTEGER, "
|
||||
+ "to_id INTEGER, "
|
||||
+ "from_id INTEGER, "
|
||||
+ "from_type TEXT, "
|
||||
+ "text TEXT, "
|
||||
+ "time TEXT, "
|
||||
+ "has_media BOOLEAN, "
|
||||
+ "sticker TEXT, "
|
||||
+ "data BLOB,"
|
||||
+ "type TEXT)");
|
||||
stmt.executeUpdate("CREATE TABLE dialogs ("
|
||||
+ "id INTEGER PRIMARY KEY ASC, "
|
||||
+ "name TEXT, "
|
||||
+ "type TEXT)");
|
||||
stmt.executeUpdate("CREATE TABLE people ("
|
||||
+ "id INTEGER PRIMARY KEY ASC, "
|
||||
+ "first_name TEXT, "
|
||||
+ "last_name TEXT, "
|
||||
+ "username TEXT, "
|
||||
+ "type TEXT)");
|
||||
stmt.executeUpdate("CREATE TABLE database_versions ("
|
||||
+ "version INTEGER)");
|
||||
}
|
||||
}
|
||||
|
||||
class DB_Update_2 extends DatabaseUpdate {
|
||||
public int getVersion() { return 2; }
|
||||
public DB_Update_2(Connection conn, Database db) { super(conn, db); }
|
||||
|
||||
protected void _doUpdate() throws SQLException {
|
||||
stmt.executeUpdate("ALTER TABLE people RENAME TO 'users'");
|
||||
stmt.executeUpdate("ALTER TABLE users ADD COLUMN phone TEXT");
|
||||
}
|
||||
}
|
||||
|
||||
class DB_Update_3 extends DatabaseUpdate {
|
||||
public int getVersion() { return 3; }
|
||||
public DB_Update_3(Connection conn, Database db) { super(conn, db); }
|
||||
|
||||
protected void _doUpdate() throws SQLException {
|
||||
stmt.executeUpdate("ALTER TABLE dialogs RENAME TO 'chats'");
|
||||
}
|
||||
}
|
||||
|
||||
class DB_Update_4 extends DatabaseUpdate {
|
||||
public int getVersion() { return 4; }
|
||||
public DB_Update_4(Connection conn, Database db) { super(conn, db); }
|
||||
|
||||
protected void _doUpdate() throws SQLException {
|
||||
stmt.executeUpdate("CREATE TABLE messages_new (id INTEGER PRIMARY KEY ASC, dialog_id INTEGER, to_id INTEGER, from_id INTEGER, from_type TEXT, text TEXT, time INTEGER, has_media BOOLEAN, sticker TEXT, data BLOB, type TEXT);");
|
||||
stmt.executeUpdate("INSERT INTO messages_new SELECT * FROM messages");
|
||||
stmt.executeUpdate("DROP TABLE messages");
|
||||
stmt.executeUpdate("ALTER TABLE messages_new RENAME TO 'messages'");
|
||||
}
|
||||
}
|
||||
|
||||
class DB_Update_5 extends DatabaseUpdate {
|
||||
public int getVersion() { return 5; }
|
||||
public DB_Update_5(Connection conn, Database db) { super(conn, db); }
|
||||
|
||||
protected void _doUpdate() throws SQLException {
|
||||
stmt.executeUpdate("CREATE TABLE runs (id INTEGER PRIMARY KEY ASC, time INTEGER, start_id INTEGER, end_id INTEGER, count_missing INTEGER)");
|
||||
}
|
||||
}
|
||||
|
||||
class DB_Update_6 extends DatabaseUpdate {
|
||||
public int getVersion() { return 6; }
|
||||
public DB_Update_6(Connection conn, Database db) { super(conn, db); }
|
||||
public boolean needsBackup() { return true; }
|
||||
|
||||
protected void _doUpdate() throws SQLException {
|
||||
stmt.executeUpdate(
|
||||
"CREATE TABLE messages_new (\n" +
|
||||
" id INTEGER PRIMARY KEY ASC,\n" +
|
||||
" message_type TEXT,\n" +
|
||||
" dialog_id INTEGER,\n" +
|
||||
" chat_id INTEGER,\n" +
|
||||
" sender_id INTEGER,\n" +
|
||||
" fwd_from_id INTEGER,\n" +
|
||||
" text TEXT,\n" +
|
||||
" time INTEGER,\n" +
|
||||
" has_media BOOLEAN,\n" +
|
||||
" media_type TEXT,\n" +
|
||||
" media_file TEXT,\n" +
|
||||
" media_size INTEGER,\n" +
|
||||
" media_json TEXT,\n" +
|
||||
" markup_json TEXT,\n" +
|
||||
" data BLOB)");
|
||||
LinkedHashMap<String, String> mappings = new LinkedHashMap<String, String>();
|
||||
mappings.put("id", "id");
|
||||
mappings.put("message_type", "type");
|
||||
mappings.put("dialog_id", "CASE from_type WHEN 'user' THEN dialog_id ELSE NULL END");
|
||||
mappings.put("chat_id", "CASE from_type WHEN 'chat' THEN dialog_id ELSE NULL END");
|
||||
mappings.put("sender_id", "from_id");
|
||||
mappings.put("text", "text");
|
||||
mappings.put("time", "time");
|
||||
mappings.put("has_media", "has_media");
|
||||
mappings.put("data", "data");
|
||||
StringBuilder query = new StringBuilder("INSERT INTO messages_new\n(");
|
||||
boolean first;
|
||||
first = true;
|
||||
for(String s : mappings.keySet()) {
|
||||
if (!first) query.append(", ");
|
||||
query.append(s);
|
||||
first = false;
|
||||
}
|
||||
query.append(")\nSELECT \n");
|
||||
first = true;
|
||||
for (String s : mappings.values()) {
|
||||
if (!first) query.append(", ");
|
||||
query.append(s);
|
||||
first = false;
|
||||
}
|
||||
query.append("\nFROM messages");
|
||||
stmt.executeUpdate(query.toString());
|
||||
|
||||
System.out.println(" Updating the data (this might take some time)...");
|
||||
ResultSet rs = stmt.executeQuery("SELECT id, data FROM messages_new");
|
||||
PreparedStatement ps = conn.prepareStatement("UPDATE messages_new SET fwd_from_id=?, media_type=?, media_file=?, media_size=? WHERE id=?");
|
||||
while (rs.next()) {
|
||||
ps.setInt(5, rs.getInt(1));
|
||||
TLMessage msg = db.bytesToTLMessage(rs.getBytes(2));
|
||||
if (msg==null || msg.getFwdFromId()==null || ! (msg.getFwdFromId() instanceof TLPeerUser)) {
|
||||
ps.setNull(1, Types.INTEGER);
|
||||
} else {
|
||||
ps.setInt(1, ((TLPeerUser)msg.getFwdFromId()).getUserId());
|
||||
}
|
||||
AbstractMediaFileManager f = FileManagerFactory.getFileManager(msg, db.user_manager, db.client);
|
||||
if (f==null) {
|
||||
ps.setNull(2, Types.VARCHAR);
|
||||
ps.setNull(3, Types.VARCHAR);
|
||||
ps.setNull(4, Types.INTEGER);
|
||||
} else {
|
||||
ps.setString(2, f.getName());
|
||||
ps.setString(3, f.getTargetFilename());
|
||||
ps.setInt(4, f.getSize());
|
||||
}
|
||||
ps.addBatch();
|
||||
}
|
||||
rs.close();
|
||||
conn.setAutoCommit(false);
|
||||
ps.executeBatch();
|
||||
conn.commit();
|
||||
conn.setAutoCommit(true);
|
||||
stmt.executeUpdate("DROP TABLE messages");
|
||||
stmt.executeUpdate("ALTER TABLE messages_new RENAME TO messages");
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user