2010/06/23

[objective-c][iPad][sqlite]INSERT文の発行その1

何回かエントリーが分かれそうな気がしたので。

やっとできたINSERT文の方法について書いていきたいと思います。
と同時に、CREATE文やオープン、クローズの作業をメソッド化させて、前回よりも、綺麗に整いました。

//TestTable.h

#import <Foundation/Foundation.h>
#import <sqlite3.h>

@interface TestTable : NSObject {
sqlite3 *db;
NSString *dbPath;
}

@property sqlite3 *db;
@property (retain,nonatomic) NSString *dbPath;

-(id)init;
-(BOOL)openDataBase;
-(BOOL)createTable;
-(BOOL)insertData;
-(void)closeDataBase;
-(void)errDataBase;
@end

//TestTable.m
#import "TestTable.h"


@implementation TestTable

@synthesize db;
@synthesize dbPath;

-(id)init{
self = [super init];

//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) {

}
//BOOL sql_exec_ok = NO;
//sqliteをオープンする
if([self openDataBase]){
//テーブルの作成
if ([self createTable]) {
if([self insertData]){
NSLog(@"正常終了しました。");
}
};

//テーブルのクローズ
[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の設定
char *sql = "CREATE TABLE test(column_no1,column_no2)";
//各関数の戻り値
int ret;
//sql文を実行するための変数
sqlite3_stmt *sqlstmt;

ret = sqlite3_prepare_v2(db,sql,-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{
BOOL q_Ret = NO;

//各関数の戻り値
int ret;

//トランザクションの開始
sqlite3_exec(db, "BEGIN TRANSACTION", NULL, NULL, NULL);

//insert文の作成
char *sql = "insert into test(column_no1,column_no2)values('こんばんわ','abcdef')";
ret = sqlite3_exec(db, sql, NULL, NULL, NULL);
//正常終了(COMMITをして処理を終了)
if(ret == SQLITE_OK){
//COMMIT
sqlite3_exec(db, "COMMIT TRANSACTION", NULL, NULL, NULL);
q_Ret = YES;
//異常終了(ROLLBACKして処理を終了)
}else {
//エラーメセッドをコール
[self errDataBase];
//ROLLBACK
sqlite3_exec(db, "ROLLBACK TRANSACTION", NULL, NULL, NULL);
}

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

それぞれのメソッドは、
openDataBaseメソッド:dbのオープン
closeDataBaseメソッド:dbのクローズ
errDataBaseメソッド:エラーメッセージをアラートで表示
createTableメソッド:TABLEの作成
insertDataメソッド:TABLEにデータを登録する
です。
twitterでもつぶやきましたが、トランザクションの書き方に時間をくいました。
こうして各作業をメソッド化することで汎用性が高まるのかなと。

ただ気に食わない部分もあり、特にINSERT文のvalues以降を動的に変更することがこの書き方ではできないこと。

for文でまわしながらそういった作業をすることが多いんだけど。もっと改良する点があるのかなと。

後、CREATE文を実行する時も、カラム名やテーブル名を直指定してしまっていること。

引数を元に、動的にTABLEを作りたい場合などには、融通が利かない。

もっと汎用的に変えていきたいと思います。

実行した結果についてですが、正常終了しました。
(ターミナルでも確認済み)

参考:
rktSQLite2:トランザクションの操作
SQLite Tutorial - Adding data

0 コメント:

コメントを投稿