diff --git a/plans/2026-09-04-badge-binding-and-file-limits.md b/plans/2026-09-04-badge-binding-and-file-limits.md index 209e0314f6..899ba8305a 100644 --- a/plans/2026-09-04-badge-binding-and-file-limits.md +++ b/plans/2026-09-04-badge-binding-and-file-limits.md @@ -18,7 +18,7 @@ The changes: 5. Forwarding a file above the forwarder's limit is refused with an alert before the forwarding sheet opens, and again, for the chosen destination, before anything is uploaded. 6. A received file keeps its two proofs, so a file re-sent to a new member as part of history keeps them; the sender's own files get fresh proofs from the credential. -Two new columns on `files`, and a new table `file_badge_proofs` holding the invitation proof and the description proof of a file, kept for history. The same table holds the proof of a group member, forwarded in channel introductions. A new column on `connections`, the request header of a prepared connection. The relay invitation includes the channel's public group id and the owner's member key. In simplexmq: the hash of the fields shared by all descriptions of one upload, the verification codes of a connection, links and invitations before link data is signed, and the minimum SMP version raised to 15. +Two new columns on `files`, and a new table `file_badge_proofs` holding the invitation proof and the description proof of a file, kept for history. A new table `group_member_badge_proofs` holding the proof a member presented in a group, forwarded in channel introductions. A new column on `connections`, the request header of a prepared connection. The relay invitation includes the channel's public group id and the owner's member key. In simplexmq: the hash of the fields shared by all descriptions of one upload, the verification codes of a connection, links and invitations before link data is signed, and the minimum SMP version raised to 15. ## Terms @@ -518,37 +518,27 @@ ALTER TABLE connections ADD COLUMN pres_header BLOB; **11. Member proofs** — `Badges.hs`, `Types.hs`, `Types/Preferences.hs`, `Store/Shared.hs`, `Store/Groups.hs`, `Store/Connections.hs`, `Internal.hs`, `Subscriber.hs` -A member's accepted proof is stored on the membership, in `file_badge_proofs`, and forwarded in channel introductions. The badge in the profile row is kept for display. +A member's accepted proof is stored on the membership, in `group_member_badge_proofs`, and forwarded in channel introductions. The badge in the profile row is kept for display: the profile row of a member linked to a contact is the contact's. Migration `M20260925_badge_bindings`, after the statement of item 6, SQLite: ```sql -PRAGMA writable_schema=1; - -UPDATE sqlite_master -SET sql = replace(sql, 'file_id INTEGER NOT NULL REFERENCES files', 'file_id INTEGER REFERENCES files') -WHERE name = 'file_badge_proofs' AND type = 'table'; - -PRAGMA writable_schema=RESET; - -ALTER TABLE file_badge_proofs ADD COLUMN group_member_id INTEGER REFERENCES group_members ON DELETE CASCADE; - -CREATE UNIQUE INDEX idx_file_badge_proofs_group_member_id ON file_badge_proofs(group_member_id); +CREATE TABLE group_member_badge_proofs( + group_member_id INTEGER PRIMARY KEY REFERENCES group_members ON DELETE CASCADE, + badge_proof BLOB NOT NULL, + badge_pres_header BLOB NOT NULL, + badge_key_idx INTEGER NOT NULL, + badge_type TEXT NOT NULL, + badge_expiry TEXT NOT NULL, + badge_extra TEXT NOT NULL, + created_at TEXT NOT NULL, + updated_at TEXT NOT NULL +) STRICT; ``` -Postgres: +Postgres: `BIGINT`, `BYTEA` and `TIMESTAMPTZ`. Both schema dumps and `chat_query_plans.txt` are updated. -```sql -ALTER TABLE file_badge_proofs ALTER COLUMN file_id DROP NOT NULL; - -ALTER TABLE file_badge_proofs ADD COLUMN group_member_id BIGINT REFERENCES group_members ON DELETE CASCADE; - -CREATE UNIQUE INDEX idx_file_badge_proofs_group_member_id ON file_badge_proofs(group_member_id); -``` - -In the down migration, member rows are deleted before `file_id` is `NOT NULL` again. Both schema dumps and `chat_query_plans.txt` are updated. - -- A member row has `group_member_id` set, `file_id` NULL, and `proof_kind` `member`: `BPKMember` in `BadgeProofKind`. It is ignored by `getFileBadgeProofs`. +- One row per member, keyed by the member id, as `rcv_files` is keyed by the file id. - `MaybeBadgeProofRow` and `maybeRowToBadgeProof` in `Badges.hs`: the six proof columns of a `LEFT JOIN`. - `PrefsJSON` is generalised: @@ -561,7 +551,7 @@ In the down migration, member rows are deleted before `file_id` is `NOT NULL` ag The field is omitted by `ToJSON`; `NoJSON Nothing` is returned by `FromJSON`. `NoJSON` is used at the construction sites. - `GroupMember` gains `memberBadgeProof :: NoJSON BadgeProof`. It is removed from the bot API docs: `removeField "memberBadgeProof" $ sti @GroupMember`. - Reads: - - The proof columns are selected by `groupMemberQuery` after the connection columns, with `LEFT JOIN file_badge_proofs bp ON bp.group_member_id = m.group_member_id`; the field is set by `toContactMember`. + - The proof columns are selected by `groupMemberQuery` after the connection columns, with `LEFT JOIN group_member_badge_proofs bp ON bp.group_member_id = m.group_member_id`; the field is set by `toContactMember`. - They are selected the same way by the member read of `getConnectionEntity` (`Connections.hs:145-194`); the field is set by `toGroupAndMember`. - `NoJSON Nothing` is set by `toGroupMember`, for the membership, chat item members and quoted members. - Writes, for a received profile: diff --git a/src/Simplex/Chat/Badges.hs b/src/Simplex/Chat/Badges.hs index 970bf6477b..e9308fb186 100644 --- a/src/Simplex/Chat/Badges.hs +++ b/src/Simplex/Chat/Badges.hs @@ -143,18 +143,16 @@ instance TextEncoding BadgeStatus where -- Badge proof kind - a file has at most one proof of each kind -data BadgeProofKind = BPKInvitation | BPKDescription | BPKMember +data BadgeProofKind = BPKInvitation | BPKDescription deriving (Eq, Show) instance TextEncoding BadgeProofKind where textEncode = \case BPKInvitation -> "inv" BPKDescription -> "descr" - BPKMember -> "member" textDecode = \case "inv" -> Just BPKInvitation "descr" -> Just BPKDescription - "member" -> Just BPKMember _ -> Nothing -- Disclosed badge content (BBS messages 1, 2, 3) diff --git a/src/Simplex/Chat/Store/Connections.hs b/src/Simplex/Chat/Store/Connections.hs index e47f043130..0a58b1cfd9 100644 --- a/src/Simplex/Chat/Store/Connections.hs +++ b/src/Simplex/Chat/Store/Connections.hs @@ -183,7 +183,7 @@ getConnectionEntityKeys db cxt user@User {userId, userContactId} agentConnId = d JOIN group_profiles gp USING (group_profile_id) JOIN group_members mu ON g.group_id = mu.group_id JOIN contact_profiles pu ON pu.contact_profile_id = COALESCE(mu.member_profile_id, mu.contact_profile_id) - LEFT JOIN file_badge_proofs bp ON bp.group_member_id = m.group_member_id + LEFT JOIN group_member_badge_proofs bp ON bp.group_member_id = m.group_member_id WHERE m.group_member_id = ? AND g.user_id = ? AND mu.contact_id = ? AND mu.member_status NOT IN (?,?,?) |] diff --git a/src/Simplex/Chat/Store/Files.hs b/src/Simplex/Chat/Store/Files.hs index cbe1646caa..1ba7c98fce 100644 --- a/src/Simplex/Chat/Store/Files.hs +++ b/src/Simplex/Chat/Store/Files.hs @@ -683,7 +683,6 @@ getFileBadgeProofs db fileId = foldl' addProof (Nothing, Nothing) <$> DB.query d addProof (inv_, descr_) (Only kind :. row) = case kind of BPKInvitation -> (rowToBadgeProof row, descr_) BPKDescription -> (inv_, rowToBadgeProof row) - BPKMember -> (inv_, descr_) toRcvFileDescr :: (Int64, Text, Int, BoolInt) -> RcvFileDescr toRcvFileDescr (fileDescrId, fileDescrText, fileDescrPartNo, BI fileDescrComplete) = diff --git a/src/Simplex/Chat/Store/Groups.hs b/src/Simplex/Chat/Store/Groups.hs index f9ab998568..68e94ceea8 100644 --- a/src/Simplex/Chat/Store/Groups.hs +++ b/src/Simplex/Chat/Store/Groups.hs @@ -231,7 +231,7 @@ import Data.Text (Text) import qualified Data.Text as T import Data.Time.Clock (NominalDiffTime, UTCTime (..), addUTCTime, getCurrentTime) import Data.Text.Encoding (encodeUtf8) -import Simplex.Chat.Badges (BadgeProof, BadgeProofKind (..), BadgeRow, ProofPresHeader, acceptedProof, badgeProofToRow, badgeToRow) +import Simplex.Chat.Badges (BadgeProof, BadgeRow, ProofPresHeader, acceptedProof, badgeProofToRow, badgeToRow) import Simplex.Chat.Names (SimplexDomainClaim (..)) import Simplex.Chat.Messages import Simplex.Chat.Operators @@ -3475,7 +3475,7 @@ setMemberBadgeProof :: DB.Connection -> GroupMember -> Maybe ProofPresHeader -> setMemberBadgeProof db m@GroupMember {groupMemberId} presHeader_ Profile {badge} = case badge of Just b | not (acceptedProof presHeader_ b) -> pure m _ -> do - DB.execute db "DELETE FROM file_badge_proofs WHERE group_member_id = ?" (Only groupMemberId) + DB.execute db "DELETE FROM group_member_badge_proofs WHERE group_member_id = ?" (Only groupMemberId) forM_ badge $ createMemberBadgeProof db groupMemberId pure m {memberBadgeProof = NoJSON badge} @@ -3484,8 +3484,8 @@ createMemberBadgeProof db groupMemberId badge = do currentTs <- getCurrentTime DB.execute db - "INSERT INTO file_badge_proofs (group_member_id, proof_kind, badge_proof, badge_pres_header, badge_key_idx, badge_type, badge_expiry, badge_extra, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?,?)" - ((groupMemberId, BPKMember) :. badgeProofToRow badge :. (currentTs, currentTs)) + "INSERT INTO group_member_badge_proofs (group_member_id, badge_proof, badge_pres_header, badge_key_idx, badge_type, badge_expiry, badge_extra, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?)" + (Only groupMemberId :. badgeProofToRow badge :. (currentTs, currentTs)) getXGrpLinkMemReceived :: DB.Connection -> GroupMemberId -> ExceptT StoreError IO Bool getXGrpLinkMemReceived db mId = diff --git a/src/Simplex/Chat/Store/Postgres/Migrations/M20260925_badge_bindings.hs b/src/Simplex/Chat/Store/Postgres/Migrations/M20260925_badge_bindings.hs index 20c6b85de8..7464219085 100644 --- a/src/Simplex/Chat/Store/Postgres/Migrations/M20260925_badge_bindings.hs +++ b/src/Simplex/Chat/Store/Postgres/Migrations/M20260925_badge_bindings.hs @@ -11,23 +11,23 @@ m20260925_badge_bindings = [r| ALTER TABLE connections ADD COLUMN pres_header BYTEA; -ALTER TABLE file_badge_proofs ALTER COLUMN file_id DROP NOT NULL; - -ALTER TABLE file_badge_proofs ADD COLUMN group_member_id BIGINT REFERENCES group_members ON DELETE CASCADE; - -CREATE UNIQUE INDEX idx_file_badge_proofs_group_member_id ON file_badge_proofs(group_member_id); +CREATE TABLE group_member_badge_proofs( + group_member_id BIGINT PRIMARY KEY REFERENCES group_members ON DELETE CASCADE, + badge_proof BYTEA NOT NULL, + badge_pres_header BYTEA NOT NULL, + badge_key_idx BIGINT NOT NULL, + badge_type TEXT NOT NULL, + badge_expiry TIMESTAMPTZ NOT NULL, + badge_extra TEXT NOT NULL, + created_at TIMESTAMPTZ NOT NULL, + updated_at TIMESTAMPTZ NOT NULL +); |] down_m20260925_badge_bindings :: Text down_m20260925_badge_bindings = [r| -DROP INDEX idx_file_badge_proofs_group_member_id; - -DELETE FROM file_badge_proofs WHERE group_member_id IS NOT NULL; - -ALTER TABLE file_badge_proofs DROP COLUMN group_member_id; - -ALTER TABLE file_badge_proofs ALTER COLUMN file_id SET NOT NULL; +DROP TABLE group_member_badge_proofs; ALTER TABLE connections DROP COLUMN pres_header; |] diff --git a/src/Simplex/Chat/Store/Postgres/Migrations/chat_schema.sql b/src/Simplex/Chat/Store/Postgres/Migrations/chat_schema.sql index 51541d5175..54237b9474 100644 --- a/src/Simplex/Chat/Store/Postgres/Migrations/chat_schema.sql +++ b/src/Simplex/Chat/Store/Postgres/Migrations/chat_schema.sql @@ -875,7 +875,7 @@ ALTER TABLE test_chat_schema.extra_xftp_file_descriptions ALTER COLUMN extra_fil CREATE TABLE test_chat_schema.file_badge_proofs ( badge_proof_id bigint NOT NULL, - file_id bigint, + file_id bigint NOT NULL, proof_kind text NOT NULL, badge_proof bytea NOT NULL, badge_pres_header bytea NOT NULL, @@ -884,8 +884,7 @@ CREATE TABLE test_chat_schema.file_badge_proofs ( badge_expiry timestamp with time zone NOT NULL, badge_extra text NOT NULL, created_at timestamp with time zone NOT NULL, - updated_at timestamp with time zone NOT NULL, - group_member_id bigint + updated_at timestamp with time zone NOT NULL ); @@ -946,6 +945,20 @@ ALTER TABLE test_chat_schema.files ALTER COLUMN file_id ADD GENERATED ALWAYS AS +CREATE TABLE test_chat_schema.group_member_badge_proofs ( + group_member_id bigint NOT NULL, + badge_proof bytea NOT NULL, + badge_pres_header bytea NOT NULL, + badge_key_idx bigint NOT NULL, + badge_type text NOT NULL, + badge_expiry timestamp with time zone NOT NULL, + badge_extra text NOT NULL, + created_at timestamp with time zone NOT NULL, + updated_at timestamp with time zone NOT NULL +); + + + CREATE TABLE test_chat_schema.group_member_intros ( group_member_intro_id bigint NOT NULL, re_group_member_id bigint NOT NULL, @@ -1940,6 +1953,11 @@ ALTER TABLE ONLY test_chat_schema.files +ALTER TABLE ONLY test_chat_schema.group_member_badge_proofs + ADD CONSTRAINT group_member_badge_proofs_pkey PRIMARY KEY (group_member_id); + + + ALTER TABLE ONLY test_chat_schema.group_member_intros ADD CONSTRAINT group_member_intros_pkey PRIMARY KEY (group_member_intro_id); @@ -2630,10 +2648,6 @@ CREATE UNIQUE INDEX idx_file_badge_proofs_file_id_kind ON test_chat_schema.file_ -CREATE UNIQUE INDEX idx_file_badge_proofs_group_member_id ON test_chat_schema.file_badge_proofs USING btree (group_member_id); - - - CREATE INDEX idx_files_chat_item_id ON test_chat_schema.files USING btree (chat_item_id); @@ -3330,11 +3344,6 @@ ALTER TABLE ONLY test_chat_schema.file_badge_proofs -ALTER TABLE ONLY test_chat_schema.file_badge_proofs - ADD CONSTRAINT file_badge_proofs_group_member_id_fkey FOREIGN KEY (group_member_id) REFERENCES test_chat_schema.group_members(group_member_id) ON DELETE CASCADE; - - - ALTER TABLE ONLY test_chat_schema.files ADD CONSTRAINT files_contact_id_fkey FOREIGN KEY (contact_id) REFERENCES test_chat_schema.contacts(contact_id) ON DELETE CASCADE; @@ -3415,6 +3424,11 @@ ALTER TABLE ONLY test_chat_schema.users +ALTER TABLE ONLY test_chat_schema.group_member_badge_proofs + ADD CONSTRAINT group_member_badge_proofs_group_member_id_fkey FOREIGN KEY (group_member_id) REFERENCES test_chat_schema.group_members(group_member_id) ON DELETE CASCADE; + + + ALTER TABLE ONLY test_chat_schema.group_member_intros ADD CONSTRAINT group_member_intros_re_group_member_id_fkey FOREIGN KEY (re_group_member_id) REFERENCES test_chat_schema.group_members(group_member_id) ON DELETE CASCADE; diff --git a/src/Simplex/Chat/Store/SQLite/Migrations/M20260925_badge_bindings.hs b/src/Simplex/Chat/Store/SQLite/Migrations/M20260925_badge_bindings.hs index 51c42f618a..cbcf8312f3 100644 --- a/src/Simplex/Chat/Store/SQLite/Migrations/M20260925_badge_bindings.hs +++ b/src/Simplex/Chat/Store/SQLite/Migrations/M20260925_badge_bindings.hs @@ -10,35 +10,23 @@ m20260925_badge_bindings = [sql| ALTER TABLE connections ADD COLUMN pres_header BLOB; -PRAGMA writable_schema=1; - -UPDATE sqlite_master -SET sql = replace(sql, 'file_id INTEGER NOT NULL REFERENCES files', 'file_id INTEGER REFERENCES files') -WHERE name = 'file_badge_proofs' AND type = 'table'; - -PRAGMA writable_schema=RESET; - -ALTER TABLE file_badge_proofs ADD COLUMN group_member_id INTEGER REFERENCES group_members ON DELETE CASCADE; - -CREATE UNIQUE INDEX idx_file_badge_proofs_group_member_id ON file_badge_proofs(group_member_id); +CREATE TABLE group_member_badge_proofs( + group_member_id INTEGER PRIMARY KEY REFERENCES group_members ON DELETE CASCADE, + badge_proof BLOB NOT NULL, + badge_pres_header BLOB NOT NULL, + badge_key_idx INTEGER NOT NULL, + badge_type TEXT NOT NULL, + badge_expiry TEXT NOT NULL, + badge_extra TEXT NOT NULL, + created_at TEXT NOT NULL, + updated_at TEXT NOT NULL +) STRICT; |] down_m20260925_badge_bindings :: Query down_m20260925_badge_bindings = [sql| -DROP INDEX idx_file_badge_proofs_group_member_id; - -DELETE FROM file_badge_proofs WHERE group_member_id IS NOT NULL; - -ALTER TABLE file_badge_proofs DROP COLUMN group_member_id; - -PRAGMA writable_schema=1; - -UPDATE sqlite_master -SET sql = replace(sql, 'file_id INTEGER REFERENCES files', 'file_id INTEGER NOT NULL REFERENCES files') -WHERE name = 'file_badge_proofs' AND type = 'table'; - -PRAGMA writable_schema=RESET; +DROP TABLE group_member_badge_proofs; ALTER TABLE connections DROP COLUMN pres_header; |] diff --git a/src/Simplex/Chat/Store/SQLite/Migrations/chat_query_plans.txt b/src/Simplex/Chat/Store/SQLite/Migrations/chat_query_plans.txt index 33e7ed34c4..e339c7c5f2 100644 --- a/src/Simplex/Chat/Store/SQLite/Migrations/chat_query_plans.txt +++ b/src/Simplex/Chat/Store/SQLite/Migrations/chat_query_plans.txt @@ -30,7 +30,7 @@ Query: VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) Plan: -SEARCH file_badge_proofs USING COVERING INDEX idx_file_badge_proofs_group_member_id (group_member_id=?) +SEARCH group_member_badge_proofs USING INTEGER PRIMARY KEY (rowid=?) SEARCH rcv_roster_transfers USING COVERING INDEX idx_rcv_roster_transfers_from_member_id (from_member_id=?) SEARCH group_relays USING COVERING INDEX idx_group_relays_group_member_id (group_member_id=?) SEARCH delivery_jobs USING COVERING INDEX idx_delivery_jobs_job_scope_support_gm_id (job_scope_support_gm_id=?) @@ -85,7 +85,7 @@ Query: VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) Plan: -SEARCH file_badge_proofs USING COVERING INDEX idx_file_badge_proofs_group_member_id (group_member_id=?) +SEARCH group_member_badge_proofs USING INTEGER PRIMARY KEY (rowid=?) SEARCH rcv_roster_transfers USING COVERING INDEX idx_rcv_roster_transfers_from_member_id (from_member_id=?) SEARCH group_relays USING COVERING INDEX idx_group_relays_group_member_id (group_member_id=?) SEARCH delivery_jobs USING COVERING INDEX idx_delivery_jobs_job_scope_support_gm_id (job_scope_support_gm_id=?) @@ -179,7 +179,7 @@ Query: JOIN group_profiles gp USING (group_profile_id) JOIN group_members mu ON g.group_id = mu.group_id JOIN contact_profiles pu ON pu.contact_profile_id = COALESCE(mu.member_profile_id, mu.contact_profile_id) - LEFT JOIN file_badge_proofs bp ON bp.group_member_id = m.group_member_id + LEFT JOIN group_member_badge_proofs bp ON bp.group_member_id = m.group_member_id WHERE m.group_member_id = ? AND g.user_id = ? AND mu.contact_id = ? AND mu.member_status NOT IN (?,?,?) @@ -190,7 +190,7 @@ SEARCH p USING INTEGER PRIMARY KEY (rowid=?) SEARCH gp USING INTEGER PRIMARY KEY (rowid=?) SEARCH mu USING INDEX idx_group_members_contact_id (contact_id=?) SEARCH pu USING INTEGER PRIMARY KEY (rowid=?) -SEARCH bp USING INDEX idx_file_badge_proofs_group_member_id (group_member_id=?) LEFT-JOIN +SEARCH bp USING INTEGER PRIMARY KEY (rowid=?) LEFT-JOIN Query: SELECT delivery_task_id @@ -297,7 +297,7 @@ Query: VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) Plan: -SEARCH file_badge_proofs USING COVERING INDEX idx_file_badge_proofs_group_member_id (group_member_id=?) +SEARCH group_member_badge_proofs USING INTEGER PRIMARY KEY (rowid=?) SEARCH rcv_roster_transfers USING COVERING INDEX idx_rcv_roster_transfers_from_member_id (from_member_id=?) SEARCH group_relays USING COVERING INDEX idx_group_relays_group_member_id (group_member_id=?) SEARCH delivery_jobs USING COVERING INDEX idx_delivery_jobs_job_scope_support_gm_id (job_scope_support_gm_id=?) @@ -334,7 +334,7 @@ Query: VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) Plan: -SEARCH file_badge_proofs USING COVERING INDEX idx_file_badge_proofs_group_member_id (group_member_id=?) +SEARCH group_member_badge_proofs USING INTEGER PRIMARY KEY (rowid=?) SEARCH rcv_roster_transfers USING COVERING INDEX idx_rcv_roster_transfers_from_member_id (from_member_id=?) SEARCH group_relays USING COVERING INDEX idx_group_relays_group_member_id (group_member_id=?) SEARCH delivery_jobs USING COVERING INDEX idx_delivery_jobs_job_scope_support_gm_id (job_scope_support_gm_id=?) @@ -371,7 +371,7 @@ Query: VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) Plan: -SEARCH file_badge_proofs USING COVERING INDEX idx_file_badge_proofs_group_member_id (group_member_id=?) +SEARCH group_member_badge_proofs USING INTEGER PRIMARY KEY (rowid=?) SEARCH rcv_roster_transfers USING COVERING INDEX idx_rcv_roster_transfers_from_member_id (from_member_id=?) SEARCH group_relays USING COVERING INDEX idx_group_relays_group_member_id (group_member_id=?) SEARCH delivery_jobs USING COVERING INDEX idx_delivery_jobs_job_scope_support_gm_id (job_scope_support_gm_id=?) @@ -596,7 +596,7 @@ Query: VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) Plan: -SEARCH file_badge_proofs USING COVERING INDEX idx_file_badge_proofs_group_member_id (group_member_id=?) +SEARCH group_member_badge_proofs USING INTEGER PRIMARY KEY (rowid=?) SEARCH rcv_roster_transfers USING COVERING INDEX idx_rcv_roster_transfers_from_member_id (from_member_id=?) SEARCH group_relays USING COVERING INDEX idx_group_relays_group_member_id (group_member_id=?) SEARCH delivery_jobs USING COVERING INDEX idx_delivery_jobs_job_scope_support_gm_id (job_scope_support_gm_id=?) @@ -632,7 +632,7 @@ Query: VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?) Plan: -SEARCH file_badge_proofs USING COVERING INDEX idx_file_badge_proofs_group_member_id (group_member_id=?) +SEARCH group_member_badge_proofs USING INTEGER PRIMARY KEY (rowid=?) SEARCH rcv_roster_transfers USING COVERING INDEX idx_rcv_roster_transfers_from_member_id (from_member_id=?) SEARCH group_relays USING COVERING INDEX idx_group_relays_group_member_id (group_member_id=?) SEARCH delivery_jobs USING COVERING INDEX idx_delivery_jobs_job_scope_support_gm_id (job_scope_support_gm_id=?) @@ -669,7 +669,7 @@ Query: VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?) Plan: -SEARCH file_badge_proofs USING COVERING INDEX idx_file_badge_proofs_group_member_id (group_member_id=?) +SEARCH group_member_badge_proofs USING INTEGER PRIMARY KEY (rowid=?) SEARCH rcv_roster_transfers USING COVERING INDEX idx_rcv_roster_transfers_from_member_id (from_member_id=?) SEARCH group_relays USING COVERING INDEX idx_group_relays_group_member_id (group_member_id=?) SEARCH delivery_jobs USING COVERING INDEX idx_delivery_jobs_job_scope_support_gm_id (job_scope_support_gm_id=?) @@ -706,7 +706,7 @@ Query: VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) Plan: -SEARCH file_badge_proofs USING COVERING INDEX idx_file_badge_proofs_group_member_id (group_member_id=?) +SEARCH group_member_badge_proofs USING INTEGER PRIMARY KEY (rowid=?) SEARCH rcv_roster_transfers USING COVERING INDEX idx_rcv_roster_transfers_from_member_id (from_member_id=?) SEARCH group_relays USING COVERING INDEX idx_group_relays_group_member_id (group_member_id=?) SEARCH delivery_jobs USING COVERING INDEX idx_delivery_jobs_job_scope_support_gm_id (job_scope_support_gm_id=?) @@ -1270,7 +1270,7 @@ Query: VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?) Plan: -SEARCH file_badge_proofs USING COVERING INDEX idx_file_badge_proofs_group_member_id (group_member_id=?) +SEARCH group_member_badge_proofs USING INTEGER PRIMARY KEY (rowid=?) SEARCH rcv_roster_transfers USING COVERING INDEX idx_rcv_roster_transfers_from_member_id (from_member_id=?) SEARCH group_relays USING COVERING INDEX idx_group_relays_group_member_id (group_member_id=?) SEARCH delivery_jobs USING COVERING INDEX idx_delivery_jobs_job_scope_support_gm_id (job_scope_support_gm_id=?) @@ -1308,7 +1308,7 @@ Query: VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) Plan: -SEARCH file_badge_proofs USING COVERING INDEX idx_file_badge_proofs_group_member_id (group_member_id=?) +SEARCH group_member_badge_proofs USING INTEGER PRIMARY KEY (rowid=?) SEARCH rcv_roster_transfers USING COVERING INDEX idx_rcv_roster_transfers_from_member_id (from_member_id=?) SEARCH group_relays USING COVERING INDEX idx_group_relays_group_member_id (group_member_id=?) SEARCH delivery_jobs USING COVERING INDEX idx_delivery_jobs_job_scope_support_gm_id (job_scope_support_gm_id=?) @@ -1958,7 +1958,7 @@ Query: VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) Plan: -SEARCH file_badge_proofs USING COVERING INDEX idx_file_badge_proofs_group_member_id (group_member_id=?) +SEARCH group_member_badge_proofs USING INTEGER PRIMARY KEY (rowid=?) SEARCH rcv_roster_transfers USING COVERING INDEX idx_rcv_roster_transfers_from_member_id (from_member_id=?) SEARCH group_relays USING COVERING INDEX idx_group_relays_group_member_id (group_member_id=?) SEARCH delivery_jobs USING COVERING INDEX idx_delivery_jobs_job_scope_support_gm_id (job_scope_support_gm_id=?) @@ -1995,7 +1995,7 @@ Query: VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) Plan: -SEARCH file_badge_proofs USING COVERING INDEX idx_file_badge_proofs_group_member_id (group_member_id=?) +SEARCH group_member_badge_proofs USING INTEGER PRIMARY KEY (rowid=?) SEARCH rcv_roster_transfers USING COVERING INDEX idx_rcv_roster_transfers_from_member_id (from_member_id=?) SEARCH group_relays USING COVERING INDEX idx_group_relays_group_member_id (group_member_id=?) SEARCH delivery_jobs USING COVERING INDEX idx_delivery_jobs_job_scope_support_gm_id (job_scope_support_gm_id=?) @@ -5900,7 +5900,7 @@ Query: FROM group_members m JOIN contact_profiles p ON p.contact_profile_id = COALESCE(m.member_profile_id, m.contact_profile_id) LEFT JOIN connections c ON c.group_member_id = m.group_member_id - LEFT JOIN file_badge_proofs bp ON bp.group_member_id = m.group_member_id + LEFT JOIN group_member_badge_proofs bp ON bp.group_member_id = m.group_member_id WHERE m.group_id = ? AND m.user_id = ? AND (m.contact_id IS NULL OR m.contact_id != ?) AND m.member_status IN (?, ?, ?, ?) @@ -5914,7 +5914,7 @@ LIST SUBQUERY 1 SCAN chat_items USING COVERING INDEX idx_chat_items_group_member_id SEARCH p USING INTEGER PRIMARY KEY (rowid=?) SEARCH c USING INDEX idx_connections_group_member_id (group_member_id=?) LEFT-JOIN -SEARCH bp USING INDEX idx_file_badge_proofs_group_member_id (group_member_id=?) LEFT-JOIN +SEARCH bp USING INTEGER PRIMARY KEY (rowid=?) LEFT-JOIN Query: SELECT @@ -5931,14 +5931,14 @@ Query: FROM group_members m JOIN contact_profiles p ON p.contact_profile_id = COALESCE(m.member_profile_id, m.contact_profile_id) LEFT JOIN connections c ON c.group_member_id = m.group_member_id - LEFT JOIN file_badge_proofs bp ON bp.group_member_id = m.group_member_id + LEFT JOIN group_member_badge_proofs bp ON bp.group_member_id = m.group_member_id JOIN group_member_status_predicates sp ON m.member_status = sp.member_status WHERE m.group_id = ? AND m.relay_link = ? AND sp.current_member = 1 Plan: SEARCH m USING INDEX idx_group_members_group_id_index_in_group (group_id=?) SEARCH sp USING INDEX sqlite_autoindex_group_member_status_predicates_1 (member_status=?) SEARCH p USING INTEGER PRIMARY KEY (rowid=?) SEARCH c USING INDEX idx_connections_group_member_id (group_member_id=?) LEFT-JOIN -SEARCH bp USING INDEX idx_file_badge_proofs_group_member_id (group_member_id=?) LEFT-JOIN +SEARCH bp USING INTEGER PRIMARY KEY (rowid=?) LEFT-JOIN Query: SELECT @@ -5955,13 +5955,13 @@ Query: FROM group_members m JOIN contact_profiles p ON p.contact_profile_id = COALESCE(m.member_profile_id, m.contact_profile_id) LEFT JOIN connections c ON c.group_member_id = m.group_member_id - LEFT JOIN file_badge_proofs bp ON bp.group_member_id = m.group_member_id + LEFT JOIN group_member_badge_proofs bp ON bp.group_member_id = m.group_member_id WHERE m.group_id = ? AND m.group_member_id = ? AND m.user_id = ? Plan: SEARCH m USING INTEGER PRIMARY KEY (rowid=?) SEARCH p USING INTEGER PRIMARY KEY (rowid=?) SEARCH c USING INDEX idx_connections_group_member_id (group_member_id=?) LEFT-JOIN -SEARCH bp USING INDEX idx_file_badge_proofs_group_member_id (group_member_id=?) LEFT-JOIN +SEARCH bp USING INTEGER PRIMARY KEY (rowid=?) LEFT-JOIN Query: SELECT @@ -5978,13 +5978,13 @@ Query: FROM group_members m JOIN contact_profiles p ON p.contact_profile_id = COALESCE(m.member_profile_id, m.contact_profile_id) LEFT JOIN connections c ON c.group_member_id = m.group_member_id - LEFT JOIN file_badge_proofs bp ON bp.group_member_id = m.group_member_id + LEFT JOIN group_member_badge_proofs bp ON bp.group_member_id = m.group_member_id WHERE m.group_id = ? AND m.index_in_group = ? Plan: SEARCH m USING INDEX idx_group_members_group_id_index_in_group (group_id=? AND index_in_group=?) SEARCH p USING INTEGER PRIMARY KEY (rowid=?) SEARCH c USING INDEX idx_connections_group_member_id (group_member_id=?) LEFT-JOIN -SEARCH bp USING INDEX idx_file_badge_proofs_group_member_id (group_member_id=?) LEFT-JOIN +SEARCH bp USING INTEGER PRIMARY KEY (rowid=?) LEFT-JOIN Query: SELECT @@ -6001,13 +6001,13 @@ Query: FROM group_members m JOIN contact_profiles p ON p.contact_profile_id = COALESCE(m.member_profile_id, m.contact_profile_id) LEFT JOIN connections c ON c.group_member_id = m.group_member_id - LEFT JOIN file_badge_proofs bp ON bp.group_member_id = m.group_member_id + LEFT JOIN group_member_badge_proofs bp ON bp.group_member_id = m.group_member_id WHERE m.group_id = ? AND m.index_in_group = ? AND (m.member_role IN (?,?,?) OR m.group_member_id = ?) Plan: SEARCH m USING INDEX idx_group_members_group_id_index_in_group (group_id=? AND index_in_group=?) SEARCH p USING INTEGER PRIMARY KEY (rowid=?) SEARCH c USING INDEX idx_connections_group_member_id (group_member_id=?) LEFT-JOIN -SEARCH bp USING INDEX idx_file_badge_proofs_group_member_id (group_member_id=?) LEFT-JOIN +SEARCH bp USING INTEGER PRIMARY KEY (rowid=?) LEFT-JOIN Query: SELECT @@ -6024,13 +6024,13 @@ Query: FROM group_members m JOIN contact_profiles p ON p.contact_profile_id = COALESCE(m.member_profile_id, m.contact_profile_id) LEFT JOIN connections c ON c.group_member_id = m.group_member_id - LEFT JOIN file_badge_proofs bp ON bp.group_member_id = m.group_member_id + LEFT JOIN group_member_badge_proofs bp ON bp.group_member_id = m.group_member_id WHERE m.group_id = ? AND m.member_category = ? Plan: SEARCH m USING INDEX idx_group_members_group_id_index_in_group (group_id=?) SEARCH p USING INTEGER PRIMARY KEY (rowid=?) SEARCH c USING INDEX idx_connections_group_member_id (group_member_id=?) LEFT-JOIN -SEARCH bp USING INDEX idx_file_badge_proofs_group_member_id (group_member_id=?) LEFT-JOIN +SEARCH bp USING INTEGER PRIMARY KEY (rowid=?) LEFT-JOIN Query: SELECT @@ -6047,13 +6047,13 @@ Query: FROM group_members m JOIN contact_profiles p ON p.contact_profile_id = COALESCE(m.member_profile_id, m.contact_profile_id) LEFT JOIN connections c ON c.group_member_id = m.group_member_id - LEFT JOIN file_badge_proofs bp ON bp.group_member_id = m.group_member_id + LEFT JOIN group_member_badge_proofs bp ON bp.group_member_id = m.group_member_id WHERE m.group_id = ? AND m.member_id = ? Plan: SEARCH m USING INDEX sqlite_autoindex_group_members_1 (group_id=? AND member_id=?) SEARCH p USING INTEGER PRIMARY KEY (rowid=?) SEARCH c USING INDEX idx_connections_group_member_id (group_member_id=?) LEFT-JOIN -SEARCH bp USING INDEX idx_file_badge_proofs_group_member_id (group_member_id=?) LEFT-JOIN +SEARCH bp USING INTEGER PRIMARY KEY (rowid=?) LEFT-JOIN Query: SELECT @@ -6070,13 +6070,13 @@ Query: FROM group_members m JOIN contact_profiles p ON p.contact_profile_id = COALESCE(m.member_profile_id, m.contact_profile_id) LEFT JOIN connections c ON c.group_member_id = m.group_member_id - LEFT JOIN file_badge_proofs bp ON bp.group_member_id = m.group_member_id + LEFT JOIN group_member_badge_proofs bp ON bp.group_member_id = m.group_member_id WHERE m.group_member_id = ? AND m.user_id = ? Plan: SEARCH m USING INTEGER PRIMARY KEY (rowid=?) SEARCH p USING INTEGER PRIMARY KEY (rowid=?) SEARCH c USING INDEX idx_connections_group_member_id (group_member_id=?) LEFT-JOIN -SEARCH bp USING INDEX idx_file_badge_proofs_group_member_id (group_member_id=?) LEFT-JOIN +SEARCH bp USING INTEGER PRIMARY KEY (rowid=?) LEFT-JOIN Query: SELECT @@ -6093,13 +6093,13 @@ Query: FROM group_members m JOIN contact_profiles p ON p.contact_profile_id = COALESCE(m.member_profile_id, m.contact_profile_id) LEFT JOIN connections c ON c.group_member_id = m.group_member_id - LEFT JOIN file_badge_proofs bp ON bp.group_member_id = m.group_member_id + LEFT JOIN group_member_badge_proofs bp ON bp.group_member_id = m.group_member_id WHERE m.group_member_id = ? AND m.user_id = ? AND m.member_status NOT IN (?,?,?,?) Plan: SEARCH m USING INTEGER PRIMARY KEY (rowid=?) SEARCH p USING INTEGER PRIMARY KEY (rowid=?) SEARCH c USING INDEX idx_connections_group_member_id (group_member_id=?) LEFT-JOIN -SEARCH bp USING INDEX idx_file_badge_proofs_group_member_id (group_member_id=?) LEFT-JOIN +SEARCH bp USING INTEGER PRIMARY KEY (rowid=?) LEFT-JOIN Query: SELECT @@ -6116,13 +6116,13 @@ Query: FROM group_members m JOIN contact_profiles p ON p.contact_profile_id = COALESCE(m.member_profile_id, m.contact_profile_id) LEFT JOIN connections c ON c.group_member_id = m.group_member_id - LEFT JOIN file_badge_proofs bp ON bp.group_member_id = m.group_member_id + LEFT JOIN group_member_badge_proofs bp ON bp.group_member_id = m.group_member_id WHERE m.user_id = ? AND m.group_id = ? AND (m.contact_id IS NULL OR m.contact_id != ?) Plan: SEARCH m USING INDEX idx_group_members_group_id (user_id=? AND group_id=?) SEARCH p USING INTEGER PRIMARY KEY (rowid=?) SEARCH c USING INDEX idx_connections_group_member_id (group_member_id=?) LEFT-JOIN -SEARCH bp USING INDEX idx_file_badge_proofs_group_member_id (group_member_id=?) LEFT-JOIN +SEARCH bp USING INTEGER PRIMARY KEY (rowid=?) LEFT-JOIN Query: SELECT @@ -6139,13 +6139,13 @@ Query: FROM group_members m JOIN contact_profiles p ON p.contact_profile_id = COALESCE(m.member_profile_id, m.contact_profile_id) LEFT JOIN connections c ON c.group_member_id = m.group_member_id - LEFT JOIN file_badge_proofs bp ON bp.group_member_id = m.group_member_id + LEFT JOIN group_member_badge_proofs bp ON bp.group_member_id = m.group_member_id WHERE m.user_id = ? AND m.group_id = ? AND (m.contact_id IS NULL OR m.contact_id != ?) AND m.member_role = ? Plan: SEARCH m USING INDEX idx_group_members_group_id (user_id=? AND group_id=?) SEARCH p USING INTEGER PRIMARY KEY (rowid=?) SEARCH c USING INDEX idx_connections_group_member_id (group_member_id=?) LEFT-JOIN -SEARCH bp USING INDEX idx_file_badge_proofs_group_member_id (group_member_id=?) LEFT-JOIN +SEARCH bp USING INTEGER PRIMARY KEY (rowid=?) LEFT-JOIN Query: SELECT @@ -6162,13 +6162,13 @@ Query: FROM group_members m JOIN contact_profiles p ON p.contact_profile_id = COALESCE(m.member_profile_id, m.contact_profile_id) LEFT JOIN connections c ON c.group_member_id = m.group_member_id - LEFT JOIN file_badge_proofs bp ON bp.group_member_id = m.group_member_id + LEFT JOIN group_member_badge_proofs bp ON bp.group_member_id = m.group_member_id WHERE m.user_id = ? AND m.group_id = ? AND (m.contact_id IS NULL OR m.contact_id != ?) AND m.member_role IN (?,?) Plan: SEARCH m USING INDEX idx_group_members_group_id (user_id=? AND group_id=?) SEARCH p USING INTEGER PRIMARY KEY (rowid=?) SEARCH c USING INDEX idx_connections_group_member_id (group_member_id=?) LEFT-JOIN -SEARCH bp USING INDEX idx_file_badge_proofs_group_member_id (group_member_id=?) LEFT-JOIN +SEARCH bp USING INTEGER PRIMARY KEY (rowid=?) LEFT-JOIN Query: SELECT @@ -6185,13 +6185,13 @@ Query: FROM group_members m JOIN contact_profiles p ON p.contact_profile_id = COALESCE(m.member_profile_id, m.contact_profile_id) LEFT JOIN connections c ON c.group_member_id = m.group_member_id - LEFT JOIN file_badge_proofs bp ON bp.group_member_id = m.group_member_id + LEFT JOIN group_member_badge_proofs bp ON bp.group_member_id = m.group_member_id WHERE m.user_id = ? AND m.group_id = ? AND (m.contact_id IS NULL OR m.contact_id != ?) AND m.member_role IN (?,?,?) Plan: SEARCH m USING INDEX idx_group_members_group_id (user_id=? AND group_id=?) SEARCH p USING INTEGER PRIMARY KEY (rowid=?) SEARCH c USING INDEX idx_connections_group_member_id (group_member_id=?) LEFT-JOIN -SEARCH bp USING INDEX idx_file_badge_proofs_group_member_id (group_member_id=?) LEFT-JOIN +SEARCH bp USING INTEGER PRIMARY KEY (rowid=?) LEFT-JOIN Query: SELECT @@ -6208,13 +6208,13 @@ Query: FROM group_members m JOIN contact_profiles p ON p.contact_profile_id = COALESCE(m.member_profile_id, m.contact_profile_id) LEFT JOIN connections c ON c.group_member_id = m.group_member_id - LEFT JOIN file_badge_proofs bp ON bp.group_member_id = m.group_member_id + LEFT JOIN group_member_badge_proofs bp ON bp.group_member_id = m.group_member_id WHERE m.user_id = ? AND m.group_id = ? AND m.contact_id IS DISTINCT FROM ? AND m.member_role = ? Plan: SEARCH m USING INDEX idx_group_members_group_id (user_id=? AND group_id=?) SEARCH p USING INTEGER PRIMARY KEY (rowid=?) SEARCH c USING INDEX idx_connections_group_member_id (group_member_id=?) LEFT-JOIN -SEARCH bp USING INDEX idx_file_badge_proofs_group_member_id (group_member_id=?) LEFT-JOIN +SEARCH bp USING INTEGER PRIMARY KEY (rowid=?) LEFT-JOIN Query: SELECT @@ -6231,13 +6231,13 @@ Query: FROM group_members m JOIN contact_profiles p ON p.contact_profile_id = COALESCE(m.member_profile_id, m.contact_profile_id) LEFT JOIN connections c ON c.group_member_id = m.group_member_id - LEFT JOIN file_badge_proofs bp ON bp.group_member_id = m.group_member_id + LEFT JOIN group_member_badge_proofs bp ON bp.group_member_id = m.group_member_id WHERE m.user_id = ? AND m.removed_at < ? Plan: SEARCH m USING INDEX idx_group_members_user_id (user_id=?) SEARCH p USING INTEGER PRIMARY KEY (rowid=?) SEARCH c USING INDEX idx_connections_group_member_id (group_member_id=?) LEFT-JOIN -SEARCH bp USING INDEX idx_file_badge_proofs_group_member_id (group_member_id=?) LEFT-JOIN +SEARCH bp USING INTEGER PRIMARY KEY (rowid=?) LEFT-JOIN Query: SELECT f.file_id, f.ci_file_status, f.file_path @@ -6924,10 +6924,6 @@ SEARCH groups USING COVERING INDEX sqlite_autoindex_groups_1 (user_id=? AND loca SEARCH contacts USING COVERING INDEX sqlite_autoindex_contacts_1 (user_id=? AND local_display_name=?) SEARCH users USING INTEGER PRIMARY KEY (rowid=?) -Query: DELETE FROM file_badge_proofs WHERE group_member_id = ? -Plan: -SEARCH file_badge_proofs USING INDEX idx_file_badge_proofs_group_member_id (group_member_id=?) - Query: DELETE FROM files WHERE roster_transfer_id = ? Plan: SEARCH files USING COVERING INDEX idx_files_roster_transfer_id (roster_transfer_id=?) @@ -6955,10 +6951,14 @@ SEARCH rcv_files USING INTEGER PRIMARY KEY (rowid=?) SEARCH snd_files USING COVERING INDEX idx_snd_files_file_id (file_id=?) SEARCH files USING COVERING INDEX idx_files_redirect_file_id (redirect_file_id=?) +Query: DELETE FROM group_member_badge_proofs WHERE group_member_id = ? +Plan: +SEARCH group_member_badge_proofs USING INTEGER PRIMARY KEY (rowid=?) + Query: DELETE FROM group_members WHERE member_id = ? Plan: SCAN group_members -SEARCH file_badge_proofs USING COVERING INDEX idx_file_badge_proofs_group_member_id (group_member_id=?) +SEARCH group_member_badge_proofs USING INTEGER PRIMARY KEY (rowid=?) SEARCH rcv_roster_transfers USING COVERING INDEX idx_rcv_roster_transfers_from_member_id (from_member_id=?) SEARCH group_relays USING COVERING INDEX idx_group_relays_group_member_id (group_member_id=?) SEARCH delivery_jobs USING COVERING INDEX idx_delivery_jobs_job_scope_support_gm_id (job_scope_support_gm_id=?) @@ -6990,7 +6990,7 @@ SEARCH contacts USING COVERING INDEX idx_contacts_contact_group_member_id (conta Query: DELETE FROM group_members WHERE user_id = ? AND group_id = ? Plan: SEARCH group_members USING COVERING INDEX idx_group_members_group_id (user_id=? AND group_id=?) -SEARCH file_badge_proofs USING COVERING INDEX idx_file_badge_proofs_group_member_id (group_member_id=?) +SEARCH group_member_badge_proofs USING INTEGER PRIMARY KEY (rowid=?) SEARCH rcv_roster_transfers USING COVERING INDEX idx_rcv_roster_transfers_from_member_id (from_member_id=?) SEARCH group_relays USING COVERING INDEX idx_group_relays_group_member_id (group_member_id=?) SEARCH delivery_jobs USING COVERING INDEX idx_delivery_jobs_job_scope_support_gm_id (job_scope_support_gm_id=?) @@ -7022,7 +7022,7 @@ SEARCH contacts USING COVERING INDEX idx_contacts_contact_group_member_id (conta Query: DELETE FROM group_members WHERE user_id = ? AND group_member_id = ? Plan: SEARCH group_members USING INTEGER PRIMARY KEY (rowid=?) -SEARCH file_badge_proofs USING COVERING INDEX idx_file_badge_proofs_group_member_id (group_member_id=?) +SEARCH group_member_badge_proofs USING INTEGER PRIMARY KEY (rowid=?) SEARCH rcv_roster_transfers USING COVERING INDEX idx_rcv_roster_transfers_from_member_id (from_member_id=?) SEARCH group_relays USING COVERING INDEX idx_group_relays_group_member_id (group_member_id=?) SEARCH delivery_jobs USING COVERING INDEX idx_delivery_jobs_job_scope_support_gm_id (job_scope_support_gm_id=?) @@ -7260,9 +7260,6 @@ SEARCH users USING INTEGER PRIMARY KEY (rowid=?) Query: INSERT INTO extra_xftp_file_descriptions (file_id, user_id, file_descr_text, created_at, updated_at) VALUES (?,?,?,?,?) Plan: -Query: INSERT INTO file_badge_proofs (group_member_id, proof_kind, badge_proof, badge_pres_header, badge_key_idx, badge_type, badge_expiry, badge_extra, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?,?) -Plan: - Query: INSERT INTO files (contact_id, group_id, user_id, file_name, file_path, file_crypto_key, file_crypto_nonce, file_size, chunk_size, redirect_file_id, agent_snd_file_id, ci_file_status, protocol, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) Plan: @@ -7278,6 +7275,9 @@ Plan: Query: INSERT INTO files (user_id, group_id, file_name, file_size, chunk_size, file_inline, ci_file_status, protocol, file_type, shared_msg_id, roster_transfer_id, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?) Plan: +Query: INSERT INTO group_member_badge_proofs (group_member_id, badge_proof, badge_pres_header, badge_key_idx, badge_type, badge_expiry, badge_extra, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?) +Plan: + Query: INSERT INTO group_profiles (display_name, full_name, short_descr, description, image, user_id, member_admission, created_at, updated_at, preferences, preferences_json) VALUES (?,?,?,?,?,?,?,?,?,?,?) Plan: @@ -7663,10 +7663,6 @@ Query: SELECT issue_failed_since, issue_error FROM badge_purchases Plan: SCAN badge_purchases -Query: SELECT item_content FROM chat_items ORDER BY chat_item_id DESC LIMIT 1 -Plan: -SCAN chat_items - Query: SELECT last_insert_rowid() Plan: SCAN CONSTANT ROW @@ -8083,6 +8079,10 @@ Query: UPDATE group_members SET member_profile_id = ?, updated_at = ? WHERE grou Plan: SEARCH group_members USING INTEGER PRIMARY KEY (rowid=?) +Query: UPDATE group_members SET member_pub_key = ? WHERE member_category = 'user' +Plan: +SCAN group_members + Query: UPDATE group_members SET member_pub_key = ?, member_role = ?, updated_at = ? WHERE group_member_id = ? Plan: SEARCH group_members USING INTEGER PRIMARY KEY (rowid=?) diff --git a/src/Simplex/Chat/Store/SQLite/Migrations/chat_schema.sql b/src/Simplex/Chat/Store/SQLite/Migrations/chat_schema.sql index 63659a129d..bf471bc6f2 100644 --- a/src/Simplex/Chat/Store/SQLite/Migrations/chat_schema.sql +++ b/src/Simplex/Chat/Store/SQLite/Migrations/chat_schema.sql @@ -860,7 +860,7 @@ CREATE TABLE rcv_roster_transfers( ) STRICT; CREATE TABLE file_badge_proofs( badge_proof_id INTEGER PRIMARY KEY AUTOINCREMENT, - file_id INTEGER REFERENCES files ON DELETE CASCADE, + file_id INTEGER NOT NULL REFERENCES files ON DELETE CASCADE, proof_kind TEXT NOT NULL, badge_proof BLOB NOT NULL, badge_pres_header BLOB NOT NULL, @@ -870,8 +870,6 @@ CREATE TABLE file_badge_proofs( badge_extra TEXT NOT NULL, created_at TEXT NOT NULL, updated_at TEXT NOT NULL - , - group_member_id INTEGER REFERENCES group_members ON DELETE CASCADE ) STRICT; CREATE TABLE invoices( invoice_id TEXT NOT NULL PRIMARY KEY, @@ -984,6 +982,17 @@ CREATE TABLE badge_code_redemptions( created_at TEXT NOT NULL, UNIQUE(user_id, code) ) STRICT; +CREATE TABLE group_member_badge_proofs( + group_member_id INTEGER PRIMARY KEY REFERENCES group_members ON DELETE CASCADE, + badge_proof BLOB NOT NULL, + badge_pres_header BLOB NOT NULL, + badge_key_idx INTEGER NOT NULL, + badge_type TEXT NOT NULL, + badge_expiry TEXT NOT NULL, + badge_extra TEXT NOT NULL, + created_at TEXT NOT NULL, + updated_at TEXT NOT NULL +) STRICT; CREATE INDEX contact_profiles_index ON contact_profiles( display_name, full_name @@ -1547,9 +1556,6 @@ CREATE INDEX idx_badge_code_redemptions_user ON badge_code_redemptions( CREATE UNIQUE INDEX idx_badge_purchases_code_redemption ON badge_purchases( badge_code_redemption_id ); -CREATE UNIQUE INDEX idx_file_badge_proofs_group_member_id ON file_badge_proofs( - group_member_id -); CREATE TRIGGER on_group_members_insert_update_summary AFTER INSERT ON group_members FOR EACH ROW diff --git a/src/Simplex/Chat/Store/Shared.hs b/src/Simplex/Chat/Store/Shared.hs index a952d20670..cc3de11787 100644 --- a/src/Simplex/Chat/Store/Shared.hs +++ b/src/Simplex/Chat/Store/Shared.hs @@ -816,7 +816,7 @@ groupMemberQuery = FROM group_members m JOIN contact_profiles p ON p.contact_profile_id = COALESCE(m.member_profile_id, m.contact_profile_id) LEFT JOIN connections c ON c.group_member_id = m.group_member_id - LEFT JOIN file_badge_proofs bp ON bp.group_member_id = m.group_member_id + LEFT JOIN group_member_badge_proofs bp ON bp.group_member_id = m.group_member_id |] toContactMember :: UTCTime -> StoreCxt -> User -> (GroupMemberRow :. MaybeConnectionRow :. MaybeBadgeProofRow) -> GroupMember