package io.mycat.sqlengine.sharejoin;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLOrderBy;
import com.alibaba.druid.sql.ast.SQLOrderingSpecification;
import com.alibaba.druid.sql.ast.expr.*;
import com.alibaba.druid.sql.ast.statement.SQLJoinTableSource;
import com.alibaba.druid.sql.ast.statement.SQLJoinTableSource.JoinType;
import com.alibaba.druid.sql.ast.statement.SQLSelectItem;
import com.alibaba.druid.sql.ast.statement.SQLSelectOrderByItem;
import com.alibaba.druid.sql.ast.statement.SQLTableSource;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
/**
* 功能详细描述:分片join,解析join语句
* @author sohudo[http://blog.csdn.net/wind520]
* @create 2015年01月25日
* @version 0.0.1
*/
public class JoinParser {
public static final Logger LOGGER = LoggerFactory
.getLogger(JoinParser.class);
private MySqlSelectQueryBlock mysqlQuery;
private String stmt="";
private String joinType;
private String masterTable;
private TableFilter tableFilter;
//private LinkedHashMap<String,String> fieldAliasMap = new LinkedHashMap<String,String>();
public JoinParser(MySqlSelectQueryBlock selectQuery,String stmt) {
this.mysqlQuery=selectQuery;
this.stmt=stmt;
}
public void parser(){
masterTable="";
SQLTableSource table=mysqlQuery.getFrom();
parserTable(table,tableFilter,false);
parserFields(mysqlQuery.getSelectList());
parserMaserTable();
parserWhere(mysqlQuery.getWhere(),"");
// getJoinField();
parserOrderBy(mysqlQuery.getOrderBy());
parserLimit();
// LOGGER.info("field "+fieldAliasMap);
// LOGGER.info("master "+masterTable);
// LOGGER.info("join Lkey "+getJoinLkey());
// LOGGER.info("join Rkey "+getJoinRkey());
LOGGER.info("SQL: "+this.stmt);
}
private void parserTable(SQLTableSource table,TableFilter tFilter,boolean isOutJoin){
if(table instanceof SQLJoinTableSource){
SQLJoinTableSource table1=(SQLJoinTableSource)table;
joinType=table1.getJoinType().toString();
if ((table1.getJoinType()==JoinType.COMMA)||(table1.getJoinType()==JoinType.JOIN)||(table1.getJoinType()==JoinType.INNER_JOIN)
||(table1.getJoinType()==JoinType.LEFT_OUTER_JOIN)) {
tFilter=setTableFilter(tFilter,getTableFilter(table1.getLeft(),isOutJoin));
if (tableFilter==null){
tableFilter=tFilter;
}
}
//parserTable(table1.getLeft()); //SQLExprTableSource
parserTable(table1.getRight(),tFilter,true);
SQLExpr expr=table1.getCondition();//SQLBinaryOpExpr
parserJoinKey(expr);
}
else {
tFilter=setTableFilter(tFilter,getTableFilter(table,isOutJoin));
// LOGGER.info("table "+table.toString() +" Alias:"+table.getAlias()+" Hints:"+table.getHints());
}
}
private TableFilter setTableFilter(TableFilter tFilter,TableFilter newFilter){
if (tFilter==null) {
tFilter=newFilter;
return tFilter;
}
else {
tFilter.setTableJoin(newFilter);
return tFilter.getTableJoin();
}
}
private TableFilter getTableFilter(SQLTableSource table,boolean isOutJoin){
String key ;
String value = table.toString().trim();
if (table.getAlias()==null) {
key=value;
}
else {
key = table.getAlias().trim();
}
return new TableFilter(value,key,isOutJoin);
}
private void parserJoinKey(SQLExpr expr){
if (expr==null) return;
parserWhere(expr,"");
}
private String getExprFieldName(SQLAggregateExpr expr){
String field="";
for (SQLExpr item :expr.getArguments()){
field+=item.toString();
}
return expr.getMethodName()+"("+field+")";
}
private String getFieldName(SQLSelectItem item){
if (item.getExpr() instanceof SQLPropertyExpr) {
return item.getExpr().toString();//字段别名
}
else
return item.toString();
}
private void parserFields(List<SQLSelectItem> mysqlSelectList){
//显示的字段
String key="";
String value ="";
for(SQLSelectItem item : mysqlSelectList) {
if (item.getExpr() instanceof SQLAllColumnExpr) {
//*解析
setField(item.toString(), item.toString());
}
else {
if (item.getExpr() instanceof SQLAggregateExpr) {
SQLAggregateExpr expr =(SQLAggregateExpr)item.getExpr();
key = getExprFieldName(expr);
//value=expr.
}
else {
key=getFieldName(item);
value=item.getAlias();
}
setField(key, value);
}
}
}
private void setField(String key,String value){
//fieldAliasMap.put(key, value);
if (tableFilter!=null){
tableFilter.addField(key, value);
}
}
//判断并获得主表
private void parserMaserTable(){
if (tableFilter!=null){
masterTable=tableFilter.getTableAlia();
}
}
private boolean checkJoinField(String value){
if (value==null){
return false;
}
else {
int i=value.indexOf('.');
return i>0;
}
}
private void parserWhere(SQLExpr aexpr,String Operator){
if (aexpr==null) return;
if (aexpr instanceof SQLBinaryOpExpr){
SQLBinaryOpExpr expr=(SQLBinaryOpExpr)aexpr;
SQLExpr exprL=expr.getLeft();
if (!(exprL instanceof SQLBinaryOpExpr))
{
opSQLExpr((SQLBinaryOpExpr)aexpr,Operator);
}
else {
// if (expr.getOperator().getName().equals("AND")) {
if (expr.getOperator()==SQLBinaryOperator.BooleanAnd) {
//parserWhere(exprL);
//parserWhere(expr.getRight());
andorWhere(exprL,expr.getOperator().getName(),expr.getRight());
}
else if (expr.getOperator()==SQLBinaryOperator.BooleanOr){//.getName().equals("OR")) {
andorWhere(exprL,expr.getOperator().getName(),expr.getRight());
}
else {
throw new RuntimeException("Can't identify the operation of of where");
}
}
}
}
private void andorWhere(SQLExpr exprL,String Operator,SQLExpr exprR ){
parserWhere(exprL,"");
parserWhere(exprR,Operator);
}
private void opSQLExpr(SQLBinaryOpExpr expr,String Operator) {
if (expr==null) return;
SQLExpr exprL=expr.getLeft();
if (!(exprL instanceof SQLBinaryOpExpr))
{
String field=exprL.toString();
String value=getExpValue(expr.getRight()).toString();
if (expr.getOperator()==SQLBinaryOperator.Equality) {
if (checkJoinField(value)) {
//joinLkey=field;
//joinRkey=value;
tableFilter.setJoinKey(field,value);
}
else
tableFilter.addWhere(field, value, expr.getOperator().getName(),Operator);
}
else
tableFilter.addWhere(field, value, expr.getOperator().getName(),Operator);
}
}
private Object getExpValue(SQLExpr expr){
if (expr instanceof SQLIntegerExpr){
return ((SQLIntegerExpr)expr).getNumber().intValue();
}
if (expr instanceof SQLNumberExpr){
return ((SQLNumberExpr)expr).getNumber().doubleValue();
}
if (expr instanceof SQLCharExpr){
String va=((SQLCharExpr)expr).toString();
return va;//remove(va,'\'');
}
if (expr instanceof SQLBooleanExpr){
return ((SQLBooleanExpr)expr).getValue();
}
if (expr instanceof SQLNullExpr){
return null;
}
return expr;
}
private void parserOrderBy(SQLOrderBy orderby)
{
if (orderby != null ){
for (int i = 0; i < orderby.getItems().size(); i++)
{
SQLSelectOrderByItem orderitem = orderby.getItems().get(i);
tableFilter.addOrders(orderitem.getExpr().toString(), getSQLExprToAsc(orderitem.getType()));
}
}
}
private void parserLimit(){
int limitoff=0;
int limitnum=0;
if (this.mysqlQuery.getLimit()!=null) {
limitoff=getSQLExprToInt(this.mysqlQuery.getLimit().getOffset());
limitnum=getSQLExprToInt(this.mysqlQuery.getLimit().getRowCount());
tableFilter.addLimit(limitoff,limitnum);
}
}
private int getSQLExprToInt(SQLExpr expr){
if (expr instanceof SQLIntegerExpr){
return ((SQLIntegerExpr)expr).getNumber().intValue();
}
return 0;
}
private String getSQLExprToAsc(SQLOrderingSpecification ASC){
if (ASC==null ) return " ASC ";
if (ASC==SQLOrderingSpecification.DESC){
return " DESC ";
}
else {
return " ASC ";
}
}
public String getChildSQL(){
//String sql="select "+joinRkey+","+sql+" from "+mtable+" where "+joinRkey+" in ";
String sql=tableFilter.getTableJoin().getSQL();
return sql;
}
public String getSql(){
stmt=tableFilter.getSQL();
return stmt;
}
public String getJoinType(){
return joinType;
}
public String getJoinLkey(){
return tableFilter.getJoinKey(true);
}
public String getJoinRkey(){
return tableFilter.getJoinKey(false);
}
}