最近作一款app,使用到了Sqlite3數據庫,ios上的sqlite都是可移植的c語言代碼,可是使用起來不像java或者php那麼方便,打算嘗試一下realm,可是因爲項目代碼要求支持SQL,所以只能使用SQLite3了。
php
封裝後的功能以下功能
java
增刪改查ios
支持批量插入,刪除,修改sql
支持事務(須要手動開啓關閉,begin,commit,rollback)數據庫
支持獲取表信息,表結構,表字段,支持獲取受影響的函數,支持檢索數據庫是否存在數組
支持自行建立數據庫,刪除數據庫app
看代碼
函數
在iOS中,NSDictionary是有序的,並且經過字典取得的key值順序和遍歷出的順序不一致,是一個很大的坑,所以咱們須要先定義一個無序的字典SparseDictionary,來防止咱們預編譯時鍵值錯位fetch
SparseDictionary.hatom
#import <Foundation/Foundation.h> @interface SparseDictionary : NSObject -(instancetype) init; +(instancetype)initWidthDictionary:(NSDictionary *) dict; -(void) addEntryDictonary:(NSDictionary *) dict; -(void) putValue:(NSObject *) value Key:(NSObject *)key; -(NSObject *) getValueOfKey:(NSObject *)key; -(NSArray *) keys; -(NSArray *) values; -(NSObject *) keyAtIndex:(NSInteger) index; -(NSObject *) valueAtIndex:(NSInteger) index; -(NSInteger) indexOfKey:(NSObject *) value; -(NSInteger) indexOfValue:(NSObject *) value; -(NSObject *) remove:(NSObject *) key; -(NSObject *) deleteAtIndex:(NSInteger ) index; -(NSInteger) size; -(void) clear; @end;
SparseDictonary.m
#import "SparseDictionary.h" @interface SparseDictionary() @property (nonatomic,strong,readonly) NSMutableArray * keysOfArray; @property (nonatomic,strong,readonly) NSMutableArray * valuesOfArray; @end @implementation SparseDictionary -(instancetype) init{ self = [super init]; if(self) { _keysOfArray = [NSMutableArray array]; _valuesOfArray = [NSMutableArray array]; } return self; } +(instancetype)initWidthDictionary:(NSDictionary *) dict { SparseDictionary * instance = [[SparseDictionary alloc] init]; if(instance) { if(dict!=nil) { for(NSObject * key in dict.allKeys) { [instance putValue:dict[key] Key:key]; } } } return instance; } -(void) addEntryDictonary:(NSDictionary *) dict { if(dict!=nil) { for(NSObject * key in dict.allKeys) { [self putValue:dict[key] Key:key]; } } } -(void) putValue:(NSObject *) value Key:(NSObject *)key { if([_keysOfArray indexOfObject:key]==NSNotFound) { [_keysOfArray addObject:key]; } if([_keysOfArray indexOfObject:key]<_valuesOfArray.count) { [_valuesOfArray removeObjectAtIndex:[_keysOfArray indexOfObject:key]]; [_valuesOfArray insertObject:value atIndex:[_keysOfArray indexOfObject:key]]; }else{ [ _valuesOfArray addObject:value]; } } -(NSObject *) getValueOfKey:(NSObject *)key{ if([_keysOfArray indexOfObject:key]==NSNotFound) { return nil; } return [_valuesOfArray objectAtIndex:[_keysOfArray indexOfObject:key]]; } -(NSArray *) keys { return [_keysOfArray copy]; } -(NSArray *) values { return [_valuesOfArray copy]; } -(NSObject *) keyAtIndex:(NSInteger) index { return _keysOfArray[index]; } -(NSObject *) valueAtIndex:(NSInteger) index{ return _valuesOfArray[index]; } -(NSInteger) indexOfKey:(NSObject *) key{ return [_keysOfArray indexOfObject:key]; } -(NSInteger) indexOfValue:(NSObject *) value { return [_valuesOfArray indexOfObject:value]; } -(NSObject *) remove:(NSObject *) key { NSObject * value = nil; if([_keysOfArray indexOfObject:key]!=NSNotFound) { NSInteger index = [_keysOfArray indexOfObject:key]; value = [self getValueOfKey:key]; [_keysOfArray removeObjectAtIndex:index]; [_valuesOfArray removeObjectAtIndex:index]; } return value; } -(NSInteger) size { return _keysOfArray.count; } -(NSObject *) deleteAtIndex:(NSInteger ) index { NSObject * key = [self keyAtIndex: index]; NSObject * value = nil; if(key!=nil) { value = [self getValueOfKey:key]; [_keysOfArray removeObjectAtIndex:index]; [_valuesOfArray removeObjectAtIndex:index]; } return value; } -(void) clear { [_keysOfArray removeAllObjects]; [_valuesOfArray removeAllObjects]; } -(NSString *) description{ NSString * desc = @"(\n"; for(int i=0;i<_keysOfArray.count;i++) { if(i<(_keysOfArray.count-1)) { desc = [desc stringByAppendingString:[NSString stringWithFormat:@"%@=%@,\n",_keysOfArray[i],_valuesOfArray[i]]]; }else{ desc = [desc stringByAppendingString:[NSString stringWithFormat:@"%@=%@\n",_keysOfArray[i],_valuesOfArray[i]]]; } } desc = [desc stringByAppendingString:@")\n"]; return desc; } -(void) dealloc { [self clear]; } @end
SqliteDatabase.h
#import <Foundation/Foundation.h> #import "SparseDictonary.h" #include <sqlite3.h> @interface SqliteDatabase : NSObject +(instancetype) shareInstance; -(BOOL)createDatabase:(NSString *) dbPath; /* * *初始化 */ -(BOOL)openDatabase:(NSString *) dbPath; /** * 打開默認數據庫 */ -(BOOL)openDefaultDatabase; //開啓事務 -(BOOL) beginTransaction:(NSString *) dbPath; //提交事務 -(BOOL) commitTransaction:(NSString *) dbPath; //回滾事務 -(BOOL) rollbackTransaction:(NSString *) dbPath; //開啓默認數據庫事務 -(BOOL) beginTransaction; //提交默認數據庫事務 -(BOOL) commitTransaction; //回滾默認數據庫事務 -(BOOL) rollbackTransaction; /** * @brief 執行非查詢sql * * @param sql - sql語句 */ - (void)executeUpdate:(NSString *)sql fromDatabase:(NSString *) dbPath; //默認數據庫 - (void)executeUpdate:(NSString *)sql; /** * @brief 執行查詢sql * * @param sql - sql語句 * * @return 返回查詢的數據 */ - (NSArray *)query:(NSString *) sql fromDatabase:(NSString *)dbPath; //默認數據庫 - (NSArray *)query:(NSString *) sql; /** * * 關閉數據庫 */ - (void)closeAllDatabase; /** * * 關閉指定的數據庫 */ -(void)closeDatabase:(NSString *)dbPath; -(void) closeDefaultDatabase; /** * *檢查數據表是否存在 */ -(BOOL)isExistTable:(NSString *)tableName fromDatabase:(NSString *) dbPath; //默認數據庫 -(BOOL)isExistTable:(NSString *)tableName; /* * *刪除數據庫 * */ -(void) deleteDatabase:(NSString *) dbPath; /** * * 刪除表 * */ -(void) dropTable:(NSString *) tableName fromDatabase:(NSString *)dbPath; //默認數據庫 -(void) dropTable:(NSString *) tableName; /** * 判斷是否Base64字符串 */ +(BOOL)isBase64String:(NSString *)src; /** * *獲取表字段信息 */ -(NSArray *)fetchFieldsInfo:(NSString *) tableName fromDatabase:(NSString *)dbPath; //默認數據庫 -(NSArray *)fetchFieldsInfo:(NSString *) tableName; /** * *獲取表字段名稱 */ -(NSArray *)fetchFieldsName:(NSString *) tableName fromDatabase:(NSString *)dbPath; //默認數據庫 -(NSArray *)fetchFieldsName:(NSString *) tableName; //獲取受影響的函數 -(int) fetchNumberOfAffectedRows:(NSString *)dbPath; //默認數據庫 -(int) fetchNumberOfAffectedRows; /** * 數據插入 *{}----------普通字典 */ - (void)insertTable:(NSString *)tableName tableData:(NSDictionary *) dict fromDatabase:(NSString *) dbPath; //默認數據庫 - (void)insertTable:(NSString *)tableName tableData:(NSDictionary *) dict; /** * 批量插入 */ - (void)insertTable:(NSString *)tableName fields:(NSArray *) fields values:(NSArray *) values fromDatabase:(NSString *) dbPath; - (void)insertTable:(NSString *)tableName fields:(NSArray *) fields values:(NSArray *) values; /****過濾特殊字符****/ +(NSString *)sqlEscape:(NSString *)source; @end
SqliteDatabase.m
#import "SqliteDatabase.h" @interface DBInfo : NSObject @property(nonatomic,strong) NSString * dbPath; @property(nonatomic,assign) sqlite3 * db; @property(nonatomic,strong) NSString * dbName; @property(nonatomic,assign) BOOL isOpened; @property(nonatomic,assign) BOOL isOpenedTransaction; -(instancetype) initWidthDBName:(NSString *) path forSQLite:(sqlite3 *) db; @end @implementation DBInfo -(instancetype) initWidthDBName:(NSString *) path forSQLite:(sqlite3 *) db { self = [super init]; if(self) { _dbPath = path; _db = db; _dbName = [path lastPathComponent]; _isOpened = NO; _isOpenedTransaction = NO; } return self; } @end @interface SqliteDatabase() -(instancetype) init; @property(nonatomic,strong) NSMutableDictionary * sqliteDBInfos; @property(nonatomic,strong) NSString * defaultDBPath; -(void) createDefaultDatabase; -(void) deleteDefaultDatabase; @end @implementation SqliteDatabase -(instancetype) init { self = [super init]; if(self!=nil) { _sqliteDBInfos = [NSMutableDictionary dictionary]; sqlite3_initialize(); [self performSelector:@selector(createDefaultDatabase) withObject:nil]; } return self; } -(void) createDefaultDatabase { NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString * dbPath = [path[0] stringByAppendingPathComponent:@"Databases"]; if(![[NSFileManager defaultManager] fileExistsAtPath:dbPath]) { NSError * error; [[NSFileManager defaultManager] createDirectoryAtPath:dbPath withIntermediateDirectories:YES attributes:nil error:&error]; } _defaultDBPath = [dbPath stringByAppendingPathComponent:@"default_local_db_storage.sqlite3"]; [self createDatabase:_defaultDBPath]; } +(instancetype) shareInstance { static SqliteDatabase * instance; static dispatch_once_t onceToken = 0; dispatch_once(&onceToken, ^(void){ instance = [[SqliteDatabase alloc] init]; }); return instance; } - (BOOL)createDatabase:(NSString *) nsFile { sqlite3 * db; const char *filename = [nsFile UTF8String]; int rc = sqlite3_open_v2(filename, &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL ); if (rc != SQLITE_OK) { NSLog(@"數據庫建立失敗"); return NO; } if(db!=NULL) { sqlite3_close(db); } NSLog(@"數據庫建立成功,位置:%@",nsFile); return YES; } -(BOOL) openDatabase:(NSString *) nsFile { sqlite3 * db; DBInfo * dbInfo = _sqliteDBInfos[[nsFile lastPathComponent]]; if(dbInfo!=nil && dbInfo.isOpened && dbInfo.db!=NULL) { sqlite3_close(dbInfo.db); dbInfo.db = NULL; NSLog(@"從新打開數據庫"); } const char *filename = [nsFile UTF8String]; int rc = sqlite3_open_v2(filename, &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL ); if (rc != SQLITE_OK) { if(db!=NULL) { sqlite3_close(db); } NSLog(@"數據庫打開失敗"); return NO; } if(dbInfo==nil) { dbInfo = [[DBInfo alloc] initWidthDBName:nsFile forSQLite:db]; }else{ dbInfo.db = db; } [_sqliteDBInfos setObject:dbInfo forKey:[nsFile lastPathComponent]]; dbInfo.isOpened = YES; return YES; } -(BOOL) openDefaultDatabase { return [self openDatabase:_defaultDBPath]; } -(BOOL) beginTransaction:(NSString *) dbPath { DBInfo * dbInfo = _sqliteDBInfos[[dbPath lastPathComponent]]; char *errorMsg; NSException *exception = nil; if(dbInfo==nil) { exception = [NSException exceptionWithName:@"NotFound" reason:@"數據庫不存在" userInfo:nil]; @throw exception; } if(!dbInfo.isOpened) { //防止誤操做,這裏建議開始打開數據庫,開啓事務 [self openDatabase:dbPath]; } if(dbInfo.isOpenedTransaction) { NSLog(@"事務已經開啓,無需重複開啓!"); return YES; } if (sqlite3_exec(dbInfo.db, "BEGIN", NULL, NULL, &errorMsg)!=SQLITE_OK) { if (errorMsg != NULL) { sqlite3_free(errorMsg); NSString *msg = [[NSString stringWithFormat:@"error=%s\nSQL=",errorMsg] stringByAppendingString:@"Begin Transaction"]; exception = [NSException exceptionWithName:@"ExectueError" reason:msg userInfo:nil]; @throw exception; } NSLog(@"事務開啓失敗"); return NO; } NSLog(@"事務成功開啓"); dbInfo.isOpenedTransaction = YES; return YES; } -(BOOL) beginTransaction { return [self beginTransaction:_defaultDBPath]; } -(BOOL) commitTransaction:(NSString *) dbPath { DBInfo * dbInfo = _sqliteDBInfos[[dbPath lastPathComponent]]; char *errorMsg; NSException *exception = nil; if(dbInfo==nil) { exception = [NSException exceptionWithName:@"NotFound" reason:@"數據庫不存在" userInfo:nil]; @throw exception; } if(!dbInfo.isOpened) { NSLog(@"數據庫未打開,沒有事務"); return YES; } if(!dbInfo.isOpenedTransaction) { NSLog(@"數據庫未開啓事務,無需Commit"); return YES;//事務操做未開啓 } if (sqlite3_exec(dbInfo.db, "COMMIT", NULL, NULL, &errorMsg)!=SQLITE_OK) { if (errorMsg != NULL) { sqlite3_free(errorMsg); NSString *msg = [[NSString stringWithFormat:@"error=%s\nSQL=",errorMsg] stringByAppendingString:@"COMMIT Transaction"]; exception = [NSException exceptionWithName:@"ExectueError" reason:msg userInfo:nil]; @throw exception; } NSLog(@"數據庫Commit失敗"); return NO; } NSLog(@"數據庫Commit成功"); dbInfo.isOpenedTransaction = NO; return YES; } -(BOOL) commitTransaction { return [self commitTransaction:_defaultDBPath]; } -(BOOL) rollbackTransaction:(NSString *) dbPath { DBInfo * dbInfo = _sqliteDBInfos[[dbPath lastPathComponent]]; char *errorMsg; NSException *exception = nil; if(dbInfo==nil) { exception = [NSException exceptionWithName:@"NotFound" reason:@"數據庫不存在" userInfo:nil]; @throw exception; } if(!dbInfo.isOpened) { NSLog(@"數據庫未打開,沒有事務"); return YES; } if(!dbInfo.isOpenedTransaction) { NSLog(@"數據庫未開啓事務,無需回滾"); return YES;//事務操做未開啓 } if (sqlite3_exec(dbInfo.db, "ROLLBACK", NULL, NULL, &errorMsg)!=SQLITE_OK) { if (errorMsg != NULL) { sqlite3_free(errorMsg); NSString *msg = [[NSString stringWithFormat:@"error=%s\nSQL=",errorMsg] stringByAppendingString:@"COMMIT Transaction"]; exception = [NSException exceptionWithName:@"ExectueError" reason:msg userInfo:nil]; @throw exception; } NSLog(@"數據庫事務回滾失敗"); return NO; } NSLog(@"數據庫事務回滾成功"); dbInfo.isOpenedTransaction = NO; return YES; } -(BOOL) rollbackTransaction { return [self rollbackTransaction:_defaultDBPath]; } /** *@brief執行非查詢sql * *@param sql - sql語句 */ - (void)executeUpdate:(NSString *)sql fromDatabase:(NSString *) dbPath; { @synchronized(self) { char *errMsg; NSException *exception = nil; DBInfo * dbInfo = _sqliteDBInfos[[dbPath lastPathComponent]]; if(dbInfo==nil) { exception = [NSException exceptionWithName:@"NotFound" reason:@"數據庫未開啓" userInfo:nil]; @throw exception; } if(!dbInfo.isOpened) { [self openDatabase:dbPath]; } if(sqlite3_exec(dbInfo.db, [sql UTF8String],NULL,NULL,&errMsg) != SQLITE_OK) { if (errMsg != NULL) { NSString *msg = [[NSString stringWithFormat:@"error=%s\nSQL=",errMsg] stringByAppendingString:sql]; exception = [NSException exceptionWithName:@"ExectueError" reason:msg userInfo:nil]; sqlite3_free(errMsg); } } if (exception != nil) { @throw exception; }else{ NSLog(@"執行成功:%@",sql); } } } - (void)executeUpdate:(NSString *)sql { [self executeUpdate:sql fromDatabase:_defaultDBPath]; } - (void)insertTable:(NSString *)tableName tableData:(NSDictionary *) dict fromDatabase:(NSString *) dbPath { if(dict==nil || dict.count==0) { return; } @synchronized(self) { NSException *exception = nil; DBInfo * dbInfo = _sqliteDBInfos[[dbPath lastPathComponent]]; if(dbInfo==nil) { exception = [NSException exceptionWithName:@"NotFound" reason:@"數據庫未開啓" userInfo:nil]; @throw exception; } NSArray * columns = [self fetchFieldsName:tableName fromDatabase:dbPath]; SparseDictionary * keyValueEntry = [SparseDictionary initWidthDictionary:dict]; //防止字典排序,使用無序的SparseDictionary for (NSString *key in keyValueEntry.keys) { if([columns indexOfObject:key]==NSNotFound) { exception = [NSException exceptionWithName:@"ErrorFields" reason:[@"不存在的字段>>" stringByAppendingString:key] userInfo:nil]; @throw exception; } } if(!dbInfo.isOpened) { [self openDatabase:dbPath]; } NSString *sql = [NSString stringWithFormat: @"INSERT INTO %@( ",tableName]; NSString *values = @" values ("; for(NSString * key in keyValueEntry.keys) { if(![key isEqualToString:dict.allKeys.lastObject]) { sql = [sql stringByAppendingString:[NSString stringWithFormat:@" '%@' ,",key]]; values = [values stringByAppendingString:@" ? ,"]; }else{ sql = [sql stringByAppendingString:[NSString stringWithFormat:@" '%@' ) ",key]]; values = [values stringByAppendingString:@" ? );"]; } } sql = [NSString stringWithFormat:@"%@ %@",sql,values]; sqlite3_stmt *stmt; if (sqlite3_prepare_v2(dbInfo.db, [sql UTF8String], -1, &stmt, NULL) == SQLITE_OK) { NSArray * fieldsInfos = [self fetchFieldsInfo:tableName fromDatabase:dbPath]; [self bindToStatement:stmt values:keyValueEntry useFieldsInfo:fieldsInfos forDepth:0]; if (sqlite3_step(stmt) != SQLITE_DONE) { const char * errorMSG = sqlite3_errmsg(dbInfo.db); int errorCode = sqlite3_errcode(dbInfo.db); NSString *msg = [[NSString stringWithFormat:@"errorCode=%d,error=%s\nSQL=",errorCode,errorMSG] stringByAppendingString:sql]; exception = [NSException exceptionWithName:@"執行sql錯誤" reason:msg userInfo:nil]; sqlite3_free(&errorMSG); } }else{ NSLog(@"插入數據錯誤"); const char * errorMSG = sqlite3_errmsg(dbInfo.db); int errorCode = sqlite3_errcode(dbInfo.db); NSString *msg = [[NSString stringWithFormat:@"errorCode=%d,error=%s\nSQL=",errorCode,errorMSG] stringByAppendingString:sql]; exception = [NSException exceptionWithName:@"執行sql錯誤" reason:msg userInfo:nil]; sqlite3_free(&errorMSG); } if(stmt!=NULL) { sqlite3_finalize(stmt); } if(exception!=nil) { @throw exception; } } } /** * 批量插入 * * NSArray<NSString> fields 是一維數組,爲了防止錯誤插入,這裏filed不容許默認空缺 * NSArray<NSArray> values 是二維數組,而且每一維數組的長度必須相同,不然可能引發致命錯誤 * */ - (void)insertTable:(NSString *)tableName fields:(NSArray *) fields values:(NSArray *) values fromDatabase:(NSString *) dbPath { if(fields == nil || fields.count==0 || values==nil || values.count==0) { return; } @synchronized(self) { NSException *exception = nil; DBInfo * dbInfo = _sqliteDBInfos[[dbPath lastPathComponent]]; if(dbInfo==nil) { exception = [NSException exceptionWithName:@"NotFound" reason:@"數據庫未開啓" userInfo:nil]; @throw exception; } NSArray * columns = [self fetchFieldsName:tableName fromDatabase:dbPath]; for (NSString *key in fields) { if([columns indexOfObject:key]==NSNotFound) { exception = [NSException exceptionWithName:@"ErrorFields" reason:[@"不存在的字段>>" stringByAppendingString:key] userInfo:nil]; @throw exception; } } if(!dbInfo.isOpened) { [self openDatabase:dbPath]; } NSString *sql = [NSString stringWithFormat: @"INSERT INTO %@( ",tableName]; NSString * valueStr = @" values"; for (NSString *key in fields) { if(![key isEqualToString:fields.lastObject]) { sql = [sql stringByAppendingString:[NSString stringWithFormat:@" '%@' ,",key]]; }else{ sql = [sql stringByAppendingString:[NSString stringWithFormat:@" '%@' )",key]]; } } NSMutableArray * dataArrayDict = [NSMutableArray array]; SparseDictionary * keyValueSparseDict = nil; for (int i=0;i<values.count;i++) { valueStr = [valueStr stringByAppendingString:@" ("]; keyValueSparseDict = [[SparseDictionary alloc] init]; for (int j=0;j<fields.count;j++) { if(j<fields.count-1) { valueStr = [valueStr stringByAppendingString:@" ?,"]; }else{ valueStr = [valueStr stringByAppendingString:@" ? "]; } [keyValueSparseDict putValue:values[i][j] Key:fields[j]]; } valueStr = [valueStr stringByAppendingString:@")"]; if(i<values.count-1) { valueStr = [valueStr stringByAppendingString:@","]; }else{ valueStr = [valueStr stringByAppendingString:@";"]; } [dataArrayDict addObject:keyValueSparseDict]; } sql = [NSString stringWithFormat:@" %@ %@",sql,valueStr]; sqlite3_stmt *stmt; if (sqlite3_prepare_v2(dbInfo.db, [sql UTF8String], -1, &stmt, NULL) == SQLITE_OK) { NSArray * fieldsInfos = [self fetchFieldsInfo:tableName fromDatabase:dbPath]; int k = 0; for (SparseDictionary * dict in dataArrayDict) { [self bindToStatement:stmt values:dict useFieldsInfo:fieldsInfos forDepth:k]; k++; } if (sqlite3_step(stmt) != SQLITE_DONE) { NSLog(@"插入數據錯誤"); const char * errorMSG = sqlite3_errmsg(dbInfo.db); int errorCode = sqlite3_errcode(dbInfo.db); NSString *msg = [[NSString stringWithFormat:@"errorCode=%d,error=%s\nSQL=",errorCode,errorMSG] stringByAppendingString:sql]; exception = [NSException exceptionWithName:@"執行sql錯誤" reason:msg userInfo:nil]; sqlite3_free(&errorMSG); } }else{ NSLog(@"插入數據錯誤"); const char * errorMSG = sqlite3_errmsg(dbInfo.db); int errorCode = sqlite3_errcode(dbInfo.db); NSString *msg = [[NSString stringWithFormat:@"errorCode=%d,error=%s\nSQL=",errorCode,errorMSG] stringByAppendingString:sql]; exception = [NSException exceptionWithName:@"執行sql錯誤" reason:msg userInfo:nil]; sqlite3_free(&errorMSG); } if(stmt!=NULL) { sqlite3_finalize(stmt); } if(exception!=nil) { @throw exception; } } } -(NSArray *) sortKeyForSQL:(NSArray *) values fields:(NSArray *) fields { if(values==nil || fields==nil) { return fields; } NSMutableDictionary * tempSortDict = [NSMutableDictionary dictionaryWithObjects:values forKeys:fields]; return tempSortDict.allKeys;//進行字典排序,防止key=value與sql語句不對稱問題 } - (void)insertTable:(NSString *)tableName fields:(NSArray *) fields values:(NSArray *) values { [self insertTable:tableName fields:fields values:values fromDatabase:_defaultDBPath]; } - (void)insertTable:(NSString *) tableName tableData:(NSDictionary *) dict { [self insertTable:tableName tableData:dict fromDatabase:_defaultDBPath]; } -(void) bindToStatement:(sqlite3_stmt *)stmt values:(SparseDictionary *) dict useFieldsInfo:(NSArray *) filedsInfo forDepth:(int)depIndex { if(filedsInfo==nil || dict==nil) { return; } NSMutableDictionary *fieldInfoDict = [NSMutableDictionary dictionary]; for (NSDictionary * fieldInfo in filedsInfo) { fieldInfoDict[fieldInfo[@"name"]] = fieldInfo; } for( int i=0;i< [dict size];i++) { NSString * key = [(NSString *)dict.keys[i] lowercaseString]; int index = (int)(i+(depIndex*[dict size]))+1; //數據庫索引從1開始 NSString * fieldType = [fieldInfoDict[key][@"type"] lowercaseString]; NSLog(@"bindIndex=%d,key=%@,value=%@,type=%@",index,key,[dict getValueOfKey:key],fieldType); if([@"integer" isEqualToString:fieldType]||[@"int" isEqualToString:fieldType]||[@"biginteger" isEqualToString:fieldType] || [fieldType hasPrefix:@"int("]) { sqlite3_bind_int(stmt, index, [(NSString *)[dict getValueOfKey:key] intValue]); } else if([@"float" isEqualToString:fieldType]||[@"double" isEqualToString:fieldType]|| [@"real" isEqualToString:fieldType]|| [@"decimal" isEqualToString:fieldType]) { sqlite3_bind_double(stmt, index, [(NSString *)[dict getValueOfKey:key] floatValue]); } else if([@"blob" isEqualToString:fieldType] ) { NSData * data = (NSData *)[dict getValueOfKey:key]; sqlite3_bind_blob(stmt, index, data.bytes, (int)data.length, SQLITE_STATIC); } else if([@"varchar" isEqualToString:fieldType]||[@"text" isEqualToString:fieldType] || [fieldType hasPrefix:@"varchar("]) { NSString * nsSqlText = (NSString *)[dict getValueOfKey:key]; const char* sqlText = [nsSqlText UTF8String]; sqlite3_bind_text(stmt,index, sqlText,-1, SQLITE_STATIC); }else{ sqlite3_value *p = (__bridge sqlite3_value *)[dict getValueOfKey:key]; sqlite3_bind_value(stmt, index,p); } } } -(NSArray *)fetchFieldsName:(NSString *) tableName fromDatabase:(NSString *)dbPath { NSArray * tableFieldsInfo = [self fetchFieldsInfo:tableName fromDatabase:dbPath]; NSMutableArray * tableNameArray = [NSMutableArray array]; if(tableFieldsInfo!=nil) { [tableFieldsInfo enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { if([obj isKindOfClass:[NSDictionary class]]) { [tableNameArray addObject:[obj objectForKey:@"name"]]; } }]; } return tableNameArray; } -(NSArray *)fetchFieldsName:(NSString *) tableName { return [self fetchFieldsName:tableName fromDatabase:_defaultDBPath]; } -(NSArray *)fetchFieldsInfo:(NSString *) tableName fromDatabase:(NSString *)dbPath { NSString * sql = [NSString stringWithFormat:@"PRAGMA TABLE_INFO('%@')",tableName]; NSLog(@"SQL-Lang:%@",sql); NSMutableArray *table = [NSMutableArray array]; @synchronized(self) { sqlite3_stmt *stmt; NSException *exception = nil; DBInfo * dbInfo = _sqliteDBInfos[[dbPath lastPathComponent]]; if(dbInfo==nil) { NSString * exName = [NSString stringWithFormat:@"NotFound"]; exception = [NSException exceptionWithName:exName reason:@"數據庫不存在" userInfo:nil]; @throw exception; } if(!dbInfo.isOpened) { [self openDatabase:dbPath]; } if(sqlite3_prepare_v2(dbInfo.db,[sql UTF8String],-1,&stmt,nil) == SQLITE_OK) { while(sqlite3_step(stmt) == SQLITE_ROW) { @autoreleasepool { int col = sqlite3_column_count(stmt); NSMutableDictionary *row = [NSMutableDictionary dictionary]; for (int i=0; i<col; i++) { id k = [NSString stringWithCString:sqlite3_column_name(stmt,i) encoding:NSUTF8StringEncoding]; id v = [self reloadData:stmt column:i]; [row setObject:v forKey:k]; } [table addObject:row]; } } sqlite3_finalize(stmt); } else { NSString *msg = [[NSString stringWithFormat:@"error=%s\nSQL=",sqlite3_errmsg(dbInfo.db)] stringByAppendingString:sql]; exception = [NSException exceptionWithName:@"執行sql錯誤" reason:msg userInfo:nil]; @throw exception; } } return table; } -(NSArray *)fetchFieldsInfo:(NSString *) tableName { return [self fetchFieldsInfo:tableName fromDatabase:_defaultDBPath]; } /** *@brief執行查詢sql *@param sql - sql語句 * @return 返回查詢的數據 */ - (NSArray *)query:(NSString *) sql fromDatabase:(NSString *)dbPath;{ NSMutableArray *table = [NSMutableArray array]; @synchronized(self) { sqlite3_stmt *stmt; NSException *exception = nil; DBInfo * dbInfo = _sqliteDBInfos[[dbPath lastPathComponent]]; if(sql==nil || sql.length==0) { NSString * exName = [NSString stringWithFormat:@"EmptySQL"]; exception = [NSException exceptionWithName:exName reason:@"sql語句不能爲null" userInfo:nil]; @throw exception; }else{ NSLog(@"SQL-Lang:%@",sql); } if(dbInfo==nil) { NSString * exName = [NSString stringWithFormat:@"NotFound"]; exception = [NSException exceptionWithName:exName reason:@"數據庫不存在" userInfo:nil]; @throw exception; } if(!dbInfo.isOpened) { [self openDatabase:dbPath]; } if(sqlite3_prepare_v2(dbInfo.db,[sql UTF8String],-1,&stmt,nil) == SQLITE_OK) { while(sqlite3_step(stmt) == SQLITE_ROW) { @autoreleasepool { int col = sqlite3_column_count(stmt); NSMutableDictionary *row = [NSMutableDictionary dictionary]; for (int i=0; i<col; i++) { id k = [NSString stringWithCString:sqlite3_column_name(stmt,i) encoding:NSUTF8StringEncoding]; if([@"age" isEqualToString:k]){ } id v = [self reloadData:stmt column:i]; if(v==nil) { v = [self reloadData:stmt column:i]; } [row setObject:v forKey:k]; } [table addObject:row]; } } sqlite3_finalize(stmt); } else { NSString *msg = [[NSString stringWithFormat:@"error=%s\nSQL=",sqlite3_errmsg(dbInfo.db)] stringByAppendingString:sql]; exception = [NSException exceptionWithName:@"執行sql錯誤" reason:msg userInfo:nil]; @throw exception; } } return table; } - (NSArray *)query:(NSString *) sql { return [self query:sql fromDatabase:_defaultDBPath]; } /** * * 按照表類型獲取數據 * */ - (id)reloadData:(sqlite3_stmt *)stmt column:(int)column { id object; switch (sqlite3_column_type(stmt,column)) { case SQLITE_INTEGER: { object = [NSNumber numberWithInt:sqlite3_column_int(stmt,column)]; if(object==nil) { object = [NSNumber numberWithInt:0]; } } break; case SQLITE_FLOAT: { object = [NSNumber numberWithDouble:sqlite3_column_double(stmt,column)]; if(object==nil) { object = [NSNumber numberWithDouble:0.0]; } } break; case SQLITE_BLOB: { object = [NSData dataWithBytes:sqlite3_column_blob(stmt,column) length:sqlite3_column_bytes(stmt,column)]; if(object==nil) { object = [NSNull null]; } } break; case SQLITE_NULL: object = [NSString stringWithFormat:@""]; break; case SQLITE_TEXT: { char * value = (char *) sqlite3_column_text(stmt,column); if(value!=NULL) { object = [NSString stringWithUTF8String:value]; } if(object==nil) { object = @""; } } break; default: sqlite3_value * val = sqlite3_column_value(stmt, column); NSObject * objValue = (__bridge_transfer id)val;//將c對象轉爲OC對象 object = objValue; break; } return object; } - (void)closeAllDatabase { NSArray * keys = [_sqliteDBInfos.allKeys copy]; for(int i=0;keys!=nil &&i<keys.count;i++) { [self closeDatabase:keys[i]]; } } -(void)closeDatabase:(NSString *)dbPath; { DBInfo * dbInfo = _sqliteDBInfos[[dbPath lastPathComponent]]; if(dbInfo!=nil && dbInfo.isOpened && dbInfo.db!=NULL) { sqlite3_close(dbInfo.db); dbInfo.isOpened = NO; dbInfo.isOpenedTransaction = NO; dbInfo.db = NULL; } } -(void) closeDefaultDatabase { [self closeDatabase:_defaultDBPath]; } -(void)dealloc { [self closeAllDatabase]; [_sqliteDBInfos removeAllObjects]; } /** *@brief判斷表是否存在 *@param name 表名字 * @return 返回轉義後的字符串 */ -(BOOL)isExistTable:(NSString *)tableName fromDatabase:(NSString *) dbPath; { char *err; NSString *sql = [NSString stringWithFormat:@"SELECT COUNT(*) FROM sqlite_master where type='table' and name='%@';",tableName]; const char *sql_stmt = [sql UTF8String]; DBInfo * dbInfo = _sqliteDBInfos[[dbPath lastPathComponent]]; if(dbInfo==nil) { return NO; } if(sqlite3_exec(dbInfo.db, sql_stmt, NULL, NULL, &err) == 1){ return YES; }else{ return NO; } } -(BOOL)isExistTable:(NSString *)tableName { return [self isExistTable:tableName fromDatabase:_defaultDBPath]; } -(void) dropTable:(NSString *) tableName fromDatabase:(NSString *)dbPath { NSString * sql = [@"DROP TABLE IF EXISTS " stringByAppendingString:tableName]; [self executeUpdate:sql fromDatabase:dbPath]; } -(void) dropTable:(NSString *) tableName { return [self dropTable:tableName fromDatabase:_defaultDBPath]; } -(void) deleteDatabase:(NSString *) dbPath{ [self closeDatabase:dbPath]; [_sqliteDBInfos removeObjectForKey:[dbPath lastPathComponent]]; if ([[NSFileManager defaultManager]removeItemAtPath:dbPath error:nil]) { NSLog( @"remove: %@", [NSString stringWithFormat:@"%@", dbPath]); } } -(void) deleteDefaultDatabase { return [self deleteDatabase:_defaultDBPath]; } +(BOOL)isBase64String:(NSString *)src { if(src==nil || src.length==0) { return NO; } if(src.length%4!=0) { return NO; } NSString *decodedString = nil; @try { NSData *decodedData = [[NSData alloc] initWithBase64EncodedString:src options:0]; if(decodedData!=nil) { decodedString = [[NSString alloc] initWithData:decodedData encoding:NSUTF8StringEncoding]; } if(decodedString==nil) { @throw [[NSException alloc] initWithName:@"Base64DecodeException" reason:@"Base64Decode 解碼失敗!" userInfo:nil]; } } @catch(NSException *exception) { NSLog(@"exception=%@",exception); return NO; } return YES; } -(int) fetchNumberOfAffectedRows:(NSString *)dbPath { NSException *exception = nil; DBInfo * dbInfo = _sqliteDBInfos[[dbPath lastPathComponent]]; if(dbInfo==nil) { exception = [NSException exceptionWithName:@"NotFound" reason:@"數據庫不存在" userInfo:nil]; @throw exception; } if(!dbInfo.isOpened) { [self openDatabase:dbPath]; } return sqlite3_changes(dbInfo.db); } -(int) fetchNumberOfAffectedRows { return [self fetchNumberOfAffectedRows:_defaultDBPath]; } +(NSString *)sqlEscape:(NSString *)source { if(source==nil || source.length==0) { return source; } static NSDictionary * exludeDict = @{ @"\0":@"", @"\'":@"\\'", @"\"":@"\\\"", @"\n":@" ", @"/":@"\\/", @"\t":@" ", @"\r":@" ", @"%":@"\\%", @"\b":@" ", @"_":@"\\_" }; for (NSString * key in exludeDict.allKeys) { if([source containsString:key]) { source = [source stringByReplacingOccurrencesOfString:key withString:exludeDict[key]]; } } return source; } @end