通常包含一组状态、事件、状态之间的转换规则。状态机的目的是描述系统在不同状态下对事件的响应以及状态之间的切换过程
--greenplum分割do函数、存储过程
private static String[] parseSQL(String sql) {
List<String> sqlList = new ArrayList<>();
// 先设置状态
final int OUTSIDE_PROCEDURE = 0, IN_PROCEDURE = 1,
IN_DO = 2, IN_STRING = 3,
IN_LINE_COMMENT = 4, IN_MULTI_LINE_COMMENT = 5,
IN_DO_LABEL = 6;
int state = OUTSIDE_PROCEDURE;
StringBuilder statementBuilder = new StringBuilder();
StringBuilder labelBuilder = new StringBuilder(); // 用于记录label的内容
StringBuilder label2 = new StringBuilder(); // 用于记录label的内容
for (int i = 0; i < sql.length(); i++) {
char c = sql.charAt(i);
switch (state) {
case OUTSIDE_PROCEDURE:
if (c == '-' && i + 1 < sql.length() && sql.charAt(i + 1) == '-') {
state = IN_LINE_COMMENT;
i++;
} else if (c == '/' && i + 1 < sql.length() && sql.charAt(i + 1) == '*') {
state = IN_MULTI_LINE_COMMENT;
statementBuilder.append(c); // 追加注释开始符号到语句构建器
} else {
statementBuilder.append(c);
if (c == '$' && i + 1 < sql.length() && sql.charAt(i + 1) == '$') {
state = IN_PROCEDURE;
statementBuilder.append(sql.charAt(i + 1));
i++;
} else if (c == '$' && i + 1 < sql.length() && Character.isJavaIdentifierPart(sql.charAt(i + 1))) {
labelBuilder.setLength(0); // 清空labelBuilder
labelBuilder.append(c);
state = IN_DO;
} else if (c == '\'') {
state = IN_STRING;
} else if (c == ';') {
addSqlToList(statementBuilder.toString().trim(), sqlList);
statementBuilder.setLength(0); // 清空语句缓存
}
}
break;
case IN_PROCEDURE:
statementBuilder.append(c);
if (c == '$' && statementBuilder.toString().endsWith("$$")) {
state = OUTSIDE_PROCEDURE;
}
break;
case IN_DO:
statementBuilder.append(c);
labelBuilder.append(c);
if (c == '$') {
state = IN_DO_LABEL;
}
break;
case IN_DO_LABEL:
if (labelBuilder.toString().equals(label2.toString())) {
state = OUTSIDE_PROCEDURE;
label2.setLength(0);
} else if (c == '$') {
int endIdx = parseDollarQuotes(sql.toCharArray(), i);
if (endIdx != i) {
label2.append(sql, i, endIdx + 1);
statementBuilder.append(sql, i, endIdx + 1);
i = endIdx;
} else {
statementBuilder.append(c);
}
} else {
statementBuilder.append(c);
}
break;
case IN_STRING:
statementBuilder.append(c);
if (c == '\'') {
state = OUTSIDE_PROCEDURE;
}
break;
case IN_LINE_COMMENT:
if (c == '\n' || c == '\r') {
state = OUTSIDE_PROCEDURE;
}
break;
case IN_MULTI_LINE_COMMENT:
statementBuilder.append(c);
if (c == '*' && i + 1 < sql.length() && sql.charAt(i + 1) == '/') {
state = OUTSIDE_PROCEDURE;
statementBuilder.append(sql.charAt(++i)); // 追加注释结束符号到语句构建器
} else if (c == '/' && i + 1 < sql.length() && sql.charAt(i + 1) == '*') {
// 处理 /* 嵌套 */ 的情况
state = IN_MULTI_LINE_COMMENT;
statementBuilder.append(c);
i++;
}
break;
default:
// 处理其他状态(如果有的话)
}
}
// 处理最后一条语句
if (statementBuilder.length() > 0) {
addSqlToList(statementBuilder.toString().trim(), sqlList);
}
return sqlList.toArray(new String[0]);
}
private static boolean ifBlockComment(String sql) {
if (sql.trim().startsWith("/*") && sql.trim().endsWith("*/")) {
// /* */作为注释不能作为单独一条sql执行,不能保留在末尾
return true;
}
return false;
}
public static int parseDollarQuotes(char[] query, int offset) {
int endIdx = -1;
if (offset + 1 < query.length - 1 && (offset == 0 || !Character.isJavaIdentifierPart(query[offset - 1]))) {
int d;
if (query[offset + 1] == '$') {
endIdx = offset + 1;
} else if (isDollarQuoteStartChar(query[offset + 1])) {
for (d = offset + 2; d < query.length - 1; ++d) {
if (query[d] == '$') {
endIdx = d;
break;
}
if (!isDollarQuoteContChar(query[d])) {
break;
}
}
}
}
if (endIdx > 0) {
return endIdx;
}
return offset;
}
public static boolean isDollarQuoteStartChar(char c) {
return c != '$' && Character.isJavaIdentifierStart(c);
}
public static boolean isDollarQuoteContChar(char c) {
return c != '$' && Character.isJavaIdentifierPart(c);
}
/**
* 将单句sql添加到list中
*
* @param sql 1、正常sql 2、可能包含分号,但是是一个错误sql("……;)
* @param sqlList 用于存储拆分的sql
*/
private static void addSqlToList(String sql, List<String> sqlList) {
if (StringUtils.isEmpty(sql) || ifBlockComment(sql)) {
return;
}
if (sql.charAt(sql.length() - 1) != ';') {
sql += ";";
}
System.out.println("SQL输出:" + sql);
sqlList.add(sql);
}