package org.opencloudb.parser.druid.impl; import java.sql.SQLNonTransientException; import java.util.LinkedHashMap; import java.util.List; import org.opencloudb.config.model.SchemaConfig; import org.opencloudb.mpp.OrderCol; import org.opencloudb.route.RouteResultset; import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.SQLOrderingSpecification; import com.alibaba.druid.sql.ast.SQLStatement; import com.alibaba.druid.sql.ast.expr.SQLAggregateExpr; import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr; import com.alibaba.druid.sql.ast.statement.SQLSelectItem; import com.alibaba.druid.sql.ast.statement.SQLSelectOrderByItem; import com.alibaba.druid.sql.ast.statement.SQLSelectQuery; import com.alibaba.druid.sql.ast.statement.SQLSelectStatement; import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlSelectGroupByExpr; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock.Limit; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlUnionQuery; public class DruidSelectParser extends DefaultDruidParser { @Override public void statementParse(SchemaConfig schema, RouteResultset rrs, SQLStatement stmt) { SQLSelectStatement selectStmt = (SQLSelectStatement)stmt; SQLSelectQuery sqlSelectQuery = selectStmt.getSelect().getQuery(); if(sqlSelectQuery instanceof MySqlSelectQueryBlock) { MySqlSelectQueryBlock mysqlSelectQuery = (MySqlSelectQueryBlock)selectStmt.getSelect().getQuery(); //setHasAggrColumn ,such as count(*) //以下注释的代码没准以后有用,rrs.setMergeCols(aggrColumns);目前就是个坑,设置了反而报错,得不到正确结果 // boolean hasAggrColumn = false; // Map<String, Integer> aggrColumns = new HashMap<String, Integer>(); // for(SQLSelectItem item : mysqlSelectQuery.getSelectList()) { // // if(item.getExpr() instanceof SQLAggregateExpr) { // SQLAggregateExpr expr = (SQLAggregateExpr)item.getExpr(); // List<SQLExpr> argList = expr.getArguments(); // String method = expr.getMethodName(); // if (argList.size() > 0) { // for(SQLExpr arg : argList) { // aggrColumns.put(arg.toString(), MergeCol.getMergeType(method)); // } // } // hasAggrColumn = true; // } // // } // if(aggrColumns.size() > 0) { // rrs.setMergeCols(aggrColumns); // } // if(hasAggrColumn) { // rrs.setHasAggrColumn(true); // } //setHasAggrColumn ,such as count(*) for(SQLSelectItem item : mysqlSelectQuery.getSelectList()) { if(item.getExpr() instanceof SQLAggregateExpr) { rrs.setHasAggrColumn(true); break; } } //setGroupByCols if(mysqlSelectQuery.getGroupBy() != null) { List<SQLExpr> groupByItems = mysqlSelectQuery.getGroupBy().getItems(); String[] groupByCols = buildGroupByCols(groupByItems); rrs.setGroupByCols(groupByCols); } //setOrderByCols if(mysqlSelectQuery.getOrderBy() != null) { List<SQLSelectOrderByItem> orderByItems = mysqlSelectQuery.getOrderBy().getItems(); rrs.setOrderByCols(buildOrderByCols(orderByItems)); } //setMergeCols TODO 目前设置这个值会报错,可能有特殊场景需要,后续如果出现bug在考虑设置 } else if (sqlSelectQuery instanceof MySqlUnionQuery) { //TODO union语句可能需要额外考虑,目前不处理也没问题 // MySqlUnionQuery unionQuery = (MySqlUnionQuery)sqlSelectQuery; // MySqlSelectQueryBlock left = (MySqlSelectQueryBlock)unionQuery.getLeft(); // MySqlSelectQueryBlock right = (MySqlSelectQueryBlock)unionQuery.getLeft(); // System.out.println(); } } /** * 改写sql:需要加limit的加上 */ @Override public void changeSql(SchemaConfig schema, RouteResultset rrs, SQLStatement stmt) throws SQLNonTransientException { SQLSelectStatement selectStmt = (SQLSelectStatement)stmt; SQLSelectQuery sqlSelectQuery = selectStmt.getSelect().getQuery(); if(sqlSelectQuery instanceof MySqlSelectQueryBlock) { MySqlSelectQueryBlock mysqlSelectQuery = (MySqlSelectQueryBlock)selectStmt.getSelect().getQuery(); if(isNeedAddLimit(schema, rrs, mysqlSelectQuery) ) { Limit limit = new Limit(); limit.setRowCount(new SQLIntegerExpr(schema.getDefaultMaxLimit())); mysqlSelectQuery.setLimit(limit); } } } private boolean isNeedAddLimit(SchemaConfig schema, RouteResultset rrs, MySqlSelectQueryBlock mysqlSelectQuery) { if (!rrs.hasPrimaryKeyToCache() && schema.getDefaultMaxLimit() != -1 && mysqlSelectQuery.getLimit() == null && ctx.getTables().size() > 0) { return true; } return false; } private String[] buildGroupByCols(List<SQLExpr> groupByItems) { String[] groupByCols = new String[groupByItems.size()]; for(int i= 0; i < groupByItems.size(); i++) { String column = removeBackquote(((MySqlSelectGroupByExpr)groupByItems.get(i)).getExpr().toString().toUpperCase()); groupByCols[i] = column; } return groupByCols; } private LinkedHashMap<String, Integer> buildOrderByCols(List<SQLSelectOrderByItem> orderByItems) { LinkedHashMap<String, Integer> map = new LinkedHashMap<String, Integer>(); for(int i= 0; i < orderByItems.size(); i++) { SQLOrderingSpecification type = orderByItems.get(i).getType(); String col = orderByItems.get(i).getExpr().toString(); map.put(col, type == SQLOrderingSpecification.ASC ? OrderCol.COL_ORDER_TYPE_ASC : OrderCol.COL_ORDER_TYPE_DESC); } return map; } }