package jef.database.cache;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.persistence.PersistenceException;
import jef.common.PairSO;
import jef.common.log.LogUtil;
import jef.database.dialect.DatabaseDialect;
import jef.database.jsqlparser.expression.Column;
import jef.database.jsqlparser.expression.Table;
import jef.database.jsqlparser.parser.ParseException;
import jef.database.jsqlparser.parser.StSqlParser;
import jef.database.jsqlparser.parser.TokenMgrError;
import jef.database.jsqlparser.statement.select.Join;
import jef.database.jsqlparser.visitor.Expression;
import jef.database.jsqlparser.visitor.FromItem;
import jef.database.jsqlparser.visitor.VisitorAdapter;
import jef.tools.StringUtils;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr;
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
import com.alibaba.druid.sql.ast.statement.SQLTableSource;
import com.alibaba.druid.sql.parser.Lexer;
import com.alibaba.druid.sql.parser.ParserException;
import com.alibaba.druid.sql.parser.SQLExprParser;
import com.alibaba.druid.sql.parser.SQLSelectParser;
import com.alibaba.druid.sql.parser.Token;
import com.alibaba.druid.sql.visitor.SQLASTOutputVisitor;
public abstract class WhereParser {
static {
String a = "A123B";
if (a.toUpperCase() != a) {// String的实现必须满足大写字符串取大写还是本身的要求
throw new UnsupportedClassVersionError("The JDK Implementation is too old!");
}
}
abstract String process(String where, DatabaseDialect profile);
/**
* 解析后得到一下内容
*
* @param tableDef
* @param profile
* @return key: 规范话后的table定义 List<String>各个表的名称转大写
*/
abstract PairSO<List<String>> parseTables(String tableDef, DatabaseDialect profile);
public static final class NativeImpl extends WhereParser {
@Override
String process(String where, DatabaseDialect profile) {
StSqlParser parser = new StSqlParser(new StringReader(where));
try {
Expression exp = parser.WhereClause();
removeAliasAndCase(exp);
return exp.toString();
} catch (ParseException e) {
throw new PersistenceException("[" + where + "]", e);
} catch (TokenMgrError e) {
throw new PersistenceException("[" + where + "]", e);
}
}
@Override
PairSO<List<String>> parseTables(String tableDef, DatabaseDialect profile) {
// root_cus T1 left join ENUMATIONTABLE T2 ON T1.CODE=T2.CODE and
// T2.TYPE='1'
StSqlParser parser = new StSqlParser(new StringReader(tableDef));
List<String> tables = new ArrayList<String>();
try {
FromItem exp = parser.FromItem();
@SuppressWarnings("unchecked")
List<Join> joins = parser.JoinsList();
String result = ast2String(exp, joins, tables);
return new PairSO<List<String>>(result, tables);
} catch (ParseException e) {
throw new PersistenceException("[" + tableDef + "]", e);
} catch (TokenMgrError e) {
throw new PersistenceException("[" + tableDef + "]", e);
}
}
// 转换为规范化文本
private String ast2String(FromItem fromItem, List<Join> joins, List<String> tables) {
removeAliasAndCase(fromItem);
StringBuilder sb = new StringBuilder(64);
fromItem.appendTo(sb);
tables.add(fromItem.toWholeName());
if (joins != null) {
Iterator<Join> it = joins.iterator();
while (it.hasNext()) {
Join join = (Join) it.next();
join.accept(VA);
tables.add(join.getRightItem().toWholeName());
if (join.isSimple()) {
join.appendTo(sb.append(", "));
} else {
join.appendTo(sb.append(' '));
}
}
}
return sb.toString();
}
};
public static void removeAliasAndCase(FromItem fromItem) {
fromItem.accept(VA);
}
public static void removeAliasAndCase(Expression exp) {
exp.accept(VA);
}
private static final VisitorAdapter VA = new VisitorAdapter() {
public void visit(Column tableColumn) {
tableColumn.setTableAlias(null);
String s = tableColumn.getColumnName();
String s2 = s.toUpperCase();
char c1 = s2.charAt(0);
if (c1 == '"') {
s2 = s2.substring(1, s2.length() - 1);
}
if (s2 != s) {
tableColumn.setColumnName(s2);
}
}
@Override
public void visit(Table tableName) {
tableName.setName(StringUtils.upperCase(tableName.getName()));
tableName.setAlias(null);
super.visit(tableName);
}
};
public static final class DruidImpl extends WhereParser {
@Override
String process(String where, DatabaseDialect profile) {
SQLExprParser parser = profile.getParserFactory().getExprParser(where);
Lexer lexer = parser.getLexer();
if (lexer.token() == Token.WHERE) {
try {
lexer.nextToken();
SQLExpr exp = parser.expr();
SQLASTOutputVisitor v = new SQLASTOutputVisitor(new StringBuilder(where.length() - 6)) {
@Override
public boolean visit(SQLIdentifierExpr x) {
print(x.getName().toUpperCase());
return false;
}
public boolean visit(SQLPropertyExpr x) {
print(x.getName().toUpperCase());
return false;
}
};
v.setPrettyFormat(false);
exp.accept(v);
return v.getAppender().toString();
} catch (ParserException e) {
LogUtil.warn("Druid Parser error:{}\nException:{}", where, e);
throw e;
}
} else {
throw new PersistenceException("parse where error[" + where + "]");
}
}
@Override
PairSO<List<String>> parseTables(String tableDef, DatabaseDialect profile) {
SQLSelectParser parser = profile.getParserFactory().getSelectParser(tableDef);
Lexer lexer = parser.getLexer();
final List<String> tables=new ArrayList<String>();
try {
SQLTableSource exp= parser.parseTableSource();
SQLASTOutputVisitor v = new SQLASTOutputVisitor(new StringBuilder(tableDef.length())) {
@Override
public boolean visit(SQLExprTableSource x) {
x.setAlias(null);
return super.visit(x);
}
@Override
public boolean visit(SQLIdentifierExpr x) {
print(x.getName().toUpperCase());
tables.add(x.getName().toUpperCase());
return false;
}
public boolean visit(SQLPropertyExpr x) {
print(x.getName().toUpperCase());
return false;
}
};
v.setPrettyFormat(false);
exp.accept(v);
String result=v.getAppender().toString();
return new PairSO<List<String>>(result, tables);
} catch (ParserException e) {
LogUtil.warn("Druid Parser error:{}\nException:{}", tableDef, e);
throw e;
}
}
};
}