From 89b40fb6fe7e00aea7e3790186d8603a5960fae0 Mon Sep 17 00:00:00 2001 From: Leander Beernaert Date: Fri, 29 Dec 2023 10:07:30 +0100 Subject: [PATCH] fix(GODT-3183): Fix mailbox flags tables Ensure combined primary keys start with the mailbox id then the flag value and correct the data type to integer. --- internal/db_impl/sqlite3/v3/migration.go | 129 +++++++++++++++++++++++ 1 file changed, 129 insertions(+) diff --git a/internal/db_impl/sqlite3/v3/migration.go b/internal/db_impl/sqlite3/v3/migration.go index af35f845..24f7c947 100644 --- a/internal/db_impl/sqlite3/v3/migration.go +++ b/internal/db_impl/sqlite3/v3/migration.go @@ -11,7 +11,100 @@ import ( type Migration struct{} +const MailboxFlagsTableNameTmp = "tmp_mailbox_flags" + +const MailboxPermFlagsTableNameTmp = "tmp_mailbox_perm_flags" + +const MailboxAttrsTableNameTmp = "tmp_mailbox_attr" + func (m Migration) Run(ctx context.Context, tx utils.QueryWrapper, _ imap.UIDValidityGenerator) error { + // Create mailboxes flags table. + { + query := fmt.Sprintf("CREATE TABLE `%[1]v` (`%[3]v` integer NOT NULL, `%[2]v` text NOT NULL, "+ + "CONSTRAINT `mailbox_flags_mailbox_id` FOREIGN KEY (`%[3]v`) REFERENCES `%[4]v` (`%[5]v`) ON DELETE CASCADE, "+ + "PRIMARY KEY (%[2]v, %[3]v)"+ + ")", + MailboxFlagsTableNameTmp, + v1.MailboxFlagsFieldValue, + v1.MailboxFlagsFieldMailboxID, + v1.MailboxesTableName, + v1.MailboxesFieldID, + ) + + if _, err := utils.ExecQuery(ctx, tx, query); err != nil { + return fmt.Errorf("failed to create mailboxes flags table: %w", err) + } + + if err := migrateMailboxFlags( + ctx, + tx, + v1.MailboxFlagsTableName, + MailboxFlagsTableNameTmp, + v1.MailboxFlagsFieldMailboxID, + v1.MailboxFlagsFieldValue, + ); err != nil { + return fmt.Errorf("failed to migrate mailbox flags table: %w", err) + } + } + + // Create perm mailboxes flags table. + { + query := fmt.Sprintf("CREATE TABLE `%[1]v` (`%[3]v` integer NOT NULL, `%[2]v` text NOT NULL, "+ + "CONSTRAINT `perm_mailbox_flags_mailbox_id` FOREIGN KEY (`%[3]v`) REFERENCES `%[4]v` (`%[5]v`) ON DELETE CASCADE, "+ + "PRIMARY KEY (%[2]v, %[3]v)"+ + ")", + MailboxPermFlagsTableNameTmp, + v1.MailboxPermFlagsFieldValue, + v1.MailboxPermFlagsFieldMailboxID, + v1.MailboxesTableName, + v1.MailboxesFieldID, + ) + + if _, err := utils.ExecQuery(ctx, tx, query); err != nil { + return fmt.Errorf("failed to create mailboxes perm flags table: %w", err) + } + + if err := migrateMailboxFlags( + ctx, + tx, + v1.MailboxPermFlagsTableName, + MailboxPermFlagsTableNameTmp, + v1.MailboxPermFlagsFieldMailboxID, + v1.MailboxPermFlagsFieldValue, + ); err != nil { + return fmt.Errorf("failed to migrate mailbox perm flags table: %w", err) + } + } + + // Create Mailbox Attributes table. + { + query := fmt.Sprintf("CREATE TABLE `%[1]v` (`%[3]v` integer NOT NULL, `%[2]v` text NOT NULL, "+ + "CONSTRAINT `perm_attrs_flags_mailbox_id` FOREIGN KEY (`%[3]v`) REFERENCES `%[4]v` (`%[5]v`) ON DELETE CASCADE, "+ + "PRIMARY KEY (%[2]v, %[3]v)"+ + ")", + MailboxAttrsTableNameTmp, + v1.MailboxAttrsFieldValue, + v1.MailboxAttrsFieldMailboxID, + v1.MailboxesTableName, + v1.MailboxesFieldID, + ) + + if _, err := utils.ExecQuery(ctx, tx, query); err != nil { + return fmt.Errorf("failed to create mailboxes attr table: %w", err) + } + + if err := migrateMailboxFlags( + ctx, + tx, + v1.MailboxAttrsTableName, + MailboxAttrsTableNameTmp, + v1.MailboxAttrsFieldMailboxID, + v1.MailboxAttrsFieldValue, + ); err != nil { + return fmt.Errorf("failed to migrate mailbox perm flags table: %w", err) + } + } + { // Create an index on message id field to speed up lookup queries for message flags. query := fmt.Sprintf("create index message_flags_message_id_index on %v (%v)", @@ -62,3 +155,39 @@ func (m Migration) Run(ctx context.Context, tx utils.QueryWrapper, _ imap.UIDVal return nil } + +func migrateMailboxFlags(ctx context.Context, + tx utils.QueryWrapper, + fromTableName string, + toTableName string, + fieldID string, + fieldValue string, +) error { + query := fmt.Sprintf("INSERT INTO %v (`%v`, `%v`) SELECT `%v`,`%v` FROM %v ORDER BY `%v`", + toTableName, + fieldID, + fieldValue, + fieldID, + fieldValue, + fromTableName, + fieldID, + ) + + if _, err := utils.ExecQuery(ctx, tx, query); err != nil { + return err + } + + dropQuery := fmt.Sprintf("DROP TABLE %v", fromTableName) + + if _, err := utils.ExecQuery(ctx, tx, dropQuery); err != nil { + return err + } + + renameQuery := fmt.Sprintf("ALTER TABLE %v RENAME TO %v", toTableName, fromTableName) + + if _, err := utils.ExecQuery(ctx, tx, renameQuery); err != nil { + return err + } + + return nil +}