Несколько запросов не выполняются в FMDB - PullRequest
8 голосов
/ 10 ноября 2011

Я использую FMDB для создания базы данных SQLite на iPhone. У меня есть initial.sql, который имеет вид

CREATE TABLE Abc ... ;
CREATE TABLE Def ... ;

Я загружаю это, загружая файл в строку NSString и запуская его

NSString * str = // string from file initial.sql

[db executeUpdate: str];

Это успешно, но позже я получаю ошибку:

no such table: Def

Понятно, что второе утверждение не вызывается. Как я могу сделать это, чтобы все запросы были вызваны?

Согласно документации SQLite: «Подпрограммы sqlite3_prepare_v2 (), sqlite3_prepare (), sqlite3_prepare16 (), sqlite3_prepare16_v2 (), sqlite3_exec () и sqlite3_get_table () принимают список операторов SQL (sql-stmt-list), который является разделенным списком операторов.»

Итак, все это должно работать.

Ответы [ 3 ]

8 голосов
/ 04 мая 2014

FMDB v2.3 теперь имеет встроенную оболочку для sqlite3_exec с именем executeStatements:

BOOL success;

NSString *sql = @"create table bulktest1 (id integer primary key autoincrement, x text);"
                 "create table bulktest2 (id integer primary key autoincrement, y text);"
                 "create table bulktest3 (id integer primary key autoincrement, z text);"
                 "insert into bulktest1 (x) values ('XXX');"
                 "insert into bulktest2 (y) values ('YYY');"
                 "insert into bulktest3 (z) values ('ZZZ');";

success = [db executeStatements:sql];

. Также имеется вариант с обратным вызовом sqlite3_exec, реализованныйкак блок:

sql = @"select count(*) as count from bulktest1;"
       "select count(*) as count from bulktest2;"
       "select count(*) as count from bulktest3;";

success = [db executeStatements:sql withResultBlock:^int(NSDictionary *dictionary) {
    NSInteger count = [dictionary[@"count"] integerValue];
    NSLog(@"Count = %d", count);
    return 0;   // if you return 0, it continues execution; return non-zero, it stops execution
}];
8 голосов
/ 18 ноября 2011

Меня тоже укусила эта;мне потребовалось целое утро, чтобы пройтись по базе данных FMD и прочитать документацию по API sqlite3, чтобы найти ее.Я до сих пор не до конца уверен в основной причине проблемы, но в соответствии с этой ошибкой в ​​PHP необходимо вызвать sqlite3_exec вместо подготовки оператора с помощью sqlite3_prepare_v2 и затем вызватьsqlite3_step.

Документация, по-видимому, не предполагает, что такое поведение может произойти, отсюда и наша путаница, и я бы хотел, чтобы кто-то с большим опытом работы с sqlite выдвинул некоторые гипотезы.

Я решил эту проблему, разработав метод для выполнения пакета запросов.Пожалуйста, найдите код ниже.Если вы предпочитаете, вы можете переписать это в категорию, а не просто добавить его в FMDatabase.h, ваш вызов.

Добавьте это в интерфейс FMDatabase в FMDatabase.h:

- (BOOL)executeBatch:(NSString*)sql error:(NSError**)error;

Добавьте это к реализации FMDatabase в FMDatabase.m:

- (BOOL)executeBatch:(NSString *)sql error:(NSError**)error
{
    char* errorOutput;
    int responseCode = sqlite3_exec(db, [sql UTF8String], NULL, NULL, &errorOutput);

    if (errorOutput != nil)
    {
        *error = [NSError errorWithDomain:[NSString stringWithUTF8String:errorOutput]
                                     code:responseCode 
                                 userInfo:nil];
        return false;
    }

    return true;
}

Обратите внимание, что в executeBatch отсутствуют многие функции, которые делают его непригодным для многих целей.В частности, он не проверяет, заблокирована ли база данных, не проверяет, не заблокирована ли сама база данных FMD, он не поддерживает кэширование операторов.

Если вам это нужно, приведенное вышехорошая отправная точка, чтобы кодировать это самостоятельно.Удачного взлома!

2 голосов
/ 21 апреля 2014
Split Batch Statement
Add in .h file:
#import "FMSQLStatementSplitter.h"
#import "FMDatabaseQueue.h"

FMSQLStatementSplitter can split batch sql statement into several separated statements, then [FMDatabase executeUpdate:] or other methods can be used to execute each separated statement:

FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:databasePath];
NSString *batchStatement = @"insert into ftest values ('hello;');"
                           @"insert into ftest values ('hi;');"
                           @"insert into ftest values ('not h!\\\\');"
                           @"insert into ftest values ('definitely not h!')";
NSArray *statements = [[FMSQLStatementSplitter sharedInstance] statementsFromBatchSqlStatement:batchStatement];
[queue inDatabase:^(FMDatabase *adb) {
    for (FMSplittedStatement *sqlittedStatement in statements)
    {
        [adb executeUpdate:sqlittedStatement.statementString];
    }
}];
...