diff --git a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java index 4cdb62214..f1cf78760 100644 --- a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java +++ b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java @@ -11,6 +11,8 @@ import android.os.SystemClock; import android.util.Base64; import android.util.Log; +import com.google.common.base.Stopwatch; + import org.json.JSONException; import org.json.JSONObject; import org.whispersystems.libsignal.IdentityKey; @@ -62,7 +64,9 @@ import eu.siacs.conversations.xmpp.mam.MamReference; public class DatabaseBackend extends SQLiteOpenHelper { private static final String DATABASE_NAME = "history"; - private static final int DATABASE_VERSION = 48; + private static final int DATABASE_VERSION = 49; + + private static boolean requiresMessageIndexRebuild = false; private static DatabaseBackend instance = null; private static final String CREATE_CONTATCS_STATEMENT = "create table " + Contact.TABLENAME + "(" + Contact.ACCOUNT + " TEXT, " @@ -187,6 +191,17 @@ public class DatabaseBackend extends SQLiteOpenHelper { return values; } + public static boolean requiresMessageIndexRebuild() { + return requiresMessageIndexRebuild; + } + + public void rebuildMessagesIndex() { + final SQLiteDatabase db = getWritableDatabase(); + final Stopwatch stopwatch = Stopwatch.createStarted(); + db.execSQL(COPY_PREEXISTING_ENTRIES); + Log.d(Config.LOGTAG,"rebuilt message index in "+ stopwatch.stop().toString()); + } + public static synchronized DatabaseBackend getInstance(Context context) { if (instance == null) { instance = new DatabaseBackend(context); @@ -520,14 +535,6 @@ public class DatabaseBackend extends SQLiteOpenHelper { db.execSQL(CREATE_RESOLVER_RESULTS_TABLE); } - if (oldVersion < 41 && newVersion >= 41) { - db.execSQL(CREATE_MESSAGE_INDEX_TABLE); - db.execSQL(CREATE_MESSAGE_INSERT_TRIGGER); - db.execSQL(CREATE_MESSAGE_UPDATE_TRIGGER); - db.execSQL(CREATE_MESSAGE_DELETE_TRIGGER); - db.execSQL(COPY_PREEXISTING_ENTRIES); - } - if (oldVersion < 42 && newVersion >= 42) { db.execSQL("DROP TRIGGER IF EXISTS after_message_delete"); } @@ -554,10 +561,10 @@ public class DatabaseBackend extends SQLiteOpenHelper { if (oldVersion < 46 && newVersion >= 46) { final long start = SystemClock.elapsedRealtime(); db.rawQuery("PRAGMA secure_delete = FALSE", null).close(); - db.execSQL("update "+Message.TABLENAME+" set "+Message.EDITED+"=NULL"); + db.execSQL("update " + Message.TABLENAME + " set " + Message.EDITED + "=NULL"); db.rawQuery("PRAGMA secure_delete=ON", null).close(); final long diff = SystemClock.elapsedRealtime() - start; - Log.d(Config.LOGTAG,"deleted old edit information in "+diff+"ms"); + Log.d(Config.LOGTAG, "deleted old edit information in " + diff + "ms"); } if (oldVersion < 47 && newVersion >= 47) { db.execSQL("ALTER TABLE " + Contact.TABLENAME + " ADD COLUMN " + Contact.PRESENCE_NAME + " TEXT"); @@ -565,6 +572,19 @@ public class DatabaseBackend extends SQLiteOpenHelper { if (oldVersion < 48 && newVersion >= 48) { db.execSQL("ALTER TABLE " + Contact.TABLENAME + " ADD COLUMN " + Contact.RTP_CAPABILITY + " TEXT"); } + if (oldVersion < 49 && newVersion >= 49) { + db.beginTransaction(); + db.execSQL("DROP TRIGGER IF EXISTS after_message_insert;"); + db.execSQL("DROP TRIGGER IF EXISTS after_message_update;"); + db.execSQL("DROP TABLE IF EXISTS messages_index;"); + db.execSQL(CREATE_MESSAGE_INDEX_TABLE); + db.execSQL(CREATE_MESSAGE_INSERT_TRIGGER); + db.execSQL(CREATE_MESSAGE_UPDATE_TRIGGER); + db.execSQL(CREATE_MESSAGE_DELETE_TRIGGER); + requiresMessageIndexRebuild = true; + db.setTransactionSuccessful(); + db.endTransaction(); + } } private void canonicalizeJids(SQLiteDatabase db) { @@ -779,7 +799,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { try { list.add(0, Message.fromCursor(cursor, conversation)); } catch (Exception e) { - Log.e(Config.LOGTAG,"unable to restore message"); + Log.e(Config.LOGTAG, "unable to restore message"); } } cursor.close(); @@ -790,14 +810,12 @@ public class DatabaseBackend extends SQLiteOpenHelper { final SQLiteDatabase db = this.getReadableDatabase(); final StringBuilder SQL = new StringBuilder(); final String[] selectionArgs; - // TODO: change "ON messages_index.uuid=messages.uuid" to - // "ON messages_index.rowid=messages.rowid" when everyone's migrated. - SQL.append("SELECT " + Message.TABLENAME + ".*," + Conversation.TABLENAME + "." + Conversation.CONTACTJID + "," + Conversation.TABLENAME + "." + Conversation.ACCOUNT + "," + Conversation.TABLENAME + "." + Conversation.MODE + " FROM " + Message.TABLENAME + " JOIN " + Conversation.TABLENAME + " ON " + Message.TABLENAME + "." + Message.CONVERSATION + "=" + Conversation.TABLENAME + "." + Conversation.UUID + " JOIN messages_index ON messages_index.uuid=messages.uuid WHERE " + Message.ENCRYPTION + " NOT IN(" + Message.ENCRYPTION_AXOLOTL_NOT_FOR_THIS_DEVICE + "," + Message.ENCRYPTION_PGP + "," + Message.ENCRYPTION_DECRYPTION_FAILED + "," + Message.ENCRYPTION_AXOLOTL_FAILED + ") AND " + Message.TYPE + " IN(" + Message.TYPE_TEXT + "," + Message.TYPE_PRIVATE + ") AND messages_index.body MATCH ?"); + SQL.append("SELECT " + Message.TABLENAME + ".*," + Conversation.TABLENAME + "." + Conversation.CONTACTJID + "," + Conversation.TABLENAME + "." + Conversation.ACCOUNT + "," + Conversation.TABLENAME + "." + Conversation.MODE + " FROM " + Message.TABLENAME + " JOIN " + Conversation.TABLENAME + " ON " + Message.TABLENAME + "." + Message.CONVERSATION + "=" + Conversation.TABLENAME + "." + Conversation.UUID + " JOIN messages_index ON messages_index.rowid=messages.rowid WHERE " + Message.ENCRYPTION + " NOT IN(" + Message.ENCRYPTION_AXOLOTL_NOT_FOR_THIS_DEVICE + "," + Message.ENCRYPTION_PGP + "," + Message.ENCRYPTION_DECRYPTION_FAILED + "," + Message.ENCRYPTION_AXOLOTL_FAILED + ") AND " + Message.TYPE + " IN(" + Message.TYPE_TEXT + "," + Message.TYPE_PRIVATE + ") AND messages_index.body MATCH ?"); if (uuid == null) { selectionArgs = new String[]{FtsUtils.toMatchString(term)}; } else { selectionArgs = new String[]{FtsUtils.toMatchString(term), uuid}; - SQL.append(" AND "+Conversation.TABLENAME+'.'+Conversation.UUID+"=?"); + SQL.append(" AND " + Conversation.TABLENAME + '.' + Conversation.UUID + "=?"); } SQL.append(" ORDER BY " + Message.TIME_SENT + " DESC limit " + Config.MAX_SEARCH_RESULTS); Log.d(Config.LOGTAG, "search term: " + FtsUtils.toMatchString(term)); @@ -861,7 +879,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { public List getFilePathInfo() { final SQLiteDatabase db = this.getReadableDatabase(); - final Cursor cursor = db.query(Message.TABLENAME, new String[]{Message.UUID, Message.RELATIVE_FILE_PATH, Message.DELETED}, "type in (1,2,5) and "+Message.RELATIVE_FILE_PATH+" is not null", null, null, null, null); + final Cursor cursor = db.query(Message.TABLENAME, new String[]{Message.UUID, Message.RELATIVE_FILE_PATH, Message.DELETED}, "type in (1,2,5) and " + Message.RELATIVE_FILE_PATH + " is not null", null, null, null, null); final List list = new ArrayList<>(); while (cursor != null && cursor.moveToNext()) { list.add(new FilePathInfo(cursor.getString(0), cursor.getString(1), cursor.getInt(2) > 0)); @@ -874,7 +892,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { public List getRelativeFilePaths(String account, Jid jid, int limit) { SQLiteDatabase db = this.getReadableDatabase(); - final String SQL = "select uuid,relativeFilePath from messages where type in (1,2,5) and deleted=0 and "+Message.RELATIVE_FILE_PATH+" is not null and conversationUuid=(select uuid from conversations where accountUuid=? and (contactJid=? or contactJid like ?)) order by timeSent desc"; + final String SQL = "select uuid,relativeFilePath from messages where type in (1,2,5) and deleted=0 and " + Message.RELATIVE_FILE_PATH + " is not null and conversationUuid=(select uuid from conversations where accountUuid=? and (contactJid=? or contactJid like ?)) order by timeSent desc"; final String[] args = {account, jid.toString(), jid.toString() + "/%"}; Cursor cursor = db.rawQuery(SQL + (limit > 0 ? " limit " + limit : ""), args); List filesPaths = new ArrayList<>(); @@ -899,7 +917,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { public boolean deleted; private FilePathInfo(String uuid, String path, boolean deleted) { - super(uuid,path); + super(uuid, path); this.deleted = deleted; } @@ -1043,9 +1061,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { long start = SystemClock.elapsedRealtime(); final SQLiteDatabase db = this.getWritableDatabase(); db.beginTransaction(); - String[] args = {conversation.getUuid()}; - // TODO: remove once everyone has the after_message_delete trigger - db.delete("messages_index", "uuid in (select uuid from messages where conversationUuid=?)", args); + final String[] args = {conversation.getUuid()}; int num = db.delete(Message.TABLENAME, Message.CONVERSATION + "=?", args); db.setTransactionSuccessful(); db.endTransaction(); @@ -1055,9 +1071,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { public void expireOldMessages(long timestamp) { final String[] args = {String.valueOf(timestamp)}; SQLiteDatabase db = this.getReadableDatabase(); - // TODO: remove once everyone has the after_message_delete trigger db.beginTransaction(); - db.delete("messages_index", "uuid in (select uuid from messages where timeSent { - long deletionDate = getAutomaticMessageDeletionDate(); + if (DatabaseBackend.requiresMessageIndexRebuild()) { + DatabaseBackend.getInstance(this).rebuildMessagesIndex(); + } + final long deletionDate = getAutomaticMessageDeletionDate(); mLastExpiryRun.set(SystemClock.elapsedRealtime()); if (deletionDate > 0) { Log.d(Config.LOGTAG, "deleting messages that are older than " + AbstractGenerator.getTimestamp(deletionDate));