问题描述
在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应用效果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!