From 4836366b4861451767bb69464207d7e0f0d869f0 Mon Sep 17 00:00:00 2001 From: M66B Date: Sun, 12 May 2024 20:35:00 +0200 Subject: [PATCH] Debug: legacy queries --- .../java/eu/faircode/email/DaoMessage.java | 168 ++++++++++++++++++ .../faircode/email/FragmentOptionsMisc.java | 15 ++ .../eu/faircode/email/ViewModelMessages.java | 151 +++++++++++----- .../main/res/layout/fragment_options_misc.xml | 13 +- app/src/main/res/values/strings.xml | 1 + 5 files changed, 298 insertions(+), 50 deletions(-) diff --git a/app/src/main/java/eu/faircode/email/DaoMessage.java b/app/src/main/java/eu/faircode/email/DaoMessage.java index 903a93c18a..d3d4d529d6 100644 --- a/app/src/main/java/eu/faircode/email/DaoMessage.java +++ b/app/src/main/java/eu/faircode/email/DaoMessage.java @@ -1068,4 +1068,172 @@ public interface DaoMessage { " ORDER BY received DESC" + " LIMIT :keep)") int deleteMessagesKeep(long folder, int keep); + + @Transaction + @SuppressWarnings(RoomWarnings.CURSOR_MISMATCH) + @Query("SELECT message.*" + + ", account.pop AS accountProtocol, account.name AS accountName, account.category AS accountCategory, COALESCE(identity.color, folder.color, account.color) AS accountColor" + + ", account.notify AS accountNotify, account.summary AS accountSummary, account.leave_deleted AS accountLeaveDeleted, account.auto_seen AS accountAutoSeen" + + ", folder.name AS folderName, folder.color AS folderColor, folder.display AS folderDisplay, folder.type AS folderType, NULL AS folderInheritedType, folder.unified AS folderUnified, folder.read_only AS folderReadOnly" + + ", IFNULL(identity.display, identity.name) AS identityName, identity.email AS identityEmail, identity.color AS identityColor, identity.synchronize AS identitySynchronize" + + ", '[' || substr(group_concat(message.`from`, ','), 0, 2048) || ']' AS senders" + + ", '[' || substr(group_concat(message.`to`, ','), 0, 2048) || ']' AS recipients" + + ", COUNT(message.id) AS count" + + ", SUM(1 - message.ui_seen) AS unseen" + + ", SUM(1 - message.ui_flagged) AS unflagged" + + ", SUM(folder.type = '" + EntityFolder.DRAFTS + "') AS drafts" + + ", COUNT(DISTINCT" + + " CASE WHEN NOT message.hash IS NULL THEN message.hash" + + " WHEN NOT message.msgid IS NULL THEN message.msgid" + + " ELSE message.id END) AS visible" + + ", COUNT(DISTINCT" + + " CASE WHEN message.ui_seen THEN NULL" + + " WHEN NOT message.hash IS NULL THEN message.hash" + + " WHEN NOT message.msgid IS NULL THEN message.msgid" + + " ELSE message.id END) AS visible_unseen" + + ", SUM(message.attachments) AS totalAttachments" + + ", SUM(message.total) AS totalSize" + + ", message.priority AS ui_priority" + + ", message.importance AS ui_importance" + + ", MAX(CASE WHEN" + + " (:found AND folder.type <> '" + EntityFolder.ARCHIVE + "' AND NOT (" + is_outgoing + "))" + + " OR (NOT :found AND :type IS NULL AND folder.unified)" + + " OR (NOT :found AND folder.type = :type)" + + " THEN message.received ELSE 0 END) AS dummy" + + " FROM (SELECT * FROM message" + + " WHERE message.thread IN" + + " (SELECT DISTINCT mm.thread FROM folder ff" + + " JOIN message mm ON mm.folder = ff.id" + + " WHERE ((:found AND mm.ui_found)" + + " OR (NOT :found AND :type IS NULL AND ff.unified)" + + " OR (NOT :found AND :type IS NOT NULL AND ff.type = :type))" + + " AND (NOT mm.ui_hide OR :debug))" + + " ORDER BY received DESC) AS message" + // group_concat + " JOIN account_view AS account ON account.id = message.account" + + " LEFT JOIN identity_view AS identity ON identity.id = message.identity" + + " JOIN folder_view AS folder ON folder.id = message.folder" + + " WHERE account.`synchronize`" + + " AND (:threading OR (:type IS NULL AND (folder.unified OR :found)) OR (:type IS NOT NULL AND folder.type = :type))" + + " AND (NOT message.ui_hide OR :debug)" + + " AND (NOT :found OR message.ui_found = :found)" + + " GROUP BY account.id, CASE WHEN message.thread IS NULL OR NOT :threading THEN message.id ELSE message.thread END" + + " HAVING (SUM((:found AND message.ui_found)" + + " OR (NOT :found AND :type IS NULL AND folder.unified)" + + " OR (NOT :found AND :type IS NOT NULL AND folder.type = :type)) > 0)" + // thread can be the same in different accounts + " AND SUM(NOT message.ui_hide OR :debug) > 0" + + " AND (NOT :filter_seen OR SUM(1 - message.ui_seen) > 0)" + + " AND (NOT :filter_unflagged OR COUNT(message.id) - SUM(1 - message.ui_flagged) > 0)" + + " AND (NOT :filter_unknown OR SUM(message.avatar IS NOT NULL AND message.sender <> identity.email) > 0)" + + " AND (NOT :filter_snoozed OR message.ui_snoozed IS NULL OR " + is_drafts + ")" + + " AND (NOT :filter_deleted OR NOT message.ui_deleted)" + + " AND (:filter_language IS NULL OR SUM(message.language = :filter_language) > 0)" + + " ORDER BY CASE WHEN :found THEN 0 ELSE -IFNULL(message.importance, 1) END" + + ", CASE WHEN :group_category THEN account.category ELSE '' END COLLATE NOCASE" + + ", CASE" + + " WHEN 'unread' = :sort1 THEN SUM(1 - message.ui_seen) = 0" + + " WHEN 'starred' = :sort1 THEN COUNT(message.id) - SUM(1 - message.ui_flagged) = 0" + + " WHEN 'priority' = :sort1 THEN -IFNULL(message.priority, 1)" + + " WHEN 'sender' = :sort1 THEN LOWER(message.sender)" + + " WHEN 'subject' = :sort1 THEN LOWER(message.subject)" + + " WHEN 'size' = :sort1 THEN -SUM(message.total)" + + " WHEN 'attachments' = :sort1 THEN -SUM(message.attachments)" + + " WHEN 'snoozed' = :sort1 THEN SUM(CASE WHEN message.ui_snoozed IS NULL THEN 0 ELSE 1 END) = 0" + + " WHEN 'touched' = :sort1 THEN IFNULL(-message.last_touched, 0)" + + " ELSE 0" + + " END" + + ", CASE" + + " WHEN 'unread' = :sort2 THEN SUM(1 - message.ui_seen) = 0" + + " WHEN 'starred' = :sort2 THEN COUNT(message.id) - SUM(1 - message.ui_flagged) = 0" + + " ELSE 0" + + " END" + + ", CASE WHEN :ascending THEN message.received ELSE -message.received END") + DataSource.Factory pagedUnifiedLegacy( + String type, + boolean threading, boolean group_category, + String sort1, String sort2, boolean ascending, + boolean filter_seen, boolean filter_unflagged, boolean filter_unknown, boolean filter_snoozed, boolean filter_deleted, String filter_language, + boolean found, + boolean debug); + + @Transaction + @SuppressWarnings(RoomWarnings.CURSOR_MISMATCH) + @Query("SELECT message.*" + + ", account.pop AS accountProtocol, account.name AS accountName, account.category AS accountCategory, COALESCE(identity.color, folder.color, account.color) AS accountColor" + + ", account.notify AS accountNotify, account.summary AS accountSummary, account.leave_deleted AS accountLeaveDeleted, account.auto_seen AS accountAutoSeen" + + ", folder.name AS folderName, folder.color AS folderColor, folder.display AS folderDisplay, folder.type AS folderType, f.inherited_type AS folderInheritedType, folder.unified AS folderUnified, folder.read_only AS folderReadOnly" + + ", IFNULL(identity.display, identity.name) AS identityName, identity.email AS identityEmail, identity.color AS identityColor, identity.synchronize AS identitySynchronize" + + ", '[' || substr(group_concat(message.`from`, ','), 0, 2048) || ']' AS senders" + + ", '[' || substr(group_concat(message.`to`, ','), 0, 2048) || ']' AS recipients" + + ", COUNT(message.id) AS count" + + ", SUM(1 - message.ui_seen) AS unseen" + + ", SUM(1 - message.ui_flagged) AS unflagged" + + ", SUM(folder.type = '" + EntityFolder.DRAFTS + "') AS drafts" + + ", COUNT(DISTINCT" + + " CASE WHEN NOT message.hash IS NULL THEN message.hash" + + " WHEN NOT message.msgid IS NULL THEN message.msgid" + + " ELSE message.id END) AS visible" + + ", COUNT(DISTINCT" + + " CASE WHEN message.ui_seen THEN NULL" + + " WHEN NOT message.hash IS NULL THEN message.hash" + + " WHEN NOT message.msgid IS NULL THEN message.msgid" + + " ELSE message.id END) AS visible_unseen" + + ", SUM(message.attachments) AS totalAttachments" + + ", SUM(message.total) AS totalSize" + + ", message.priority AS ui_priority" + + ", message.importance AS ui_importance" + + ", MAX(CASE WHEN" + + " (:found AND folder.type <> '" + EntityFolder.ARCHIVE + "' AND NOT (" + is_outgoing + "))" + + " OR (NOT :found AND folder.id = :folder)" + + " THEN message.received ELSE 0 END) AS dummy" + + " FROM (SELECT * FROM message" + + " WHERE message.thread IN" + + " (SELECT DISTINCT mm.thread FROM message mm" + + " WHERE mm.folder = :folder" + + " AND (NOT mm.ui_hide OR :debug)" + + " AND (NOT :found OR mm.ui_found))" + + " ORDER BY received DESC) AS message" + // group_concat + " JOIN account_view AS account ON account.id = message.account" + + " LEFT JOIN identity_view AS identity ON identity.id = message.identity" + + " JOIN folder_view AS folder ON folder.id = message.folder" + + " JOIN folder_view AS f ON f.id = :folder" + + " WHERE (message.account = f.account OR message.account = identity.account OR " + is_outbox + ")" + + " AND (:threading OR folder.id = :folder)" + + " AND (NOT message.ui_hide OR :debug)" + + " AND (NOT :found OR message.ui_found = :found)" + + " GROUP BY CASE WHEN message.thread IS NULL OR NOT :threading THEN message.id ELSE message.thread END" + + " HAVING (SUM((:found AND message.ui_found)" + + " OR (NOT :found AND message.folder = :folder)) > 0)" + + " AND SUM(NOT message.ui_hide OR :debug) > 0" + + " AND (NOT :filter_seen OR SUM(1 - message.ui_seen) > 0 OR " + is_outbox + ")" + + " AND (NOT :filter_unflagged OR COUNT(message.id) - SUM(1 - message.ui_flagged) > 0 OR " + is_outbox + ")" + + " AND (NOT :filter_unknown OR SUM(message.avatar IS NOT NULL AND message.sender <> identity.email) > 0" + + " OR " + is_outbox + " OR " + is_drafts + " OR " + is_sent + ")" + + " AND (NOT :filter_snoozed OR message.ui_snoozed IS NULL OR " + is_outbox + " OR " + is_drafts + ")" + + " AND (NOT :filter_deleted OR NOT message.ui_deleted)" + + " AND (:filter_language IS NULL OR SUM(message.language = :filter_language) > 0 OR " + is_outbox + ")" + + " ORDER BY CASE WHEN :found THEN 0 ELSE -IFNULL(message.importance, 1) END" + + ", CASE" + + " WHEN 'unread' = :sort1 THEN SUM(1 - message.ui_seen) = 0" + + " WHEN 'starred' = :sort1 THEN COUNT(message.id) - SUM(1 - message.ui_flagged) = 0" + + " WHEN 'priority' = :sort1 THEN -IFNULL(message.priority, 1)" + + " WHEN 'sender' = :sort1 THEN LOWER(message.sender)" + + " WHEN 'subject' = :sort1 THEN LOWER(message.subject)" + + " WHEN 'size' = :sort1 THEN -SUM(message.total)" + + " WHEN 'attachments' = :sort1 THEN -SUM(message.attachments)" + + " WHEN 'snoozed' = :sort1 THEN SUM(CASE WHEN message.ui_snoozed IS NULL THEN 0 ELSE 1 END) = 0" + + " WHEN 'touched' = :sort1 THEN IFNULL(-message.last_touched, 0)" + + " ELSE 0" + + " END" + + ", CASE" + + " WHEN 'unread' = :sort2 THEN SUM(1 - message.ui_seen) = 0" + + " WHEN 'starred' = :sort2 THEN COUNT(message.id) - SUM(1 - message.ui_flagged) = 0" + + " ELSE 0" + + " END" + + ", CASE WHEN :ascending THEN message.received ELSE -message.received END") + DataSource.Factory pagedFolderLegacy( + long folder, boolean threading, + String sort1, String sort2, boolean ascending, + boolean filter_seen, boolean filter_unflagged, boolean filter_unknown, boolean filter_snoozed, boolean filter_deleted, String filter_language, + boolean found, + boolean debug); } \ No newline at end of file diff --git a/app/src/main/java/eu/faircode/email/FragmentOptionsMisc.java b/app/src/main/java/eu/faircode/email/FragmentOptionsMisc.java index b4983c59f9..aad849111b 100644 --- a/app/src/main/java/eu/faircode/email/FragmentOptionsMisc.java +++ b/app/src/main/java/eu/faircode/email/FragmentOptionsMisc.java @@ -78,6 +78,7 @@ import androidx.appcompat.widget.SwitchCompat; import androidx.cardview.widget.CardView; import androidx.constraintlayout.widget.Group; import androidx.lifecycle.Observer; +import androidx.lifecycle.ViewModelProvider; import androidx.preference.PreferenceManager; import androidx.work.WorkManager; @@ -180,6 +181,7 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc private TextView tvSqliteCache; private SeekBar sbSqliteCache; private ImageButton ibSqliteCache; + private SwitchCompat swLegacyQueries; private SwitchCompat swOauthTabs; private TextView tvChunkSize; private SeekBar sbChunkSize; @@ -280,6 +282,7 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc "test1", "test2", "test3", "test4", "test5", "emergency_file", "work_manager", "task_description", // "external_storage", "sqlite_integrity_check", "wal", "sqlite_checkpoints", "sqlite_analyze", "sqlite_auto_vacuum", "sqlite_sync_extra", "sqlite_cache", + "legacy_queries", "oauth_tabs", "chunk_size", "thread_range", "autoscroll_editor", "undo_manager", @@ -425,6 +428,7 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc tvSqliteCache = view.findViewById(R.id.tvSqliteCache); sbSqliteCache = view.findViewById(R.id.sbSqliteCache); ibSqliteCache = view.findViewById(R.id.ibSqliteCache); + swLegacyQueries = view.findViewById(R.id.swLegacyQueries); swOauthTabs = view.findViewById(R.id.swOauthTabs); tvChunkSize = view.findViewById(R.id.tvChunkSize); sbChunkSize = view.findViewById(R.id.sbChunkSize); @@ -1242,6 +1246,15 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc } }); + swLegacyQueries.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton v, boolean checked) { + prefs.edit().putBoolean("legacy_queries", checked).apply(); + ViewModelMessages model = new ViewModelProvider(getActivity()).get(ViewModelMessages.class); + model.clear(); + } + }); + swOauthTabs.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton v, boolean checked) { @@ -2353,6 +2366,8 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc Helper.humanReadableByteCount(cache_size * 1024L))); sbSqliteCache.setProgress(sqlite_cache); + swLegacyQueries.setChecked(prefs.getBoolean("legacy_queries", false)); + swOauthTabs.setChecked(prefs.getBoolean("oauth_tabs", true)); int chunk_size = prefs.getInt("chunk_size", Core.DEFAULT_CHUNK_SIZE); diff --git a/app/src/main/java/eu/faircode/email/ViewModelMessages.java b/app/src/main/java/eu/faircode/email/ViewModelMessages.java index cc06c63786..0bca433d05 100644 --- a/app/src/main/java/eu/faircode/email/ViewModelMessages.java +++ b/app/src/main/java/eu/faircode/email/ViewModelMessages.java @@ -34,6 +34,7 @@ import androidx.lifecycle.LiveData; import androidx.lifecycle.Observer; import androidx.lifecycle.OnLifecycleEvent; import androidx.lifecycle.ViewModel; +import androidx.paging.DataSource; import androidx.paging.LivePagedListBuilder; import androidx.paging.PagedList; import androidx.preference.PreferenceManager; @@ -87,6 +88,9 @@ public class ViewModelMessages extends ViewModel { boolean filter_archive, BoundaryCallbackMessages.SearchCriteria criteria, boolean server) { + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); + boolean legacy = prefs.getBoolean("legacy_queries", false); + Args args = new Args(context, viewType, type, account, folder, thread, id, threading, @@ -112,6 +116,7 @@ public class ViewModelMessages extends ViewModel { viewType, args.account, args.folder, args.server, args.criteria, args.server ? REMOTE_PAGE_SIZE : SEARCH_PAGE_SIZE); + DataSource.Factory pager; LivePagedListBuilder builder = null; switch (viewType) { case UNIFIED: @@ -119,21 +124,35 @@ public class ViewModelMessages extends ViewModel { .setPageSize(LOCAL_PAGE_SIZE) .setMaxSize(MAX_CACHED_ITEMS) .build(); - builder = new LivePagedListBuilder<>( - db.message().pagedUnified( - args.type, - args.threading, - args.group_category, - args.sort1, args.sort2, args.ascending, - args.filter_seen, - args.filter_unflagged, - args.filter_unknown, - args.filter_snoozed, - args.filter_deleted, - args.filter_language, - false, - args.debug), - configUnified); + if (legacy) + pager = db.message().pagedUnifiedLegacy( + args.type, + args.threading, + args.group_category, + args.sort1, args.sort2, args.ascending, + args.filter_seen, + args.filter_unflagged, + args.filter_unknown, + args.filter_snoozed, + args.filter_deleted, + args.filter_language, + false, + args.debug); + else + pager = db.message().pagedUnified( + args.type, + args.threading, + args.group_category, + args.sort1, args.sort2, args.ascending, + args.filter_seen, + args.filter_unflagged, + args.filter_unknown, + args.filter_snoozed, + args.filter_deleted, + args.filter_language, + false, + args.debug); + builder = new LivePagedListBuilder<>(pager, configUnified); break; case FOLDER: @@ -143,19 +162,31 @@ public class ViewModelMessages extends ViewModel { .setPrefetchDistance(REMOTE_PAGE_SIZE) .setMaxSize(MAX_CACHED_ITEMS) .build(); - builder = new LivePagedListBuilder<>( - db.message().pagedFolder( - args.folder, args.threading, - args.sort1, args.sort2, args.ascending, - args.filter_seen, - args.filter_unflagged, - args.filter_unknown, - args.filter_snoozed, - args.filter_deleted, - args.filter_language, - false, - args.debug), - configFolder); + if (legacy) + pager = db.message().pagedFolderLegacy( + args.folder, args.threading, + args.sort1, args.sort2, args.ascending, + args.filter_seen, + args.filter_unflagged, + args.filter_unknown, + args.filter_snoozed, + args.filter_deleted, + args.filter_language, + false, + args.debug); + else + pager = db.message().pagedFolder( + args.folder, args.threading, + args.sort1, args.sort2, args.ascending, + args.filter_seen, + args.filter_unflagged, + args.filter_unknown, + args.filter_snoozed, + args.filter_deleted, + args.filter_language, + false, + args.debug); + builder = new LivePagedListBuilder<>(pager, configFolder); builder.setBoundaryCallback(boundary); break; @@ -179,27 +210,45 @@ public class ViewModelMessages extends ViewModel { .setPrefetchDistance(REMOTE_PAGE_SIZE) .setMaxSize(MAX_CACHED_ITEMS) .build(); - if (args.folder < 0) - builder = new LivePagedListBuilder<>( - db.message().pagedUnified( - null, - args.threading, false, - criteria == null || criteria.touched == null ? "time" : "touched", "", false, - false, false, false, false, false, - null, - true, - args.debug), - configSearch); - else - builder = new LivePagedListBuilder<>( - db.message().pagedFolder( - args.folder, args.threading, - criteria == null || criteria.touched == null ? "time" : "touched", "", false, - false, false, false, false, false, - null, - true, - args.debug), - configSearch); + if (args.folder < 0) { + if (legacy) + pager = db.message().pagedUnifiedLegacy( + null, + args.threading, false, + criteria == null || criteria.touched == null ? "time" : "touched", "", false, + false, false, false, false, false, + null, + true, + args.debug); + else + pager = db.message().pagedUnified( + null, + args.threading, false, + criteria == null || criteria.touched == null ? "time" : "touched", "", false, + false, false, false, false, false, + null, + true, + args.debug); + builder = new LivePagedListBuilder<>(pager, configSearch); + } else { + if (legacy) + pager = db.message().pagedFolderLegacy( + args.folder, args.threading, + criteria == null || criteria.touched == null ? "time" : "touched", "", false, + false, false, false, false, false, + null, + true, + args.debug); + else + pager = db.message().pagedFolder( + args.folder, args.threading, + criteria == null || criteria.touched == null ? "time" : "touched", "", false, + false, false, false, false, false, + null, + true, + args.debug); + builder = new LivePagedListBuilder<>(pager, configSearch); + } builder.setBoundaryCallback(boundary); break; } @@ -497,6 +546,10 @@ public class ViewModelMessages extends ViewModel { } } + void clear() { + models.clear(); + } + private class Args { private long account; private String type; diff --git a/app/src/main/res/layout/fragment_options_misc.xml b/app/src/main/res/layout/fragment_options_misc.xml index 3398eafdf3..5c3d80d8dc 100644 --- a/app/src/main/res/layout/fragment_options_misc.xml +++ b/app/src/main/res/layout/fragment_options_misc.xml @@ -1149,6 +1149,17 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/ibSqliteCache" /> + + sqlite auto vacuum sqlite sync extra sqlite cache: %1$s %% - %2$s + Legacy queries OAuth tabs Chunk size: %1$d Thread range: %1$d days