最近做一款app,使用到了Sqlite3数据库,ios上的sqlite都是可移植的c语言代码,但是使用起来不像java或者php那么方便,打算尝试一下realm,但是由于项目代码要求支持SQL,因此只能使用SQLite3了。
封装后的功能如下功能
增删改查
支持批量插入,删除,修改
支持事务(需要手动开启关闭,begin,commit,rollback)
支持获取表信息,表结构,表字段,支持获取受影响的函数,支持检索数据库是否存在
支持自行创建数据库,删除数据库
看代码
在iOS中,NSDictionary是有序的,而且通过字典取得的key值顺序和遍历出的顺序不一致,是一个很大的坑,因此我们需要先定义一个无序的字典SparseDictionary,来防止我们预编译时键值错位
SparseDictionary.h
#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