Bruno Koga
Bruno Koga

Reputation: 3874

Sqlite FTS doesn't work when compiling with LLVM on iOS

I've been developing an enterprise iPad app for a while now. Since the app development started almost 2 years ago, I needed to compile my own version SQLite from source, since the default SQLite library (the sqlite3.dylib) didn't have FTS enabled by default.

Ok, everything was working fine since then. I've been always using GCC as the project compiler.

The thing is that now I'm trying to convert my whole project to use ARC. To do so, I need to use Apple's LLVM compiler.

That's it. When I change the compiler (from GCC 4.2 to LLVM 3.1 or 4.0, without converting to ARC, and without changing anything else), my app builds fine, everything runs ok, except by my FTS queries, which don't work at all Even the simplest ones. They run and return always with no result (with a SQLITE_OK code, though).

I'm stuck here. I have already talked to an Apple engineer at WWDC'12 but we couldn't find any solution.

I guarantee that it is unlikely to be a malformed query or something like that since the app is working fine with GCC. Also, I'm able to run the queries on the Terminal version of SQLite (or using other apps, like Base)

I was also using an old version of SQLite, but I've updated to the most recent version to date (3.7.13). Everything stays the same. I've also noticed that, now (I don't know since when) the sqlite that comes with the mac supports FTS (!!!) and I was able to remove my own version and use Apple's one. The thing is, I'm having the exact same behavior.

I've been looking for a solution, but couldn't find one. I've found some bugs related to armv6 and compiler optimisations (which can be fixed by using the -mno-thumb flag), but it's not my case. I also noticed that when I analyse my custom sqlite files using Clang it points out many, many "potencial errors".

I have this non-skeptical view and I (still) don't believe that it's a LLVM or SQLite bug. I prefer to check everything that is possible before addressing them a bug. Maybe I'm forgetting to configure something or need to add some flag to the compiler that I'm not doing.

I appreciate any help. Again, the bug only occurs on projects compiled with LLVM (even with the default sqlite). If I run the same queries on the Terminal version of sqlite3, everything goes fine.

UPDATE:

This code works. It creates a new database, a new virtual table using fts, insert a couple of items and then execute the select. I'll try more complex queries later, but, for now, it seems that the issue with my app might be, as expected, a bug in my code.

NSArray *dirPaths = dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docsDir = [dirPaths objectAtIndex:0];
sqlite3 *database;

// Build the path to the database file
NSString *databasePath = [[NSString alloc] initWithString: [docsDir stringByAppendingPathComponent: @"test.db"]];

NSFileManager *filemgr = [NSFileManager defaultManager];
NSError *error = nil;
[filemgr removeItemAtPath:databasePath error:&error];

const char *dbpath = [databasePath UTF8String];

if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
    char *errMsg;
    const char *sql_stmt = "CREATE VIRTUAL TABLE IF NOT EXISTS pages USING fts3(title, body);";

    if (sqlite3_exec(database, sql_stmt, NULL, NULL, &errMsg) != SQLITE_OK)
    {
        NSLog(@"Failed to create table");
    } else {

        sql_stmt = "INSERT INTO pages(docid, title, body) VALUES(53, 'Home Page', 'SQLite is a software...');";
        if (sqlite3_exec(database, sql_stmt, NULL, NULL, &errMsg) != SQLITE_OK)
        {
            NSLog(@"Failed to insert");
        }

        sql_stmt = "INSERT INTO pages(title, body) VALUES('Download', 'All SQLite source code...');";
        if (sqlite3_exec(database, sql_stmt, NULL, NULL, &errMsg) != SQLITE_OK)
        {
            NSLog(@"Failed to insert");
        }
    }

    sqlite3_stmt *statement;
    const char *query_stmt = "select * from pages where body match 'soft*';";

    if (sqlite3_prepare_v2(database, query_stmt, -1, &statement, NULL) == SQLITE_OK)
    {
        if (sqlite3_step(statement) == SQLITE_ROW)
        {
            NSLog(@"%@ - %@", [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement, 0)],
                  [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(statement, 1)]);
        } else {
            NSLog(@"no results");
        }
        sqlite3_finalize(statement);
    }

    sqlite3_close(database);

} else {
    NSLog(@"Failed to open/create database");
}

Upvotes: 4

Views: 554

Answers (1)

Bruno Koga
Bruno Koga

Reputation: 3874

After all, I've found the bug. It was in my code. In summary, that what I've found out: If I have something like that (I know it's weird/wrong):

int a = 0;
a = a++;
NSLog(@"%d", a);

the logged value will be 1 if this code is compiled with gcc and 0 if compiled with llvm.

I don't know why, but that's another question :)

Upvotes: 3

Related Questions