|
@@ -6,19 +6,13 @@
|
|
|
*/
|
|
|
package com.baomidou.mybatisplus.core.toolkit.sql;
|
|
|
|
|
|
-import java.util.HashSet;
|
|
|
-import java.util.LinkedList;
|
|
|
-import java.util.Locale;
|
|
|
-import java.util.Set;
|
|
|
-import java.util.StringTokenizer;
|
|
|
-
|
|
|
-import com.baomidou.mybatisplus.core.toolkit.StringPool;
|
|
|
-import com.baomidou.mybatisplus.core.toolkit.StringUtils;
|
|
|
+import java.util.*;
|
|
|
|
|
|
/**
|
|
|
* Performs formatting of basic SQL statements (DML + query).
|
|
|
* <p>
|
|
|
* Copy Hibernate BasicFormatterImpl
|
|
|
+ * last commit on 2018-03-15
|
|
|
* </P>
|
|
|
*
|
|
|
* @author Gavin King
|
|
@@ -26,7 +20,7 @@ import com.baomidou.mybatisplus.core.toolkit.StringUtils;
|
|
|
*/
|
|
|
public class SqlFormatter {
|
|
|
|
|
|
- public static final String WHITESPACE = " \n\r\f\t";
|
|
|
+ private static final String WHITESPACE = " \n\r\f\t";
|
|
|
private static final Set<String> BEGIN_CLAUSES = new HashSet<>();
|
|
|
private static final Set<String> END_CLAUSES = new HashSet<>();
|
|
|
private static final Set<String> LOGICAL = new HashSet<>();
|
|
@@ -34,7 +28,7 @@ public class SqlFormatter {
|
|
|
private static final Set<String> DML = new HashSet<>();
|
|
|
private static final Set<String> MISC = new HashSet<>();
|
|
|
private static final String INDENT_STRING = " ";
|
|
|
- private static final String INITIAL = "\n ";
|
|
|
+ private static final String INITIAL = System.lineSeparator() + INDENT_STRING;
|
|
|
|
|
|
static {
|
|
|
BEGIN_CLAUSES.add("left");
|
|
@@ -47,9 +41,9 @@ public class SqlFormatter {
|
|
|
END_CLAUSES.add("where");
|
|
|
END_CLAUSES.add("set");
|
|
|
END_CLAUSES.add("having");
|
|
|
- END_CLAUSES.add("join");
|
|
|
END_CLAUSES.add("from");
|
|
|
END_CLAUSES.add("by");
|
|
|
+ END_CLAUSES.add("join");
|
|
|
END_CLAUSES.add("into");
|
|
|
END_CLAUSES.add("union");
|
|
|
|
|
@@ -78,7 +72,6 @@ public class SqlFormatter {
|
|
|
}
|
|
|
|
|
|
private static class FormatProcess {
|
|
|
-
|
|
|
boolean beginLine = true;
|
|
|
boolean afterBeginBeforeEnd;
|
|
|
boolean afterByOrSetOrFromOrSelect;
|
|
@@ -88,18 +81,17 @@ public class SqlFormatter {
|
|
|
boolean afterInsert;
|
|
|
int inFunction;
|
|
|
int parensSinceSelect;
|
|
|
- private final LinkedList<Integer> parenCounts = new LinkedList<>();
|
|
|
- private final LinkedList<Boolean> afterByOrFromOrSelects = new LinkedList<>();
|
|
|
+ StringBuilder result = new StringBuilder();
|
|
|
+ StringTokenizer tokens;
|
|
|
|
|
|
int indent = 1;
|
|
|
-
|
|
|
- final StringBuilder result = new StringBuilder();
|
|
|
- final StringTokenizer tokens;
|
|
|
+ private LinkedList<Integer> parenCounts = new LinkedList<Integer>();
|
|
|
+ private LinkedList<Boolean> afterByOrFromOrSelects = new LinkedList<Boolean>();
|
|
|
String lastToken;
|
|
|
String token;
|
|
|
String lcToken;
|
|
|
|
|
|
- public FormatProcess(String sql) {
|
|
|
+ FormatProcess(String sql) {
|
|
|
tokens = new StringTokenizer(
|
|
|
sql,
|
|
|
"()+*/-=<>'`\"[]," + WHITESPACE,
|
|
@@ -107,7 +99,68 @@ public class SqlFormatter {
|
|
|
);
|
|
|
}
|
|
|
|
|
|
- public String perform() {
|
|
|
+ private static boolean isFunctionName(String tok) {
|
|
|
+ if (tok == null || tok.length() == 0) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ final char begin = tok.charAt(0);
|
|
|
+ final boolean isIdentifier = Character.isJavaIdentifierStart(begin) || '"' == begin;
|
|
|
+ return isIdentifier &&
|
|
|
+ !LOGICAL.contains(tok) &&
|
|
|
+ !END_CLAUSES.contains(tok) &&
|
|
|
+ !QUANTIFIERS.contains(tok) &&
|
|
|
+ !DML.contains(tok) &&
|
|
|
+ !MISC.contains(tok);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void commaAfterOn() {
|
|
|
+ out();
|
|
|
+ indent--;
|
|
|
+ newline();
|
|
|
+ afterOn = false;
|
|
|
+ afterByOrSetOrFromOrSelect = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void commaAfterByOrFromOrSelect() {
|
|
|
+ out();
|
|
|
+ newline();
|
|
|
+ }
|
|
|
+
|
|
|
+ private void logical() {
|
|
|
+ if ("end".equals(lcToken)) {
|
|
|
+ indent--;
|
|
|
+ }
|
|
|
+ newline();
|
|
|
+ out();
|
|
|
+ beginLine = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void on() {
|
|
|
+ indent++;
|
|
|
+ afterOn = true;
|
|
|
+ newline();
|
|
|
+ out();
|
|
|
+ beginLine = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void misc() {
|
|
|
+ out();
|
|
|
+ if ("between".equals(lcToken)) {
|
|
|
+ afterBetween = true;
|
|
|
+ }
|
|
|
+ if (afterInsert) {
|
|
|
+ newline();
|
|
|
+ afterInsert = false;
|
|
|
+ } else {
|
|
|
+ beginLine = false;
|
|
|
+ if ("case".equals(lcToken)) {
|
|
|
+ indent++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ String perform() {
|
|
|
|
|
|
result.append(INITIAL);
|
|
|
|
|
@@ -116,32 +169,39 @@ public class SqlFormatter {
|
|
|
lcToken = token.toLowerCase(Locale.ROOT);
|
|
|
|
|
|
if ("'".equals(token)) {
|
|
|
- String t = StringUtils.EMPTY;
|
|
|
+ String t;
|
|
|
do {
|
|
|
- try {
|
|
|
- t = tokens.nextToken();
|
|
|
- } catch (Exception ignored) {
|
|
|
- }
|
|
|
+ t = tokens.nextToken();
|
|
|
token += t;
|
|
|
}
|
|
|
// cannot handle single quotes
|
|
|
while (!"'".equals(t) && tokens.hasMoreTokens());
|
|
|
- } else if (StringPool.QUOTE.equals(token)) {
|
|
|
+ } else if ("\"".equals(token)) {
|
|
|
+ String t;
|
|
|
+ do {
|
|
|
+ t = tokens.nextToken();
|
|
|
+ token += t;
|
|
|
+ }
|
|
|
+ while (!"\"".equals(t) && tokens.hasMoreTokens());
|
|
|
+ }
|
|
|
+ // SQL Server uses "[" and "]" to escape reserved words
|
|
|
+ // see SQLServerDialect.openQuote and SQLServerDialect.closeQuote
|
|
|
+ else if ("[".equals(token)) {
|
|
|
String t;
|
|
|
do {
|
|
|
t = tokens.nextToken();
|
|
|
token += t;
|
|
|
}
|
|
|
- while (!StringPool.QUOTE.equals(t));
|
|
|
+ while (!"]".equals(t) && tokens.hasMoreTokens());
|
|
|
}
|
|
|
|
|
|
- if (afterByOrSetOrFromOrSelect && StringPool.COMMA.equals(token)) {
|
|
|
+ if (afterByOrSetOrFromOrSelect && ",".equals(token)) {
|
|
|
commaAfterByOrFromOrSelect();
|
|
|
- } else if (afterOn && StringPool.COMMA.equals(token)) {
|
|
|
+ } else if (afterOn && ",".equals(token)) {
|
|
|
commaAfterOn();
|
|
|
- } else if (StringPool.LEFT_BRACKET.equals(token)) {
|
|
|
+ } else if ("(".equals(token)) {
|
|
|
openParen();
|
|
|
- } else if (StringPool.RIGHT_BRACKET.equals(token)) {
|
|
|
+ } else if (")".equals(token)) {
|
|
|
closeParen();
|
|
|
} else if (BEGIN_CLAUSES.contains(lcToken)) {
|
|
|
beginNewClause();
|
|
@@ -155,7 +215,7 @@ public class SqlFormatter {
|
|
|
values();
|
|
|
} else if ("on".equals(lcToken)) {
|
|
|
on();
|
|
|
- } else if (afterBetween && "and".equals(lcToken)) {
|
|
|
+ } else if (afterBetween && lcToken.equals("and")) {
|
|
|
misc();
|
|
|
afterBetween = false;
|
|
|
} else if (LOGICAL.contains(lcToken)) {
|
|
@@ -174,58 +234,6 @@ public class SqlFormatter {
|
|
|
return result.toString();
|
|
|
}
|
|
|
|
|
|
- private void commaAfterOn() {
|
|
|
- out();
|
|
|
- indent--;
|
|
|
- newline();
|
|
|
- afterOn = false;
|
|
|
- afterByOrSetOrFromOrSelect = true;
|
|
|
- }
|
|
|
-
|
|
|
- private void commaAfterByOrFromOrSelect() {
|
|
|
- out();
|
|
|
- newline();
|
|
|
- }
|
|
|
-
|
|
|
- private void logical() {
|
|
|
- if ("end".equals(lcToken)) {
|
|
|
- indent--;
|
|
|
- }
|
|
|
- newline();
|
|
|
- out();
|
|
|
- beginLine = false;
|
|
|
- }
|
|
|
-
|
|
|
- private void on() {
|
|
|
- indent++;
|
|
|
- afterOn = true;
|
|
|
- newline();
|
|
|
- out();
|
|
|
- beginLine = false;
|
|
|
- }
|
|
|
-
|
|
|
- private void misc() {
|
|
|
- out();
|
|
|
- if ("between".equals(lcToken)) {
|
|
|
- afterBetween = true;
|
|
|
- }
|
|
|
- if (afterInsert) {
|
|
|
- newline();
|
|
|
- afterInsert = false;
|
|
|
- } else {
|
|
|
- beginLine = false;
|
|
|
- if ("case".equals(lcToken)) {
|
|
|
- indent++;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private void white() {
|
|
|
- if (!beginLine) {
|
|
|
- result.append(StringPool.SPACE);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
private void updateOrInsertOrDelete() {
|
|
|
out();
|
|
|
indent++;
|
|
@@ -333,15 +341,10 @@ public class SqlFormatter {
|
|
|
parensSinceSelect++;
|
|
|
}
|
|
|
|
|
|
- private static boolean isFunctionName(String tok) {
|
|
|
- final char begin = tok.charAt(0);
|
|
|
- final boolean isIdentifier = Character.isJavaIdentifierStart(begin) || '"' == begin;
|
|
|
- return isIdentifier &&
|
|
|
- !LOGICAL.contains(tok) &&
|
|
|
- !END_CLAUSES.contains(tok) &&
|
|
|
- !QUANTIFIERS.contains(tok) &&
|
|
|
- !DML.contains(tok) &&
|
|
|
- !MISC.contains(tok);
|
|
|
+ private void white() {
|
|
|
+ if (!beginLine) {
|
|
|
+ result.append(" ");
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
private static boolean isWhitespace(String token) {
|
|
@@ -349,12 +352,11 @@ public class SqlFormatter {
|
|
|
}
|
|
|
|
|
|
private void newline() {
|
|
|
- result.append(StringPool.NEWLINE);
|
|
|
+ result.append(System.lineSeparator());
|
|
|
for (int i = 0; i < indent; i++) {
|
|
|
result.append(INDENT_STRING);
|
|
|
}
|
|
|
beginLine = true;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
}
|