やっと、バインド変数ではなく、動的にSQL文を実行することに成功したので、ソースを紹介します。
//TestTable.h
#import <Foundation/Foundation.h> #import <sqlite3.h> @interface TestTable : NSObject { sqlite3 *db; NSString *dbPath; NSArray *columnNames; NSString *tableName; } @property sqlite3 *db; @property (retain,nonatomic) NSString *dbPath; @property (retain,nonatomic) NSArray *columnNames; @property (retain,nonatomic) NSString *tableName; -(id)init; -(BOOL)openDataBase; -(BOOL)createTable; -(BOOL)insertData; -(void)closeDataBase; -(void)errDataBase; @end |
//TestTable.m
#import "TestTable.h" @implementation TestTable @synthesize db; @synthesize dbPath; @synthesize columnNames; @synthesize tableName; @synthesize columnDatum; -(id)init{ self = [super init]; tableName = @"test"; columnNames = [[NSArray alloc] initWithObjects: @"column_no1" , @"column_no2" , @"column_no3" , nil ]; //dbが存在しているかどうかの確認 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); dbPath = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"test.db"]; //ファイルが存在しない場合 if (![[NSFileManager defaultManager] fileExistsAtPath:dbPath]) { //ファイルを作成する BOOL result = [[NSFileManager defaultManager] createFileAtPath:dbPath contents:nil attributes:nil]; //ファイル作成が失敗した場合 if (!result) { } //sqliteをオープンする if([self openDataBase]){ //テーブルの作成 [self createTable]; //テーブルのクローズ [self closeDataBase]; } } if([self openDataBase]){ //データを登録 [self insertData]; //テーブルのクローズ [self closeDataBase]; } return self; } //sqliteをオープンする -(BOOL)openDataBase{ int ret; ret = sqlite3_open([dbPath UTF8String],&db); //正常終了 if(ret == SQLITE_OK){ return YES; //異常終了 }else { //エラーが発生してしまったので、クローズを行う sqlite3_close(db); return NO; } } //tableの作成 -(BOOL)createTable{ //sqlの設定 NSMutableString *createsql = [NSMutableString string]; [createsql appendString:@"CREATE TABLE "]; [createsql appendString:tableName]; [createsql appendString:@"("]; for (NSUInteger i=0; i< [columnNames count]; i++) { [createsql appendString:((i>0)?@",":@"")]; [createsql appendString:[columnNames objectAtIndex:i]]; } [createsql appendString:@")"]; //各関数の戻り値 int ret; //sql文を実行するための変数 sqlite3_stmt *sqlstmt; ret = sqlite3_prepare_v2(db,[createsql UTF8String],-1,&sqlstmt,NULL); //実行準備おk if(ret == SQLITE_OK){ //sqlの実行を行う ret = sqlite3_step(sqlstmt); //sql文の解放 sqlite3_finalize(sqlstmt); //sqlの実行が正常終了した場合 if(ret == SQLITE_DONE){ return YES; } } //エラーメセッドをコール [self errDataBase]; //dbクローズ [self closeDataBase]; return NO; } -(BOOL)insertData{ NSArray *tmpArray = [[NSArray alloc] initWithObjects:@"test_01" , @"test_02" , @"test_03" , @"test_04" , nil ]; BOOL q_Ret = NO; //各関数の戻り値 int ret; //トランザクションの開始 sqlite3_exec(db, "BEGIN TRANSACTION", NULL, NULL, NULL); //insert文の作成 sqlite3_stmt* sqlstmt; NSMutableString *inssql = [NSMutableString string]; [inssql appendString:@"insert into "]; [inssql appendString:tableName]; [inssql appendString:@"("]; for (NSUInteger i=0; i<[columnNames count]; i++) { [inssql appendString:((i>0)?@",":@"")]; [inssql appendString:[columnNames objectAtIndex:i]]; } [inssql appendString:@")values("]; for (NSUInteger i=0; i<[columnNames count]; i++) { [inssql appendString:((i>0)?@",":@"")]; [inssql appendString:@"?"]; } [inssql appendString:@")"]; ret = sqlite3_prepare_v2(db, [inssql UTF8String], -1, &sqlstmt, NULL); //構文解析の結果問題なし(バインド前) if (ret == SQLITE_OK) { for (NSUInteger tmp=1; tmp<3; tmp++) { //sqlをリセット sqlite3_reset(sqlstmt); //バインド変数をクリアー sqlite3_clear_bindings(sqlstmt); sqlite3_bind_text(sqlstmt,1,[[tmpArray objectAtIndex:(tmp-1)] UTF8String],-1,SQLITE_TRANSIENT); sqlite3_bind_text(sqlstmt,2,[[tmpArray objectAtIndex:tmp] UTF8String],-1,SQLITE_TRANSIENT); sqlite3_bind_text(sqlstmt,3,[[tmpArray objectAtIndex:(tmp+1)] UTF8String],-1,SQLITE_TRANSIENT); //sql文を実行 ret = sqlite3_step(sqlstmt); //一回でもエラーが発生した場合はクローズさせて終了 if(ret != SQLITE_DONE){ //sql文の解放 sqlite3_finalize(sqlstmt); //異常終了(ROLLBACKして処理を終了) sqlite3_exec(db, "ROLLBACK TRANSACTION", NULL, NULL, NULL); //エラーメソッドをコール [self errDataBase]; //dbをクローズ [self closeDataBase]; return q_Ret; } } //正常終了(COMMITをして処理を終了) sqlite3_exec(db, "COMMIT TRANSACTION", NULL, NULL, NULL); q_Ret = YES; //構文解析の結果問題あり(バインド前) }else { //エラーメソッドをコール [self errDataBase]; //異常終了(ROLLBACKして処理を終了) sqlite3_exec(db, "ROLLBACK TRANSACTION", NULL, NULL, NULL); } //sql文の解放 sqlite3_finalize(sqlstmt); //クローズ [self closeDataBase]; return q_Ret; } //sqliteをクローズする -(void)closeDataBase{ sqlite3_close(db); } //sqliteのエラー処理 -(void)errDataBase{ UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:[[NSString alloc] initWithFormat:@"error:%d",sqlite3_errcode(db)] message:[[NSString alloc] initWithUTF8String:sqlite3_errmsg(db)] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil ]; [alertView show]; [alertView release]; } @end |
NSArrayとNSStringクラスを使ってそれぞれカラム名とテーブル名をセットした後、createTableメソッドでテーブルを作成し、insertDataでデータの登録をしています。
かつinitメソッドで設定しているので、initメソッドを拡張させることで、インスタンス変数宣言時に、これらの変数をもっていくことができます。
ただ唯一気になったのが、sqlite3_prepare_v2の第二引数にchar型のsql文を叩き込むのですが、NSMutableStringでセットした変数を一度、char型変数にセットするとコンパイル時に警告がでちゃうんですよね〜。
なぜだろう???
ちなみに、上記を実行した結果、正常終了しました。
ここまでくると、iPad版のObjectBrowser的なものを作りたくなってきた。
ただ、やはり、INSERT文発行時に、登録対象となるデータをインスタンス変数に設定したいなー。
getterとsetterを使ってインスタンス変数経由で、うまくできないものだろうか?
NSDictionaryとNSArrayを使ってどうにかならないものかなーっと想定しているのだが。
0 コメント:
コメントを投稿