corrupt coredata DB

  • I have a coredata application that uses sqlite3 for persistence. One
    of my users reported that his application was not responsive and
    showed the spinning beach ball of death. If I debug the application
    using his database it stops after executing this:

    // objectId is the object we want to delete
    NSManagedObject *managedObj = [[self managedObjectContext]
    objectWithID:objectId];
    [[self managedObjectContext] deleteObject:managedObj];
    NSError *error;
    [[self managedObjectContext] save:&error]

    It never goes beyond the line above. The System halts at the save
    command without fulfilling the error object. If I run the application
    with the "-com.apple.CoreData.SQLDebug 5" argument and look at the
    console I see the infinite loop that is freezing the application:

    CoreData: sql: BEGIN EXCLUSIVE
    CoreData: sql: DELETE FROM ZPLAYEDTRACK WHERE Z_PK = ? AND Z_OPT = ?
    CoreData: details: SQLite bind[0] = (int64)660
    CoreData: details: SQLite bind[1] = nil
    CoreData: sql: SELECT Z_PK,Z_OPT FROM ZPLAYEDTRACK WHERE Z_PK IN (660)
    ORDER BY Z_PK
    CoreData: annotation: sql execution time: 0.0069s
    CoreData: sql: ROLLBACK

    CoreData: sql: BEGIN EXCLUSIVE
    CoreData: sql: DELETE FROM ZPLAYEDTRACK WHERE Z_PK = ? AND Z_OPT = ?
    CoreData: details: SQLite bind[0] = (int64)660
    CoreData: details: SQLite bind[1] = nil
    CoreData: sql: SELECT Z_PK,Z_OPT FROM ZPLAYEDTRACK WHERE Z_PK IN (660)
    ORDER BY Z_PK
    CoreData: annotation: sql execution time: 0.0056s
    CoreData: sql: ROLLBACK

    (...)

    Looks like it's trying to delete the object repeatedly in the database
    but it can't and then rolls back and tries again. By looking inside
    the sqlite database directly through sqlite3 tool I see that the tuple
    that coredata is trying to delete has Z_OPT equal to null:

    sqlite> .schema ZPLAYEDTRACK
    CREATE TABLE ZPLAYEDTRACK ( ZSKIP INTEGER, ZSHUFFLEMODE INTEGER, Z_OPT
    INTEGER, Z_ENT INTEGER, Z_PK INTEGER PRIMARY KEY, ZEND FLOAT, ZBEGIN
    FLOAT, ZTRACKNAME VARCHAR, ZLOCATION VARCHAR, ZALBUMNAME VARCHAR,
    ZARTISTNAME VARCHAR, ZSOURCE VARCHAR, ZPLAYLISTNAME VARCHAR );

    sqlite> select z_pk, z_ent, z_opt from zplayedtrack;
    660|1|
    661|1|
    662|1|1
    663|1|1

    How can I delete the two tuples (660 and 661) that have Z_OPT equal to
    NULL with coredata ?
    Any idea why Coredata ended with those tuples with null Z_OPT ?

    regards,
    Marc
  • DELETE FROM zplayedtrack WHERE z_opt = null

    I don't know much about CoreData but maybe you can't bind null
    parameters in SQLite?

    Devon

    Marc Monguio wrote:
    > I have a coredata application that uses sqlite3 for persistence. One of
    > my users reported that his application was not responsive and showed the
    > spinning beach ball of death. If I debug the application using his
    > database it stops after executing this:
    >
    > // objectId is the object we want to delete
    > NSManagedObject *managedObj = [[self managedObjectContext]
    > objectWithID:objectId];
    > [[self managedObjectContext] deleteObject:managedObj];
    > NSError *error;
    > [[self managedObjectContext] save:&error]
    >
    > It never goes beyond the line above. The System halts at the save
    > command without fulfilling the error object. If I run the application
    > with the "-com.apple.CoreData.SQLDebug 5" argument and look at the
    > console I see the infinite loop that is freezing the application:
    >
    > CoreData: sql: BEGIN EXCLUSIVE
    > CoreData: sql: DELETE FROM ZPLAYEDTRACK WHERE Z_PK = ? AND Z_OPT = ?
    > CoreData: details: SQLite bind[0] = (int64)660
    > CoreData: details: SQLite bind[1] = nil
    > CoreData: sql: SELECT Z_PK,Z_OPT FROM ZPLAYEDTRACK WHERE Z_PK IN (660)
    > ORDER BY Z_PK
    > CoreData: annotation: sql execution time: 0.0069s
    > CoreData: sql: ROLLBACK
    >
    > CoreData: sql: BEGIN EXCLUSIVE
    > CoreData: sql: DELETE FROM ZPLAYEDTRACK WHERE Z_PK = ? AND Z_OPT = ?
    > CoreData: details: SQLite bind[0] = (int64)660
    > CoreData: details: SQLite bind[1] = nil
    > CoreData: sql: SELECT Z_PK,Z_OPT FROM ZPLAYEDTRACK WHERE Z_PK IN (660)
    > ORDER BY Z_PK
    > CoreData: annotation: sql execution time: 0.0056s
    > CoreData: sql: ROLLBACK
    >
    > (...)
    >
    > Looks like it's trying to delete the object repeatedly in the database
    > but it can't and then rolls back and tries again. By looking inside the
    > sqlite database directly through sqlite3 tool I see that the tuple that
    > coredata is trying to delete has Z_OPT equal to null:
    >
    > sqlite> .schema ZPLAYEDTRACK
    > CREATE TABLE ZPLAYEDTRACK ( ZSKIP INTEGER, ZSHUFFLEMODE INTEGER, Z_OPT
    > INTEGER, Z_ENT INTEGER, Z_PK INTEGER PRIMARY KEY, ZEND FLOAT, ZBEGIN
    > FLOAT, ZTRACKNAME VARCHAR, ZLOCATION VARCHAR, ZALBUMNAME VARCHAR,
    > ZARTISTNAME VARCHAR, ZSOURCE VARCHAR, ZPLAYLISTNAME VARCHAR );
    >
    > sqlite> select z_pk, z_ent, z_opt from zplayedtrack;
    > 660|1|
    > 661|1|
    > 662|1|1
    > 663|1|1
    >
    > How can I delete the two tuples (660 and 661) that have Z_OPT equal to
    > NULL with coredata ?
    > Any idea why Coredata ended with those tuples with null Z_OPT ?
    >
    > regards,
    > Marc
  • Marc,

    > Looks like it's trying to delete the object repeatedly in the database
    > but it can't and then rolls back and tries again. By looking inside
    > the sqlite database directly through sqlite3 tool I see that the tuple
    > that coredata is trying to delete has Z_OPT equal to null:

    That looks bad, and it looks like you have enough information to be
    worth filing a bug.  What version of OSX are you on ?

    Two other things you can do are (a) run "pragma integrity_check" on
    the db file, and (b) "delete from zplayedtrack where z_pk in (660, 661)"

    CD shouldn't ever get into that situation, so the SQL generation isn't
    expecting it.  The clause Z_OPT = ? where ? is bound to NULL is
    wrong.  NULL can only be meaningfully compared with "is null" or "is
    not null", the standard operators don't work as expected in SQL.  So
    the row doesn't match, because nothing is ever "=" to NULL in SQL, and
    we realize we failed to delete it and try again...again...again

    - Ben
  • > That looks bad, and it looks like you have enough information to be
    > worth filing a bug.
    I just filed it.  Bug ID# 6280722

    > What version of OSX are you on ?

    10.5.5, tried on PPC and Intel with same results.

    > Two other things you can do are
    > (a) run "pragma integrity_check" on the db file,
    Returns "ok", so there's the database itself is not corrupt, it's just
    coredata who left in an unstable mode for him to work afterwards

    > (b) "delete from zplayedtrack where z_pk in (660, 661)"
    Yes, that works, the next tuples do work with CoreData as expected.
    Unfortunately this is not a solution since I should not be accessing
    sqlite db directly.