0

I'm checking and creating a database using the following function:

-(void) checkAndCreateDatabase
{
    // Check if the SQL database has already been saved to the users phone, if not then copy it over
    BOOL dbExists;

    // Create a FileManager object, we will use this to check the status
    // of the database and to copy it over if required
    NSFileManager *fileManager = [NSFileManager defaultManager];

    // Check if the database has already been created in the users filesystem
    dbExists = [fileManager fileExistsAtPath:_databasePath];

    // If the database already exists then return without doing anything
    if(dbExists)
    {
        //sqlite3_open([self.databasePath UTF8String], &_database);
        NSLog(@"DB DOES EXIST");
        return;
    }
    NSLog(@"DB DOES NOT YET EXIST");
    // If not then proceed to copy the database from the application to the users filesystem

    // Get the path to the database in the application package
    NSString *databasePathFromApp = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:_databaseName];

    // Copy the database from the package to the users filesystem
    [fileManager copyItemAtPath:databasePathFromApp toPath:_databasePath error:nil];
}

The database name and path are properly set here, in the init function for my Search class:

- (id)init
{
    if ((self = [super init]))
    {
        _databaseName = DB_NAME;

        NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString *documentsDir = [documentPaths objectAtIndex:0];
        _databasePath = [documentsDir stringByAppendingPathComponent:_databaseName];

        if (sqlite3_open([_databasePath UTF8String], &_database) != SQLITE_OK)
        {
            [[[UIAlertView alloc]initWithTitle:@"Missing"
                                       message:@"Database file not found"
                                      delegate:nil
                             cancelButtonTitle:@"OK"
                             otherButtonTitles:nil, nil]show];
        }
    }
    return self;
}

Then, I query the database using:

-(void)search:(NSString *)searchTerm
{
    const char *dbpath = [_databasePath UTF8String];
    sqlite3_stmt *statement;

    /* Begin Database Work */
    if(sqlite3_open(dbpath, &_database) == SQLITE_OK)
    {
        NSString *querySQL = @"SELECT * FROM types";
        const char *query_stmt = [querySQL UTF8String];
        if (sqlite3_prepare_v2(_database, query_stmt, -1, &statement, NULL))
        {
           if(sqlite3_step(statement) == SQLITE_ROW)
           {
               NSLog([[NSString alloc] initWithUTF8String: (const char *) sqlite3_column_text(statement,1)]);
           }
           else
           {
               NSLog(@"nope2: query = ");
               printf(query_stmt);
           }
        }
        else
        {
            NSLog(@"nope1");
        }


    }
}

I'm always getting "nope2" returned, which seems to imply that no results are returned. When I run the exact same query on the database in SQLite directly, however, I get the results I expect. This leads me to believe that I'm doing something wrong in the code. What looks wrong here?

4

1 回答 1

3

几个想法:

  1. 一个非常常见的问题是,在过去的某个时候,复制失败,sqlite3_open因此会创建一个空白数据库(这就是为什么我通常使用sqlite3_open_v2SQLITE_OPEN_READWRITE选项而不是SQLITE_OPEN_CREATE选项,以防止它创建一个空白数据库)。无论如何,如果发生这种情况,从那时起,检查文件是否存在将成功,即使Documents路径中的数据库是空白数据库。您可以通过在DocumentsMac 上打开路径中的数据库并检查它来确认这一点(如果使用模拟器,您可以导航到~/Library/Application Support/iPhone Simulator,找到应用程序,然后导航到它的Documents文件夹; 如果是设备,您可以使用 Xcode 管理器选择应用程序并下载应用程序的包,然后查看那里的数据库版本)。更简单的是,只需从您的设备/模拟器中删除该应用程序,重新安装该应用程序,这应该可以解决它。

    但是,如果您有疑问,请确保仅检查 Documents 文件夹中的数据库副本,您应该能够快速诊断问题。

  2. 另一个问题是您应该更换:

    if (sqlite3_prepare_v2(_database, query_stmt, -1, &statement, NULL)) 
    {
        ...
    }
    else
    {
        NSLog(@"nope1");
    }
    

    if (sqlite3_prepare_v2(_database, query_stmt, -1, &statement, NULL) == SQLITE_OK) 
    {
        ...
    }
    else
    {
        NSLog(@"%s: sqlite3_prepare_v2 error: %s", __FUNCTION__, sqlite3_errmsg(_database));
    }
    

    请注意,(a)我正在检查SQLITE_OK, ,因为它是0,并且您的代码实际上与您显然想要的完全相反;(b) 如果有错误,我会从 SQLite 收到错误消息。之后的错误消息sqlite3_prepare_v2通常非常有启发性。

  3. 您还应该检查copyItemAtPath调用的结果并确保它正在返回YES。如果没有,你应该报告一个错误。因此,替换:

    [fileManager copyItemAtPath:databasePathFromApp toPath:_databasePath error:nil];
    

    NSError *error = nil;
    if (![fileManager copyItemAtPath:databasePathFromApp toPath:_databasePath error:&error])
    {
        NSLog(@"%s: copyItemAtPathError: %@", __FUNCTION__, error);
    }
    

    例如,在您的原始代码中,如果您忽略了将数据库包含在包中,则复制将失败,但您不会检测到此失败,而且更糟糕的是,因为您使用的是sqlite3_open(而不是sqlite3_open_v2),所以您不会在打开过程中看不到错误。

于 2013-06-17T04:42:23.760 回答