iOS SQLite SELECT 使用 UTF 8 个字符

iOS SQLite SELECT with UTF 8 characters

我已经阅读了所有与 SQlite 编码相关的问题但没有成功,所以我会尝试询问我的具体情况。

我有一个预填充了 SQLite 数据库的 iOS 应用程序。 此 SQLite 已从 MySQL 数据库转换而来。 SQLite 和 MySQL 数据库都有 UTF8 编码(转换过程将默认的 sqlite 编码设置为 UTF8)

如果我用 Firefox SQlite Manager 打开我的 sqlite 数据库,我可以毫无问题地读取所有内容,并且所有 UTF8 字符都正确显示,所以我猜所有内容都已正确转换。

但是,当我尝试执行包含 UTF8 字符的 select 时,查询失败。

这是我执行查询的方法:

- (NSArray *)performQuery:(NSString *)query
{
    static sqlite3 *db;
    sqlite3_stmt *resultado;
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:@"mydatabase.sqlite"];
    const char *dbpath = [writableDBPath UTF8String];
    if (sqlite3_open(dbpath, &db) == SQLITE_OK)
    {
        printf("%s\n", [query UTF8String]);
        int codigo = sqlite3_prepare_v2(db,[query UTF8String],[query length],&resultado,NULL);
        if (codigo == SQLITE_OK)
        {
            NSMutableArray *result = [NSMutableArray array];
            while (sqlite3_step(resultado) == SQLITE_ROW)
            {
                NSMutableArray *row = [NSMutableArray array];
                for (int i = 0; i < sqlite3_column_count(resultado); i++)
                {
                    int colType = sqlite3_column_type(resultado, i);
                    id value;
                    if (colType == SQLITE_TEXT)
                    {
                        value = [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(resultado, i)];
                        if ([value isEqualToString:@"(null)"] || [value isEqualToString:@""] || (value == nil) || [value isKindOfClass:[NSNull class]])
                        {
                            value = @"";
                        }
                    }
                    else if (colType == SQLITE_INTEGER)
                    {
                        int col = sqlite3_column_int(resultado, i);
                        value = [NSNumber numberWithInt:col];
                    }
                    else if (colType == SQLITE_FLOAT)
                    {
                        double col = sqlite3_column_double(resultado, i);
                        value = [NSNumber numberWithDouble:col];
                    }
                    else if (colType == SQLITE_NULL)
                    {
                        value = [NSNull null];
                    }
                    else
                    {
                        NSLog(@"ERROR: DataBase - performQuery - Campo desconocido");
                    }
                    [row addObject:value];
                }
                [result addObject:row];
                row = nil;
            }
            sqlite3_finalize(resultado);
            sqlite3_close(db);
            resultado = nil;
            return result;
        }
        else
        {
            NSLog(@"ERROR [%d](%s): %@", codigo, sqlite3_errmsg(db), query);
        }
    }
    else
    {
        NSLog(@"ERROR: No se pudo abrir la base de datos");
    }
    sqlite3_close(db);
    db = nil;
    resultado = nil;
    return nil;
}

这是我调用 performQuery 的方法:

- (int) getIdForItem:(NSString *)item
{
    NSString *query = [NSString stringWithFormat:@"SELECT item_id FROM table_items WHERE item_name=\"%@\"", item];
    NSLog(@"QUERY:\n%@", query);
    NSArray *answer = [self performQuery:query];
    if([answer count] > 0)
        return [[[answer objectAtIndex:0] objectAtIndex:0] intValue];
    return -1;
}

如果我打这个电话:

[self getIdForItem:@"Camión"];

这是输出:

QUERY:
SELECT item_id FROM table_items WHERE item_name="Camión"
SELECT item_id FROM table_items WHERE item_name="Camión"
ERROR [1](unrecognized token: ""Cami√≥n"): SELECT item_id FROM table_items WHERE item_name="Camión"

这个错误是在方法中产生的:

sqlite3_prepare_v2(db,[query UTF8String],[query length],&resultado,NULL)

那么,为什么在sqlite_prepare_v2中Camión被解读为Cami√≥n呢?查询和 sqlite 数据库都使用 UTF8,所以我想我遗漏了一些东西...

嗯,rmaddy 的解决方案非常适合我。我所做的是:

PerformQuery 几乎相同,它接收一个新参数:

- (NSArray *)performQuery:(NSString *)query withArgument:(NSString *)arg

就在 sqlite3_prepare_v2 之后,我进行了绑定:

    int codigo = sqlite3_prepare_v2(db,[query UTF8String],[query length],&resultado,NULL);
    if (codigo == SQLITE_OK)
    {
        sqlite3_bind_text(resultado, 1, [arg UTF8String], -1, SQLITE_TRANSIENT);

        NSMutableArray *result = [NSMutableArray array];
        while (sqlite3_step(resultado) == SQLITE_ROW)

最后,我这样调用这个方法:

- (int) getIdForItem:(NSString *)item
{
    NSString *query = @"SELECT item_id FROM table_items WHERE item_name=?1";
    NSLog(@"QUERY:\n%@", query);
    NSArray *answer = [self performQuery:query];
    if([answer count] > 0)
        return [[[answer objectAtIndex:0] objectAtIndex:0] intValue];
    return -1;
}