diff --git a/HellionChat/MessageStore.cs b/HellionChat/MessageStore.cs index c52fd60..f3acb4a 100644 --- a/HellionChat/MessageStore.cs +++ b/HellionChat/MessageStore.cs @@ -690,7 +690,12 @@ internal class MessageStore : IDisposable { ct.ThrowIfCancellationRequested(); - var guidBytes = (byte[])reader.GetValue(0); + // messages.Id is BLOB-typed in the schema but stored as TEXT + // because Microsoft.Data.Sqlite binds Guid parameters as UUID + // strings by default (UpsertMessage uses AddWithValue("$Id", + // message.Id)). reader.GetValue(0) therefore returns string, + // not byte[]; GetGuid parses the TEXT form regardless. + var idGuid = reader.GetGuid(0); var senderChunks = MessagePackSerializer.Deserialize>( reader.GetFieldValue(1), MsgPackOptions @@ -700,7 +705,7 @@ internal class MessageStore : IDisposable MsgPackOptions ); - pG.Value = Convert.ToHexString(guidBytes); + pG.Value = idGuid.ToString(); pS.Value = ChunkUtil.ToRawString(senderChunks); pC.Value = ChunkUtil.ToRawString(contentChunks); insert.ExecuteNonQuery(); @@ -760,24 +765,27 @@ internal class MessageStore : IDisposable } } - // Joins hex-encoded GUIDs from FullTextSearch back to Message rows. The - // primary key is BLOB, so we decode the hex back to bytes for the IN(...) - // lookup. SQLite has a hard parameter limit of 999 in default builds, so - // we chunk the input -- a 1000-hit FTS query never explodes the SELECT. - // Result ordering is not guaranteed; callers re-sort (e.g. DbViewer sorts - // by Date descending in Sub-Task 4.4). - public IReadOnlyList LoadByGuids(IReadOnlyList hexIds) + // Joins UUID strings from FullTextSearch back to Message rows. messages.Id + // is BLOB-declared in the schema but actually stored as TEXT (UUID form) + // because Microsoft.Data.Sqlite serialises Guid parameters as strings by + // default. Binding the lookup parameters as Guid keeps the same TEXT + // storage form on both sides so the IN(...) compare matches. SQLite has a + // hard parameter limit of 999 in default builds, so we chunk the input -- + // a 1000-hit FTS query never explodes the SELECT. Result ordering is not + // guaranteed; callers re-sort (e.g. DbViewer sorts by Date descending in + // Sub-Task 4.4). + public IReadOnlyList LoadByGuids(IReadOnlyList guidStrings) { - if (hexIds.Count == 0) + if (guidStrings.Count == 0) return Array.Empty(); lock (_readLock) { - var result = new List(hexIds.Count); + var result = new List(guidStrings.Count); const int chunkSize = 500; - for (var offset = 0; offset < hexIds.Count; offset += chunkSize) + for (var offset = 0; offset < guidStrings.Count; offset += chunkSize) { - var batch = hexIds.Skip(offset).Take(chunkSize).ToList(); + var batch = guidStrings.Skip(offset).Take(chunkSize).ToList(); using var cmd = Connection.CreateCommand(); var placeholders = string.Join(",", batch.Select((_, i) => $"$id{i}")); cmd.CommandText = $""" @@ -787,7 +795,7 @@ internal class MessageStore : IDisposable WHERE Id IN ({placeholders}) AND Deleted = false; """; for (var i = 0; i < batch.Count; i++) - cmd.Parameters.AddWithValue($"$id{i}", Convert.FromHexString(batch[i])); + cmd.Parameters.AddWithValue($"$id{i}", Guid.Parse(batch[i])); using var reader = cmd.ExecuteReader(); while (reader.Read()) diff --git a/HellionChat/Ui/DbViewer.cs b/HellionChat/Ui/DbViewer.cs index 6773fba..66eecb7 100644 --- a/HellionChat/Ui/DbViewer.cs +++ b/HellionChat/Ui/DbViewer.cs @@ -485,8 +485,8 @@ public class DbViewer : Window // still serves the page. if (UseFullTextSearch && Plugin.MessageManager.Store.IsFtsIndexBuilt) { - var hexIds = Plugin.MessageManager.Store.FullTextSearch(SimpleSearchTerm); - var resolved = Plugin.MessageManager.Store.LoadByGuids(hexIds); + var guidHits = Plugin.MessageManager.Store.FullTextSearch(SimpleSearchTerm); + var resolved = Plugin.MessageManager.Store.LoadByGuids(guidHits); return new ConcurrentStack(resolved.OrderByDescending(m => m.Date)); }