From 780170e67bfe4a56e46b94f7d1f186b6b0d165ff Mon Sep 17 00:00:00 2001 From: Jesse Hallam Date: Fri, 3 Jul 2026 00:29:25 -0300 Subject: [PATCH] MM-69340: fix NULL Type scan error in Draft.Get() (#37337) * MM-69340: fix NULL Type scan error in Draft.Get() draftSliceColumns() returned "Type" bare; rows created before the v11.3 migration have Type = NULL, causing a scan error when the single- row Get() path tried to read them into a non-nullable Go string. Apply the same COALESCE(Type, '') fix that already existed in GetDraftsForUser(), and add a regression test that inserts a NULL-Type row and asserts Get() succeeds with Type == "". * fix: apply COALESCE only in Get(), not in Upsert columns draftSliceColumns() is used by Upsert's INSERT column list, where COALESCE is not valid syntax. Add draftSelectColumns() which swaps in COALESCE(Type, '') AS Type for the SELECT path only. --- server/channels/store/sqlstore/draft_store.go | 9 ++++++++- server/channels/store/storetest/draft_store.go | 12 ++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/server/channels/store/sqlstore/draft_store.go b/server/channels/store/sqlstore/draft_store.go index 58a502fe0b3..56bb7dcad06 100644 --- a/server/channels/store/sqlstore/draft_store.go +++ b/server/channels/store/sqlstore/draft_store.go @@ -39,6 +39,13 @@ func draftSliceColumns() []string { } } +func draftSelectColumns() []string { + cols := make([]string, len(draftSliceColumns())) + copy(cols, draftSliceColumns()) + cols[len(cols)-1] = "COALESCE(Type, '') AS Type" + return cols +} + func draftToSlice(draft *model.Draft) []any { return []any{ draft.CreateAt, @@ -65,7 +72,7 @@ func newSqlDraftStore(sqlStore *SqlStore, metrics einterfaces.MetricsInterface) func (s *SqlDraftStore) Get(userId, channelId, rootId string, includeDeleted bool) (*model.Draft, error) { query := s.getQueryBuilder(). - Select(draftSliceColumns()...). + Select(draftSelectColumns()...). From("Drafts"). Where(sq.Eq{ "UserId": userId, diff --git a/server/channels/store/storetest/draft_store.go b/server/channels/store/storetest/draft_store.go index 9e0cb73e4b7..de5bb2f8b11 100644 --- a/server/channels/store/storetest/draft_store.go +++ b/server/channels/store/storetest/draft_store.go @@ -362,6 +362,18 @@ func testGetDraft(t *testing.T, rctx request.CTX, ss store.Store) { assert.Equal(t, draft2.Message, draftResp.Message) assert.Equal(t, draft2.ChannelId, draftResp.ChannelId) }) + + t.Run("get draft with NULL type", func(t *testing.T) { + _, err := ss.GetInternalMasterDB().Exec( + "UPDATE Drafts SET Type = NULL WHERE UserId = $1 AND ChannelId = $2", + user.Id, channel.Id, + ) + require.NoError(t, err) + + draftResp, err := ss.Draft().Get(user.Id, channel.Id, "", false) + require.NoError(t, err) + assert.Equal(t, "", draftResp.Type) + }) } func testGetDraftsForUser(t *testing.T, rctx request.CTX, ss store.Store) {