I'm trying out Core Data with a test project and I'm facing some issues with Core Data and migrations. During the lightweight automatic migration, a crash occurs with the following :
[logging] near "null": syntax error in "SELECT MAX(Z_PK) FROM (null)"
[error] error: addPersistentStoreWithType:configuration:URL:options:error: returned error NSCocoaErrorDomain (134110)
CoreData: error: addPersistentStoreWithType:configuration:URL:options:error: returned error NSCocoaErrorDomain (134110)
CoreData: annotation: userInfo:
CoreData: annotation: sourceURL : file:///var/mobile/Containers/Data/Application/D712273A-6E49-4B19-9919-3E55F6A5A37D/Library/Application%20Support/TestApp.sqlite
CoreData: annotation: reason : Cannot migrate store in-place: near "null": syntax error
CoreData: annotation: destinationURL : file:///var/mobile/Containers/Data/Application/D712273A-6E49-4B19-9919-3E55F6A5A37D/Library/Application%20Support/TestApp.sqlite
CoreData: annotation: NSUnderlyingError : Error Domain=NSCocoaErrorDomain Code=134110 "An error occurred during persistent store migration." UserInfo={reason=near "null": syntax error, NSSQLiteErrorDomain=1, NSUnderlyingException=near "null": syntax error}
CoreData: annotation: storeType: SQLite
CoreData: annotation: configuration: (null)
CoreData: annotation: URL: file:///var/mobile/Containers/Data/Application/D712273A-6E49-4B19-9919-3E55F6A5A37D/Library/Application%20Support/TestApp.sqlite
CoreData: annotation: options:
CoreData: annotation: NSInferMappingModelAutomaticallyOption : 1
CoreData: annotation: NSMigratePersistentStoresAutomaticallyOption : 1
CoreData: annotation: NSPersistentStoreFileProtectionKey : NSFileProtectionComplete
CoreData: annotation: <NSPersistentStoreCoordinator: 0x281cf1500>: Attempting recovery from error encountered during addPersistentStore: Error Domain=NSCocoaErrorDomain Code=134110 "An error occurred during persistent store migration."
Here is the code of the PersistenceCointainer used to load database in the SwiftUI App :
struct PersistenceController {
static let shared = PersistenceController()
static var preview: PersistenceController = {
let result = PersistenceController(inMemory: true)
let viewContext = result.container.viewContext
for _ in 0..<10 {
let newItem = Relation(context: viewContext)
newItem.date = Date()
}
do {
try viewContext.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
return result
}()
var container: NSPersistentContainer
init(inMemory: Bool = false) {
container = NSPersistentContainer(name: "TestApp")
if inMemory {
container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")
}
if let storeDirectory = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first {
let sqliteURL = storeDirectory.appendingPathComponent("TestApp.sqlite")
//Set Protection for Core data sql file
let description = NSPersistentStoreDescription(url: sqliteURL)
description.shouldInferMappingModelAutomatically = true
description.shouldMigrateStoreAutomatically = true
description.setOption(FileProtectionType.complete as NSObject, forKey: NSPersistentStoreFileProtectionKey)
container.persistentStoreDescriptions = [description]
}
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
/*
Typical reasons for an error here include:
* The parent directory does not exist, cannot be created, or disallows writing.
* The persistent store is not accessible, due to permissions or data protection when the device is locked.
* The device is out of space.
* The store could not be migrated to the current model version.
Check the error message to determine what the actual problem was.
*/
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
container.viewContext.automaticallyMergesChangesFromParent = true
}
}
Here is more about the model I'm trying to change. I have a simple model called "Partner" :
I can show more details of the relations if necessary.
I'm simply adding a new String optional attribute, so I thought lightweight migration would be easy.
I have created a lot of test data to try some features and I'd enjoy avoiding to drop my database ^^ And since it's a test project I'd like to understand where the issue comes from to avoir repeating it.
Can anybody help understand where does this "SELECT MAX(Z_PK) FROM (null)" comes from and how I could fix it ?
Ok so I tried to dig inside the database and didn't find any strange-looking data.
I juste created a Mapping Model from the old to the new Partner
Model, and specified that the new field should take the "default" value, and the migrations worked : so I guess I'll never know what was the real reason for this bug :)
My advice for anyone that would face this bug : try creating a Mapping Model (steps 7/8 in this tutorial)