iOS SQLite3轻量开发框架

最近做一款app,使用到了Sqlite3数据库,ios上的sqlite都是可移植的c语言代码,但是使用起来不像java或者php那么方便,打算尝试一下realm,但是由于项目代码要求支持SQL,因此只能使用SQLite3了。

封装后的功能如下功能

  1. 增删改查

  2. 支持批量插入,删除,修改

  3. 支持事务(需要手动开启关闭,begin,commit,rollback)

  4. 支持获取表信息,表结构,表字段,支持获取受影响的函数,支持检索数据库是否存在

  5. 支持自行创建数据库,删除数据库

看代码

在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


转载于:https://my.oschina.net/ososchina/blog/659104

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值