Backfill missing errorType property for OWSRecoverableDecryptionPlaceholder(s)
This commit is contained in:
parent
d12641a3a2
commit
cad4022e68
@ -333,6 +333,7 @@ public class GRDBSchemaMigrator {
|
||||
case addMimeTypeToMessageAttachmentReference
|
||||
case purgeMyStoryDeletedAtTimestamp
|
||||
case addRecoverablePlaceholderExpirationIndex
|
||||
case backfillRecoverablePlaceholderErrorType
|
||||
|
||||
// NOTE: Every time we add a migration id, consider
|
||||
// incrementing grdbSchemaVersionLatest.
|
||||
@ -5214,6 +5215,11 @@ public class GRDBSchemaMigrator {
|
||||
return .success(())
|
||||
}
|
||||
|
||||
migrator.registerMigration(.backfillRecoverablePlaceholderErrorType) { tx in
|
||||
try Self.backfillRecoverablePlaceholderErrorType(tx: tx)
|
||||
return .success(())
|
||||
}
|
||||
|
||||
// MARK: - Schema Migration Insertion Point
|
||||
}
|
||||
|
||||
@ -5573,6 +5579,15 @@ public class GRDBSchemaMigrator {
|
||||
|
||||
// MARK: - Migrations
|
||||
|
||||
static func backfillRecoverablePlaceholderErrorType(tx: DBWriteTransaction) throws {
|
||||
try tx.database.execute(sql: """
|
||||
UPDATE model_TSInteraction
|
||||
INDEXED BY index_interactions_on_recoverable_placeholder_expiration
|
||||
SET errorType = \(TSErrorMessageType.decryptionFailure.rawValue)
|
||||
WHERE recordType = \(SDSRecordType.recoverableDecryptionPlaceholder.rawValue)
|
||||
""")
|
||||
}
|
||||
|
||||
static func addMimeTypeToMessageAttachmentReference(tx: DBWriteTransaction) throws {
|
||||
try tx.database.alter(table: "MessageAttachmentReference") { table in
|
||||
// In practice, this column will be NOT NULL. However, we can't
|
||||
|
||||
@ -383,17 +383,27 @@ public class InteractionFinder: NSObject {
|
||||
ORDER BY \(interactionColumn: .receivedAtTimestamp)
|
||||
"""
|
||||
|
||||
let cursor = TSInteraction.grdbFetchCursor(
|
||||
sql: sql,
|
||||
transaction: tx,
|
||||
)
|
||||
var cursor = FailIfThrowsRecordCursor {
|
||||
try InteractionRecord.fetchCursor(
|
||||
tx.database,
|
||||
sql: sql,
|
||||
)
|
||||
}
|
||||
|
||||
while let interactionRecord = cursor.next() {
|
||||
let interaction: TSInteraction
|
||||
do {
|
||||
interaction = try TSInteraction.fromRecord(interactionRecord)
|
||||
} catch {
|
||||
owsFailDebug("Failed to deserialize TSInteraction! \(error)")
|
||||
continue
|
||||
}
|
||||
|
||||
guard let placeholder = interaction as? OWSRecoverableDecryptionPlaceholder else {
|
||||
owsFailDebug("TSInteraction was not an OWSRecoverableDecryptionPlaceholder?")
|
||||
continue
|
||||
}
|
||||
|
||||
while
|
||||
// Silently skip malformed TSInteraction rows, lest we become stuck
|
||||
// on a malformed row forever.
|
||||
let interaction = try? cursor.next(),
|
||||
let placeholder = interaction as? OWSRecoverableDecryptionPlaceholder
|
||||
{
|
||||
return placeholder
|
||||
}
|
||||
|
||||
|
||||
@ -1642,4 +1642,74 @@ struct GRDBSchemaMigratorTest {
|
||||
false, // regular mp4
|
||||
])
|
||||
}
|
||||
|
||||
@Test
|
||||
func testBackfillRecoverablePlaceholderErrorType() throws {
|
||||
let placeholderRecordType = SDSRecordType.recoverableDecryptionPlaceholder.rawValue
|
||||
let errorMessageRecordType = SDSRecordType.errorMessage.rawValue
|
||||
let decryptionFailure = TSErrorMessageType.decryptionFailure.rawValue
|
||||
let nonBlockingIdentityChange = TSErrorMessageType.nonBlockingIdentityChange.rawValue
|
||||
|
||||
let databaseQueue = DatabaseQueue()
|
||||
try databaseQueue.write { db in
|
||||
try db.execute(sql: """
|
||||
CREATE TABLE "model_TSInteraction" (
|
||||
id INTEGER PRIMARY KEY,
|
||||
recordType INTEGER NOT NULL,
|
||||
uniqueId TEXT NOT NULL UNIQUE,
|
||||
receivedAtTimestamp INTEGER NOT NULL,
|
||||
errorType INTEGER
|
||||
);
|
||||
""")
|
||||
try db.execute(sql: """
|
||||
CREATE INDEX "index_interactions_on_recoverable_placeholder_expiration"
|
||||
ON "model_TSInteraction"(receivedAtTimestamp)
|
||||
WHERE recordType = \(placeholderRecordType);
|
||||
""")
|
||||
try db.execute(
|
||||
sql: """
|
||||
INSERT INTO "model_TSInteraction" (id, recordType, uniqueId, receivedAtTimestamp, errorType)
|
||||
VALUES (?, ?, ?, ?, ?), (?, ?, ?, ?, ?), (?, ?, ?, ?, ?), (?, ?, ?, ?, ?)
|
||||
""",
|
||||
arguments: [
|
||||
1,
|
||||
placeholderRecordType,
|
||||
"A",
|
||||
1000,
|
||||
nil,
|
||||
2,
|
||||
placeholderRecordType,
|
||||
"B",
|
||||
2000,
|
||||
nonBlockingIdentityChange,
|
||||
3,
|
||||
errorMessageRecordType,
|
||||
"C",
|
||||
3000,
|
||||
nil,
|
||||
4,
|
||||
errorMessageRecordType,
|
||||
"D",
|
||||
4000,
|
||||
nonBlockingIdentityChange,
|
||||
],
|
||||
)
|
||||
|
||||
let tx = DBWriteTransaction(database: db)
|
||||
defer { tx.finalizeTransaction() }
|
||||
try GRDBSchemaMigrator.backfillRecoverablePlaceholderErrorType(tx: tx)
|
||||
}
|
||||
|
||||
let errorTypes = try databaseQueue.read { db in
|
||||
try Int32?.fetchAll(db, sql: """
|
||||
SELECT errorType FROM model_TSInteraction ORDER BY id
|
||||
""")
|
||||
}
|
||||
#expect(errorTypes == [
|
||||
decryptionFailure, // placeholder, was NULL -> backfilled
|
||||
decryptionFailure, // placeholder, errorType corrected
|
||||
nil, // non-placeholder, untouched
|
||||
nonBlockingIdentityChange, // non-placeholder, untouched
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user