OC格式化SQL语句函数,提取表名

版权声明:原创文章,未经允许禁止转载! https://blog.csdn.net/mlibai/article/details/47123685

返回值是一个数组:

第一个元素:是查询的table名,如果查询的表不是基本表,返回的是自动创建的临时表名。

第二个元素:是格式化后的sql语句。

NSArray* analyseSQLString(NSString *sqlString, NSInteger page, NSInteger pageSize){
    __block NSString *selftable, *_sql, *sqlString2;
    sqlString2 = sqlString;

    // 格式化SQL语句为,符号前后又空格,逗号前没空格,复合符号间无空格。将字段值存入数组,替换为?
    NSCharacterSet *spaceCharSet = [NSCharacterSet whitespaceAndNewlineCharacterSet];
    NSCharacterSet *symbolCharSet = [NSCharacterSet characterSetWithCharactersInString:@"+-x/><=,"];
    sqlString2 = [[sqlString2 stringByTrimmingCharactersInSet:spaceCharSet] lowercaseString];
    BOOL meetSpaceChar = NO; // 遇到空白字符
    BOOL meetQuoteString = NO; // 上一个是单引号
    BOOL meetSymbolChar = NO;    // 遇到 + - x ÷ > < =
    BOOL meetValueString = NO;
    NSMutableArray *allSqlValues = [NSMutableArray array];
    NSMutableString *tmpSqlString = [NSMutableString string];
    NSMutableString *sqlValueString = [NSMutableString string];

    for (NSInteger i = 0; i < sqlString2.length; i ++) {
        NSString *oneCharString = [sqlString2 substringWithRange:NSMakeRange(i, 1)];
        unichar aChar = [sqlString2 characterAtIndex:i];
        if ([oneCharString isEqualToString:@"'"]) { // 遇到值
            meetValueString = YES;
            i ++; // 跳过当前的 单引号
            while (meetValueString && i < sqlString2.length) {
                oneCharString = [sqlString2 substringWithRange:NSMakeRange(i, 1)];
                aChar = [sqlString2 characterAtIndex:i];
                if ([oneCharString isEqualToString:@"'"]) {
                    if (meetQuoteString) {                // 如果当前是个单引号,且上一个也是单引号,加入单引号
                        [sqlValueString appendString:@"'"];
                        meetQuoteString = NO;
                    }else{
                        if (i == sqlString2.length - 1) { // 是最后一个字符时
                            meetValueString = NO;
                        }else{
                            meetQuoteString = YES;
                        }
                    }
                    i ++;
                }else{
                    if (meetQuoteString) {  // 当前不是单引号,而上一个是单引号,说明值结束了
                        meetValueString = NO;
                        meetQuoteString = NO;
                    }else{
                        [sqlValueString appendString:oneCharString];
                        i ++;
                    }
                }
            } // 以单引号后面第一个字符结束循环 或 sql语句遍历完毕
            if (meetValueString && i == sqlString2.length) { // 循环结束了,没有找到值的结束分号
                NSLog(@"SQL语句不正确。");
                return nil;
            }else{
                [allSqlValues addObject:[sqlValueString copy]];
                [sqlValueString setString:@""];
                if (meetSymbolChar) {
                    [tmpSqlString appendFormat:@" %@", @"?"];
                }else{
                    [tmpSqlString appendString:@"?"];
                }
            }
            meetSpaceChar = NO;
            meetSymbolChar = NO;
        }
        if (i < sqlString2.length) {
            if ([spaceCharSet characterIsMember:aChar]) { // 是空白字符
                if (!meetSpaceChar) { // 上一个不是空白字符
                    if (!meetSymbolChar) { // 上一个不是符号
                        [tmpSqlString appendString:@" "];
                        meetSpaceChar = YES;
                        meetSymbolChar = NO;
                    }
                }
            }else{// 不是空白字符
                if ([symbolCharSet characterIsMember:aChar]) { // 是符号
                    if (!meetSymbolChar) {
                        meetSymbolChar = YES;
                        if (meetSpaceChar) { // 上一个是空白字符
                            [tmpSqlString appendString:oneCharString];
                        }else{ // 上一个不是空白字符
                            if ([oneCharString isEqualToString:@","]) {
                                [tmpSqlString appendString:oneCharString];
                            }else{
                                [tmpSqlString appendFormat:@" %@", oneCharString];
                            }
                        }
                    }else{ // 上一个也是符号
                        [tmpSqlString appendString:oneCharString];
                    }
                }else{ // 不是符号,也不是空格
                    if (meetSymbolChar) {
                        [tmpSqlString appendFormat:@" %@", oneCharString]; // 前一个是符号,添加空格
                    }else{
                        [tmpSqlString appendString:oneCharString]; // 前一个不是符号,直接添加
                    }
                    meetSymbolChar = NO;
                }
                meetSpaceChar = NO;
            }
        }
    }
    sqlString2 = [NSString stringWithString:tmpSqlString];
    
    // 找出表名
    NSRange selectRange = [sqlString2 rangeOfString:@"select "];
    NSRange fromRange = [sqlString2 rangeOfString:@" from "];
    NSRange whereRange = [sqlString2 rangeOfString:@" where "];
    NSRange groupRange = [sqlString2 rangeOfString:@" group " options:NSBackwardsSearch];
    NSRange orderRange = [sqlString2 rangeOfString:@" order by " options:NSBackwardsSearch];
    NSRange limitRange = [sqlString2 rangeOfString:@" limit " options:NSBackwardsSearch];
    NSRange fieldsRange = NSMakeRange(selectRange.location + selectRange.length, fromRange.location - selectRange.location - selectRange.length);
    
    if (selectRange.length == 0 || fromRange.length == 0) {
        NSLog(@"SQL错误!");
        return nil;
    }
    
    // 格式化字段
    NSString *fields = [sqlString2 substringWithRange:fieldsRange];
    __block NSCharacterSet *charSet = [NSCharacterSet characterSetWithCharactersInString:@"`()"];
    BOOL meetRowID = NO;
    if ([fields containsString:@"rowid"]) {
        NSArray *array = [fields componentsSeparatedByString:@","];
        [tmpSqlString setString:@""];
        for (NSInteger i = 0; i < array.count; i ++) {
            NSString *str = [[array[i] stringByTrimmingCharactersInSet:spaceCharSet] stringByTrimmingCharactersInSet:charSet];
            if ([str isEqualToString:@"rowid"]) {
                meetRowID = YES;
            }
            if (!([str containsString:@" "] || [str isEqualToString:@"*"])) {
                str = [NSString stringWithFormat:@"`%@`", str];
            }
            if (i == 0) {
                [tmpSqlString appendString:str];
            }else{
                [tmpSqlString appendFormat:@", %@", str];
            }
        }
        fields = [NSString stringWithString:tmpSqlString]; // fields的替换要放到最后,sqlString下面还要使用
    }
    
    NSInteger minRangeLocation = 0;
    if (groupRange.length > 0) {
        minRangeLocation = groupRange.location;
    }
    if (orderRange.length > 0) {
        if (minRangeLocation > orderRange.location) {
            minRangeLocation = orderRange.location;
        }
    }
    if (limitRange.length > 0) {
        if (minRangeLocation > limitRange.location) {
            minRangeLocation = limitRange.location;
        }
    }
    
    __block BOOL writable;
    NSString *(^getTmpTableName)() = ^{
        return [NSString stringWithFormat:@"tmpTable%05u", arc4random()%1000000];
    };
    void (^TestAsInTableString)(NSRange, NSString *) = ^(NSRange tableRange, NSString *tmp){
        NSRange asRange = [tmp rangeOfString:@" as " options:NSBackwardsSearch];
        if (asRange.length > 0) {
            selftable = [tmp substringFromIndex:asRange.location + asRange.length];
            writable = NO;
        }else{
            if ([tmp containsString:@" "]) {
                NSString *tmpTableName = getTmpTableName();
                while ([sqlString2 containsString:tmpTableName]) {
                    tmpTableName = getTmpTableName();
                }
                selftable = tmpTableName;
                if ([tmp hasPrefix:@"("]) {
                    sqlString2 = [sqlString2 stringByReplacingCharactersInRange:tableRange withString:[NSString stringWithFormat:@"%@ as `%@`", tmp, tmpTableName]];
                }else{
                    sqlString2 = [sqlString2 stringByReplacingCharactersInRange:tableRange withString:[NSString stringWithFormat:@"(%@) as `%@`", tmp, tmpTableName]];
                }
                
                writable = NO;
            }else{
                selftable = [tmp stringByTrimmingCharactersInSet:charSet];
                sqlString2 = [sqlString2 stringByReplacingCharactersInRange:tableRange withString:[NSString stringWithFormat:@"`%@`", tmp]];
            }
        }
    };
    
    if (whereRange.length == 0) {
        if (minRangeLocation == 0) {
            NSString *tmp = [sqlString2 substringFromIndex:(fromRange.length + fromRange.location)];
            NSRange tableRange = [sqlString2 rangeOfString:tmp];
            TestAsInTableString(tableRange, tmp);
        }else{
            NSRange tableRange = NSMakeRange(fromRange.location + fromRange.length, 0);
            tableRange.length = minRangeLocation - tableRange.location;
            NSString *tmp = [sqlString2 substringWithRange:tableRange];
            TestAsInTableString(tableRange, tmp);
        }
    }else{
        NSRange tableRange = NSMakeRange(fromRange.location + fromRange.length, 0);
        tableRange.length = whereRange.location - tableRange.location;
        NSString *tmp = [sqlString2 substringWithRange:tableRange];
        if ([tmp containsString:@" "]) {
            NSInteger meetStart = 0;
            for (NSInteger i = tableRange.location; i < sqlString2.length; i ++) {
                unichar aChar = [sqlString2 characterAtIndex:i];
                if (meetStart == 0) {
                    if (aChar == '(') {
                        meetStart ++;
                    }
                }else{
                    if (aChar == ')') {
                        meetStart --;
                    }
                    if (meetStart == 0) {
                        tableRange.length = i - tableRange.location + 1;
                        break;
                    }
                }
            }
            if (tableRange.location + tableRange.length <= whereRange.location) {
                tableRange.length = whereRange.location - tableRange.location;
                NSString *tmp = [sqlString2 substringWithRange:tableRange];
                TestAsInTableString(tableRange, tmp);
            }else{
                NSString *tmp = [sqlString2 substringFromIndex:tableRange.location + tableRange.length];
                whereRange = [tmp rangeOfString:@" where "];
                if (whereRange.length == 0) {
                    tmp = [sqlString2 substringFromIndex:fromRange.location + fromRange.length];
                    tableRange = [sqlString2 rangeOfString:tmp];
                    TestAsInTableString(tableRange, tmp);
                }else{
                    if (minRangeLocation == 0) {
                        tableRange.length += whereRange.location;
                        tmp = [sqlString2 substringWithRange:tableRange];
                        TestAsInTableString(tableRange, tmp);
                    }else{
                        tableRange.length = minRangeLocation - tableRange.location;
                        tmp = [sqlString2 substringWithRange:tableRange];
                        TestAsInTableString(tableRange, tmp);
                    }
                }
            }
        }else{
            selftable = tmp;
            TestAsInTableString(tableRange, tmp);
        }
    }
    
    if (!meetRowID) {
        sqlString2 = [sqlString2 stringByReplacingCharactersInRange:fieldsRange withString:[NSString stringWithFormat:@"`rowid`, %@", fields]];
    }else{
        sqlString2 = [sqlString2 stringByReplacingCharactersInRange:fieldsRange withString:fields];
    }
    
    NSRange ranges[allSqlValues.count];
    
    for (NSInteger i = 0; i < allSqlValues.count; i ++) {
        NSRange range = NSMakeRange(0, sqlString2.length);
        if (i > 0) {
            range.location = ranges[i - 1].location + 1;
            range.length -= range.location;
        }
        ranges[i] = [sqlString2 rangeOfString:@"?" options:NSCaseInsensitiveSearch range:range];
    }
    for (NSInteger i = allSqlValues.count; i > 0; i --) {
        sqlString2 = [sqlString2 stringByReplacingCharactersInRange:ranges[i-1] withString:[NSString stringWithFormat:@"'%@'", [allSqlValues[i-1] stringByReplacingOccurrencesOfString:@"'" withString:@"''"]]];
    }
    
    if (pageSize > 0) {
        _sql = [[NSString alloc] initWithFormat:@"select * from (%@) as %@ limit %lu offset %lu", sqlString2, selftable, pageSize, pageSize * page];
    }else{
        _sql = [[NSString alloc] initWithString:sqlString2];;
    }

    return @[selftable, _sql];
}


猜你喜欢

转载自blog.csdn.net/mlibai/article/details/47123685