Why does my iPhone app update from App Store fail while upgrading the database?

2

I've released an app update which does an upgrade of the database ie. executes a script file in the bundle that adds a column to existing table , etc. I've tested this by deploying previous version builds on my device from xcode and then deploying the latest version. The upgrade worked fine.

Yesterday my distribution build got accepted to app store. When I start it up , my nightmare scenario materialized , it fails during DB upgrade! I've checked the distribution build and the upgradeSQL file is there , so it doesn't seem to be a missing resource file all though I'm not sure. I have no idea how I should debug this. What is the difference between a distribution build from app store and a release/debug build deployed from xcode , apart from code signing? Doesn't make sense to me.

This is my crash log and the code that fails:

0   libSystem.B.dylib               0x3141d414 pread + 20
1   libsqlite3.0.dylib              0x303a2154 unixRead + 40
2   libsqlite3.0.dylib              0x303bd7c4 sqlite3PagerAcquire + 3748
3   libsqlite3.0.dylib              0x303c7718 sqlite3BtreeNext + 260
4   libsqlite3.0.dylib              0x303c7b84 sqlite3BtreeNext + 1392
5   libsqlite3.0.dylib              0x304272b8 sqlite3VdbeExec + 38668
6   libsqlite3.0.dylib              0x30428944 sqlite3Step + 504
7   libsqlite3.0.dylib              0x303ecbc4 sqlite3_exec + 600
8   MyApp                       0x00046ae4 +[DBUpgradeService executeUpgradeScript:] (DBUpgradeService.m:94)
9   MyApp                       0x000469aa +[DBUpgradeService upgradeV1_0ToV1_1] (DBUpgradeService.m:67)
10  MyApp                       0x0004687a +[DBUpgradeService upgradeDBIfNecessary] (DBUpgradeService.m:27)
11  MyApp                       0x000021ec -[MyAppAppDelegate applicationDidFinishLaunching:] (MyAppAppDelegate.m:49)
12  UIKit                           0x30a4ef24 -[UIApplication performInitializationWithURL:asPanel:] + 160
13  UIKit                           0x30a57dec -[UIApplication _runWithURL:] + 644
14  Foundation                      0x306945a2 __NSFireDelayedPerform + 326
15  CoreFoundation                  0x30269d88 CFRunLoopRunSpecific + 2642
16  CoreFoundation                  0x30269320 CFRunLoopRunInMode + 44
17  GraphicsServices                0x31567e58 GSEventRunModal + 268
18  UIKit                           0x30a4fa6c -[UIApplication _run] + 520
19  UIKit                           0x30a591d0 UIApplicationMain + 1132
20  MyApp                       0x00002090 main (main.m:20)
21  MyApp                       0x0000202c start + 44



+ (BOOL) executeUpgradeScript:(NSString*) scriptName{
    NSString *resourcePath = [[NSBundle mainBundle] resourcePath];
    NSString *scriptPath = [resourcePath stringByAppendingPathComponent:scriptName];

    NSString* upgradeScript = [NSString stringWithContentsOfFile:scriptPath];
    NSArray* lines = [upgradeScript componentsSeparatedByString:@"\n"];
    //begin transaction
    NSString* begin = [NSString stringWithString:@"BEGIN TRANSACTION"];

    sqlite3_exec([DatabaseManager getDatabase], begin.UTF8String , nil , nil , nil);
    BOOL failed = NO;
    for( NSString* line in lines) {
        const char *sql = line.UTF8String;
        char* error = nil;
        sqlite3_exec([DatabaseManager getDatabase], sql , nil , nil , &error); //THIS LINE FAILS
        if(error != nil) {
            NSLog([NSString stringWithCString:error]);
            failed = YES;
            break;
        }
    }

    if(failed){
        return NO;
    }
    else{
        NSString* commit = [NSString stringWithString:@"COMMIT"];
        sqlite3_exec([DatabaseManager getDatabase], commit.UTF8String , nil , nil , nil);
        return YES;

    }
}
iphone
sqlite
asked on Stack Overflow May 23, 2009 by Maxm007 • edited May 23, 2009 by Maxm007

2 Answers

1

You aren't allowed to modify files in your application bundle (see epatel's link). As part of your build process, the app gets signed, and modifying files in the bundle will break the signature.

You should be using your application's document directory. You should replace your resourcePath assignment with:

NSString *resourcePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
answered on Stack Overflow May 23, 2009 by Martin Gordon
1

If the upgrade of the DB takes to long time in the launch phase an app can be kicked out.

One way to resolve such a problem could be to put the upgrade in a NSThread

- (void)upgradeSomething:(id)sender
{
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 

  // Do something here that takes time

  // and maybe signal when done with some flag or thing...

  [pool release];
}

- (void)awakeFromNib
{
    // The usual stuff

    // and detach a NSThread for upgrade 

    [NSThread detachNewThreadSelector:@selector(upgradeSomething:) 
                             toTarget:self 
                           withObject:nil]
}

Read here for reason for keeping the event loop active.

answered on Stack Overflow May 23, 2009 by epatel • edited May 23, 2009 by epatel

User contributions licensed under CC BY-SA 3.0