源码解析pinpoint的DefaultSqlParser代码
时间: 2024-05-11 16:17:30 浏览: 102
Pinpoint 的 DefaultSqlParser 类是用于解析 SQL 语句的工具类。它主要用于解析 SQL 语句中的表名、列名、条件语句等信息。解析过程中会涉及到正则表达式的使用。
下面是 DefaultSqlParser 类的源码解析:
```
public class DefaultSqlParser implements SqlParser {
private static final String[] EMPTY_STRING_ARRAY = new String[0];
@Override
public ParsedSql parse(String sql) {
if (sql == null) {
return new ParsedSql(EMPTY_STRING_ARRAY, EMPTY_STRING_ARRAY, false, false);
}
String newSql = SqlParsingUtils.removeComments(sql);
newSql = SqlParsingUtils.replaceQuotationMark(newSql);
List<String> parameters = new ArrayList<>();
StringBuilder parameterBuilder = new StringBuilder();
Set<String> tables = new LinkedHashSet<>();
Set<String> columns = new LinkedHashSet<>();
boolean inSingleQuoteString = false;
boolean inDoubleQuoteString = false;
boolean inParameter = false;
int length = newSql.length();
for (int i = 0; i < length; i++) {
char c = newSql.charAt(i);
boolean isLast = (i + 1) == length;
if (inSingleQuoteString) {
if (c == '\'') {
if (isLast || newSql.charAt(i + 1) != '\'') {
inSingleQuoteString = false;
} else {
i++;
}
}
} else if (inDoubleQuoteString) {
if (c == '\"') {
if (isLast || newSql.charAt(i + 1) != '\"') {
inDoubleQuoteString = false;
} else {
i++;
}
}
} else if (inParameter) {
if (c == '?') {
parameters.add(parameterBuilder.toString().trim());
parameterBuilder.setLength(0);
inParameter = false;
} else {
parameterBuilder.append(c);
}
} else {
if (c == '\'') {
inSingleQuoteString = true;
} else if (c == '\"') {
inDoubleQuoteString = true;
} else if (c == '?') {
inParameter = true;
} else if (c == ' ') {
// skip
} else if (c == ',') {
// skip
} else if (Character.isLetter(c) || c == '_') {
// table name or column name
int j = i + 1;
for (; j < length; j++) {
if (!(Character.isLetterOrDigit(newSql.charAt(j)) || newSql.charAt(j) == '_')) {
break;
}
}
String word = newSql.substring(i, j);
String lowerCaseWord = word.toLowerCase();
if (SqlParsingUtils.TABLE_HINTS.contains(lowerCaseWord)) {
// skip table hints
} else if (SqlParsingUtils.QUERY_HINTS.contains(lowerCaseWord)) {
// skip query hints
} else if (SqlParsingUtils.TABLE_KEYWORDS.contains(lowerCaseWord)) {
// table name
i = j - 1;
for (; j < length; j++) {
if (newSql.charAt(j) == ' ' || newSql.charAt(j) == '\t') {
continue;
} else if (newSql.charAt(j) == '(') {
i = j;
break;
} else {
tables.add(word);
break;
}
}
} else {
// column name
columns.add(word);
i = j - 1;
}
}
}
}
return new ParsedSql(tables.toArray(new String[tables.size()]),
columns.toArray(new String[columns.size()]),
!parameters.isEmpty(),
inParameter);
}
}
```
其中,parse() 方法接收一个 SQL 语句作为参数,并返回 ParsedSql 对象,该对象包含解析后的表名、列名、参数等信息。
在解析过程中,首先会移除 SQL 语句中的注释和替换引号,然后遍历 SQL 语句的每个字符,根据不同的字符类型进行相应的处理。具体来说:
- 如果当前字符在单引号字符串中,则跳过;
- 如果当前字符在双引号字符串中,则跳过;
- 如果当前字符是问号,则表示当前字符为参数,将 inParameter 标记设置为 true,并将参数添加到 parameters 集合中;
- 如果当前字符是空格或逗号,则跳过;
- 如果当前字符是字母或下划线,则表示当前字符为表名或列名。在往后遍历时,如果遇到空格或括号,则表示当前字符为表名,否则为列名;
- 如果当前字符不属于上述任何一种类型,则跳过。
在解析过程中,还需要注意以下几点:
- 如果 SQL 语句中出现了嵌套的单引号或双引号,则需要特殊处理;
- 如果 SQL 语句中出现了注释,则需要移除;
- 如果 SQL 语句中出现了参数,则需要将 inParameter 标记设置为 true,并将参数添加到 parameters 集合中;
- 如果 SQL 语句中出现了表名或列名,则需要将其添加到 tables 或 columns 集合中。
最后,将解析得到的表名、列名、参数等信息封装到 ParsedSql 对象中,并返回即可。
阅读全文