返回值是一个数组:
第一个元素:是查询的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];
}