/* * Copyright 2015 Liu Huanting. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package fm.liu.timo.route.visitor; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import fm.liu.timo.config.model.Database; import fm.liu.timo.config.model.Table; import fm.liu.timo.config.model.Table.TableType; import fm.liu.timo.merger.MergeType; import fm.liu.timo.parser.ast.expression.Expression; import fm.liu.timo.parser.ast.expression.PolyadicOperatorExpression; import fm.liu.timo.parser.ast.expression.comparison.ComparisionEqualsExpression; import fm.liu.timo.parser.ast.expression.logical.LogicalOrExpression; import fm.liu.timo.parser.ast.expression.primary.Identifier; import fm.liu.timo.parser.ast.expression.primary.RowExpression; import fm.liu.timo.parser.ast.expression.primary.function.groupby.Count; import fm.liu.timo.parser.ast.expression.primary.function.groupby.Max; import fm.liu.timo.parser.ast.expression.primary.function.groupby.Min; import fm.liu.timo.parser.ast.expression.primary.function.groupby.Sum; import fm.liu.timo.parser.ast.fragment.GroupBy; import fm.liu.timo.parser.ast.fragment.Limit; import fm.liu.timo.parser.ast.fragment.OrderBy; import fm.liu.timo.parser.ast.fragment.SortOrder; import fm.liu.timo.parser.ast.fragment.tableref.TableRefFactor; import fm.liu.timo.parser.ast.stmt.ddl.DDLCreateTableStatement; import fm.liu.timo.parser.ast.stmt.ddl.DDLDropTableStatement; import fm.liu.timo.parser.ast.stmt.ddl.DDLTruncateStatement; import fm.liu.timo.parser.ast.stmt.dml.DMLDeleteStatement; import fm.liu.timo.parser.ast.stmt.dml.DMLInsertReplaceStatement; import fm.liu.timo.parser.ast.stmt.dml.DMLInsertStatement; import fm.liu.timo.parser.ast.stmt.dml.DMLReplaceStatement; import fm.liu.timo.parser.util.Pair; import fm.liu.timo.parser.visitor.Visitor; import fm.liu.timo.route.Info; /** * @author Liu Huanting 2015年5月10日 * 语法树解析器 */ public class RouteVisitor extends Visitor { private final Database database; private ArrayList<Object> values; private Table table; private int info; private Set<String> groupBy; private Map<String, Integer> orderBy; private int limitSize = -1; private int limitOffset = 0; private int batchIndex = -1; public RouteVisitor(Database database) { this.database = database; this.values = new ArrayList<Object>(); } public Table getTable() { return table; } public ArrayList<Object> getValues() { return values; } public int getInfo() { return info; } public Set<String> getGroupBy() { return groupBy; } public Map<String, Integer> getOrderBy() { return orderBy; } public int getLimitSize() { return limitSize; } public int getLimitOffset() { return limitOffset; } public int getBatchIndex() { return batchIndex; } private void recordTable(Identifier node) { String table = node.getIdTextUpUnescape(); this.table = database.getTables().get(table); } /** * 记录路由字段的值 */ private void recordValue(Identifier column, Object value) { if (value != null && value != Expression.UNEVALUATABLE) { if (check(column.getIdTextUpUnescape())) { values.add(value); } } } private boolean check(String column) { if (table != null && TableType.SPLIT.equals(table.getType())) { return table.getRule().getColumn().equals(column); } return false; } @Override public void visit(TableRefFactor node) { recordTable(node.getTable()); } @Override public void visit(DDLCreateTableStatement node) { recordTable(node.getTable()); } @Override public void visit(DDLDropTableStatement node) { node.getTableNames().forEach(t -> recordTable(t)); } public void visit(DDLTruncateStatement node) { visitChild(node.getTable()); recordTable(node.getTable()); } @Override public void visit(DMLInsertStatement node) { insertReplace(node); } @Override public void visit(DMLReplaceStatement node) { insertReplace(node); } public void insertReplace(DMLInsertReplaceStatement node) { Identifier table = node.getTable(); List<Identifier> columns = node.getColumnNameList(); List<RowExpression> rows = node.getRowList(); recordTable(table); visitChild(columns); int i = 0; for (Identifier column : columns) { if (check(column.getIdTextUpUnescape())) { batchIndex = i; break; } i++; } for (RowExpression row : rows) { row.accept(this); if (batchIndex != -1) { recordValue(columns.get(batchIndex), row.getRowExprList().get(batchIndex).evaluation(Collections.emptyMap())); } } visitChild(node.getSelect()); } @Override public void visit(DMLDeleteStatement node) { visitChild(node.getLimit()); visitChild(node.getOrderBy()); List<Identifier> tables = node.getTableNames(); tables.forEach(t -> recordTable(t)); visitChild(table); visitChild(node.getTableRefs()); visitChild(node.getWhereCondition()); } @Override public void visit(ComparisionEqualsExpression node) { Expression left = node.getLeftOprand(); Expression right = node.getRightOprand(); visitChild(left); visitChild(right); if (left instanceof Identifier) { recordValue((Identifier) left, right.evaluation(Collections.emptyMap())); } else if (right instanceof Identifier) { recordValue((Identifier) right, left.evaluation(Collections.emptyMap())); } } @Override public void visit(LogicalOrExpression node) { info |= Info.TO_ALL_NODE; visit((PolyadicOperatorExpression) node); } @Override public void visit(Max node) { info |= Info.NEED_MERGE; } @Override public void visit(Min node) { info |= Info.NEED_MERGE; } @Override public void visit(Sum node) { info |= Info.NEED_MERGE; } @Override public void visit(Count node) { info |= Info.NEED_MERGE; } @Override public void visit(GroupBy node) { List<Pair<Expression, SortOrder>> list = node.getOrderByList(); if (list == null || list.isEmpty()) { return; } info |= Info.HAS_GROUPBY; this.groupBy = new HashSet<String>(); for (Pair<Expression, SortOrder> pair : list) { String column = ((Identifier) pair.getKey()).getIdTextUpUnescape(); switch (pair.getValue()) { case ASC: groupBy.add(column); case DESC: break; } } } @Override public void visit(OrderBy node) { List<Pair<Expression, SortOrder>> list = node.getOrderByList(); if (list == null || list.isEmpty()) { return; } info |= Info.HAS_ORDERBY; this.orderBy = new HashMap<String, Integer>(); for (Pair<Expression, SortOrder> pair : list) { String column = ((Identifier) pair.getKey()).getIdTextUpUnescape(); switch (pair.getValue()) { case ASC: orderBy.put(column, MergeType.ASC); break; case DESC: orderBy.put(column, MergeType.DESC); break; } } } @Override public void visit(Limit limit) { info |= Info.HAS_LIMIT; limitSize = (int) limit.getSize(); limitOffset = (int) limit.getOffset(); } }