8

iPhoneでSQLiteデータベースを作成するためにFMDBを使用しています。次の形式の initial.sql があります。

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

ファイルを NSString にロードして実行することで、これをロードします

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

[db executeUpdate: str];

これは成功しますが、後で失敗します:

no such table: Def

2 番目のステートメントが呼び出されていないことは明らかです。すべてのクエリが呼び出されるようにするにはどうすればよいですか?

SQLite のドキュメントによると、「ルーチン sqlite3_prepare_v2()、sqlite3_prepare()、sqlite3_prepare16()、sqlite3_prepare16_v2()、sqlite3_exec()、および sqlite3_get_table() は、セミコロンである SQL ステートメント リスト (sql-stmt-list) を受け入れます。ステートメントの分離されたリスト。」

したがって、これはすべて機能するはずです。

4

3 に答える 3

8

私もこれに噛まれました。FMDatabase を調べて sqlite3 API ドキュメントを読んで、それを見つけるのに丸一日かかりました。問題の根本的な原因についてはまだ完全にはわかりませんが、PHP のこのバグによると、sqlite3_prepare_v2 でステートメントを準備してから sqlite3_step を呼び出すのではなく、sqlite3_execを呼び出す必要があります。

ドキュメントは、この動作が発生することを示唆していないようです。したがって、私たちは混乱しています。sqlite の経験が豊富な人に、いくつかの仮説を提案してもらいたいと思います。

クエリのバッチを実行する方法を開発することで、これを解決しました。以下のコードを見つけてください。必要に応じて、呼び出しである FMDatabase.h に追加するだけでなく、これをカテゴリに書き直すこともできます。

これを FMDatabase.h の FMDatabase インターフェイスに追加します。

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

これを FMDatabase.m の FMDatabase 実装に追加します。

- (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 には多くの機能が欠けているため、多くの目的には適さないことに注意してください。具体的には、データベースがロックされているかどうかを確認したり、FMDatabase 自体がロックされていないことを確認したり、ステートメントのキャッシュをサポートしたりしません。

それが必要な場合、上記は自分でコーディングするための良い出発点です。ハッピーハッキング!

于 2011-11-18T10:47:41.330 に答える
2
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];
    }
}];
于 2014-04-21T12:56:55.720 に答える