SQLite的C函数在EXC_BAD_ACCESS的iOS应用效果 [英] SQLite C function in iOS application results in EXC_BAD_ACCESS

查看:496
本文介绍了SQLite的C函数在EXC_BAD_ACCESS的iOS应用效果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在iOS应用程序,我想从一个SQLite场1万行剥离变音符号在表中。

In an iOS application, I am trying to strip diacritics from a SQLite field in a table with 1 million rows.

修改:我引用href=\"http://stackoverflow.com/a/10356596/1195620\">原来的答复的以反映下面的接受的答案。这是任何人都试图做同样的事情,最好的答案。

EDIT: The original answer I referenced has been updated by its author to reflect the accepted answer below. It is the best answer for anyone trying to do the same thing.

我有一个很好的开始,从罗布较早的答案。对于这个问题的目的,我想一个表复制到另一个使用 INSERT INTO ..​​. SELECT ... FROM ... 语句。直到我介绍,从外地口音剥离和其他变音符号的C函数能正常工作:

I got a great start from an earlier answer by Rob. For the purposes of this question, I'm trying to copy a table to another using an INSERT INTO ... SELECT ... FROM ... statement. This works fine until I introduce a C function that strips accents and other diacritics from a field:

INSERT INTO DestinationTable (MasterField, SubField, IndexID) SELECT unaccented(MasterField), SubField, IndexID FROM SourceTable

随着重音()功能介绍,我经常收到我在下面指定一个EXC_BAD_ACCESS。但诱人,SQLite的操作有时会成功完成所有一百万行即可。当我向负载跨越500万行进行复制,应用程序将总是崩溃。

With the unaccented() function introduced, I often get an EXC_BAD_ACCESS which I'll specify below. But tantalizingly, the SQLite operation will sometimes complete successfully for all 1 million rows. When I extend the load to replicate across 5 million rows, the application will always crash.

TL; DR

下面是我的源$ C ​​$ C,与EXC_BAD_ACCESS点评论的第一个函数的底部:

Here is my source code, with the point of EXC_BAD_ACCESS commented at the bottom of the first function:

#import <sqlite3.h>

sqlite3 *db;

void unaccented(sqlite3_context *context, int argc, sqlite3_value **argv)
{
    if (argc != 1 || sqlite3_value_type(argv[0]) != SQLITE_TEXT) {
        sqlite3_result_null(context);
        return;
    }

    @autoreleasepool {
        NSMutableString *string = [NSMutableString stringWithUTF8String:(const char *)sqlite3_value_text(argv[0])];
        CFStringTransform((__bridge CFMutableStringRef)string, NULL, kCFStringTransformStripCombiningMarks, NO);

        char *buf = sqlite3_malloc(sizeof(char) * [string length] + 1);
        strcpy(buf, [string UTF8String]);

        sqlite3_result_text(context, buf, -1, sqlite3_free);
    } // This is where I usually get "EXC_BAD_ACCESS (code=1, address=...)"
}

@implementation MyClass

- (void)myMethod
{
    NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
    NSString *cachesDir = [documentPaths objectAtIndex:0];
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSError *error = nil;

    NSDirectoryEnumerator *directoryEnumerator = [fileManager enumeratorAtPath:[[NSBundle mainBundle] resourcePath]];

    NSString *fileName;
    while (fileName = [directoryEnumerator nextObject])
    {
        if ([fileName hasSuffix:@".sqlite"])
        {
            if (![fileManager fileExistsAtPath: [cachesDir stringByAppendingPathComponent:fileName]] == YES)
            {
                if (![fileManager copyItemAtPath:[[NSBundle mainBundle] pathForResource:fileName ofType:@""] toPath:[cachesDir stringByAppendingPathComponent:fileName] error:&error])
                {
                    NSLog(@"Error description - %@ \n", [error localizedDescription]);
                    NSLog(@"Error reason - %@", [error localizedFailureReason]);
                }
                else
                {
                    NSLog(@"HAI %@", fileName);

                    [self openDB:[cachesDir stringByAppendingPathComponent:fileName]];

                    NSString *sqlCommand = @"INSERT INTO DestinationTable (MasterField, SubField, IndexID) SELECT unaccented(MasterField), SubField, IndexID FROM SourceTable";

                    char *sqlError;
                    if (sqlite3_exec(db, [sqlCommand UTF8String], NULL, NULL, &sqlError) != SQLITE_OK)
                    {
                        NSLog(@"sqlite3_exec INSERT NOT SQLITE_OK with error: %d: %s", sqlite3_errcode(db), sqlite3_errmsg(db));
                    }

                    [self closeDB];

                    NSLog(@"KTHXBYE %@", fileName);
                }
            }
        }
    }
}

- (void) openDB: (NSString *)filePath
{
    if (sqlite3_open([filePath UTF8String], &db) != SQLITE_OK)
    {
        sqlite3_close(db);
    }
    else
    {
        [self createUnaccentedFunction];
    }
}

- (void) closeDB
{
    sqlite3_close(db);
}

- (void)createUnaccentedFunction
{
    if (sqlite3_create_function_v2(db, "unaccented", 1, SQLITE_ANY, NULL, &unaccented, NULL, NULL, NULL) != SQLITE_OK)
    {
        NSLog(@"%s: sqlite3_create_function_v2 error: %s", __FUNCTION__, sqlite3_errmsg(db));
    }
}

这是我做错了任何意见?

Any observations on what I'm doing wrong?

推荐答案

或许它是这样的:

char *buf = sqlite3_malloc(sizeof(char) * [string length] + 1);
strcpy(buf, [string UTF8String]);

你分配长度的Uni code字符,而不是UTF-8字节。

you are allocating length Unicode characters, instead of UTF-8 bytes.

的strcpy 则可以尝试写入无效的内存。

strcpy may then try to write invalid memory.

我建议你使用,让SQLite的复制串:

I suggest you to let SQLite copy string using:

sqlite3_result_text(context, [string UTF8String], -1, SQLITE_TRANSIENT);

这篇关于SQLite的C函数在EXC_BAD_ACCESS的iOS应用效果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆