Search in sources :

Example 1 with RouteCalculateUnit

use of io.mycat.route.parser.druid.RouteCalculateUnit in project Mycat-Server by MyCATApache.

the class DruidMycatRouteStrategy method routeNormalSqlWithAST.

@Override
public RouteResultset routeNormalSqlWithAST(SchemaConfig schema, String stmt, RouteResultset rrs, String charset, LayerCachePool cachePool) throws SQLNonTransientException {
    /**
		 *  只有mysql时只支持mysql语法
		 */
    SQLStatementParser parser = null;
    if (schema.isNeedSupportMultiDBType()) {
        parser = new MycatStatementParser(stmt);
    } else {
        parser = new MySqlStatementParser(stmt);
    }
    MycatSchemaStatVisitor visitor = null;
    SQLStatement statement;
    /**
		 * 解析出现问题统一抛SQL语法错误
		 */
    try {
        statement = parser.parseStatement();
        visitor = new MycatSchemaStatVisitor();
    } catch (Exception t) {
        LOGGER.error("DruidMycatRouteStrategyError", t);
        throw new SQLSyntaxErrorException(t);
    }
    /**
		 * 检验unsupported statement
		 */
    checkUnSupportedStatement(statement);
    DruidParser druidParser = DruidParserFactory.create(schema, statement, visitor);
    druidParser.parser(schema, rrs, statement, stmt, cachePool, visitor);
    DruidShardingParseInfo ctx = druidParser.getCtx();
    rrs.setTables(ctx.getTables());
    /**
		 * DruidParser 解析过程中已完成了路由的直接返回
		 */
    if (rrs.isFinishedRoute()) {
        return rrs;
    }
    /**
		 * 没有from的select语句或其他
		 */
    if ((ctx.getTables() == null || ctx.getTables().size() == 0) && (ctx.getTableAliasMap() == null || ctx.getTableAliasMap().isEmpty())) {
        return RouterUtil.routeToSingleNode(rrs, schema.getRandomDataNode(), druidParser.getCtx().getSql());
    }
    if (druidParser.getCtx().getRouteCalculateUnits().size() == 0) {
        RouteCalculateUnit routeCalculateUnit = new RouteCalculateUnit();
        druidParser.getCtx().addRouteCalculateUnit(routeCalculateUnit);
    }
    SortedSet<RouteResultsetNode> nodeSet = new TreeSet<RouteResultsetNode>();
    for (RouteCalculateUnit unit : druidParser.getCtx().getRouteCalculateUnits()) {
        RouteResultset rrsTmp = RouterUtil.tryRouteForTables(schema, druidParser.getCtx(), unit, rrs, isSelect(statement), cachePool);
        if (rrsTmp != null) {
            for (RouteResultsetNode node : rrsTmp.getNodes()) {
                nodeSet.add(node);
            }
        }
    }
    RouteResultsetNode[] nodes = new RouteResultsetNode[nodeSet.size()];
    int i = 0;
    for (RouteResultsetNode aNodeSet : nodeSet) {
        nodes[i] = aNodeSet;
        if (statement instanceof MySqlInsertStatement && ctx.getTables().size() == 1 && schema.getTables().containsKey(ctx.getTables().get(0))) {
            RuleConfig rule = schema.getTables().get(ctx.getTables().get(0)).getRule();
            if (rule != null && rule.getRuleAlgorithm() instanceof SlotFunction) {
                aNodeSet.setStatement(ParseUtil.changeInsertAddSlot(aNodeSet.getStatement(), aNodeSet.getSlot()));
            }
        }
        i++;
    }
    rrs.setNodes(nodes);
    /**
		 *  subTables="t_order$1-2,t_order3"
		 *目前分表 1.6 开始支持 幵丏 dataNode 在分表条件下只能配置一个,分表条件下不支持join。
		 */
    if (rrs.isDistTable()) {
        return this.routeDisTable(statement, rrs);
    }
    return rrs;
}
Also used : DruidShardingParseInfo(io.mycat.route.parser.druid.DruidShardingParseInfo) RouteCalculateUnit(io.mycat.route.parser.druid.RouteCalculateUnit) SQLStatementParser(com.alibaba.druid.sql.parser.SQLStatementParser) MycatStatementParser(io.mycat.route.parser.druid.MycatStatementParser) MycatSchemaStatVisitor(io.mycat.route.parser.druid.MycatSchemaStatVisitor) SQLSyntaxErrorException(java.sql.SQLSyntaxErrorException) MySqlInsertStatement(com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlInsertStatement) SQLStatement(com.alibaba.druid.sql.ast.SQLStatement) SQLNonTransientException(java.sql.SQLNonTransientException) SQLSyntaxErrorException(java.sql.SQLSyntaxErrorException) SlotFunction(io.mycat.route.function.SlotFunction) DruidParser(io.mycat.route.parser.druid.DruidParser) TreeSet(java.util.TreeSet) RouteResultsetNode(io.mycat.route.RouteResultsetNode) RuleConfig(io.mycat.config.model.rule.RuleConfig) MySqlStatementParser(com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser) RouteResultset(io.mycat.route.RouteResultset)

Example 2 with RouteCalculateUnit

use of io.mycat.route.parser.druid.RouteCalculateUnit in project Mycat-Server by MyCATApache.

the class DefaultDruidParser method buildRouteCalculateUnits.

private List<RouteCalculateUnit> buildRouteCalculateUnits(SchemaStatVisitor visitor, List<List<Condition>> conditionList) {
    List<RouteCalculateUnit> retList = new ArrayList<RouteCalculateUnit>();
    //遍历condition ,找分片字段
    for (int i = 0; i < conditionList.size(); i++) {
        RouteCalculateUnit routeCalculateUnit = new RouteCalculateUnit();
        for (Condition condition : conditionList.get(i)) {
            List<Object> values = condition.getValues();
            if (values.size() == 0) {
                break;
            }
            if (checkConditionValues(values)) {
                String columnName = StringUtil.removeBackquote(condition.getColumn().getName().toUpperCase());
                String tableName = StringUtil.removeBackquote(condition.getColumn().getTable().toUpperCase());
                if (visitor.getAliasMap() != null && visitor.getAliasMap().get(tableName) != null && !visitor.getAliasMap().get(tableName).equals(tableName)) {
                    tableName = visitor.getAliasMap().get(tableName);
                }
                if (visitor.getAliasMap() != null && visitor.getAliasMap().get(StringUtil.removeBackquote(condition.getColumn().getTable().toUpperCase())) == null) {
                    //子查询的别名条件忽略掉,不参数路由计算,否则后面找不到表
                    continue;
                }
                String operator = condition.getOperator();
                //只处理between ,in和=3中操作符
                if (operator.equals("between")) {
                    RangeValue rv = new RangeValue(values.get(0), values.get(1), RangeValue.EE);
                    routeCalculateUnit.addShardingExpr(tableName.toUpperCase(), columnName, rv);
                } else if (operator.equals("=") || operator.toLowerCase().equals("in")) {
                    //只处理=号和in操作符,其他忽略
                    routeCalculateUnit.addShardingExpr(tableName.toUpperCase(), columnName, values.toArray());
                }
            }
        }
        retList.add(routeCalculateUnit);
    }
    return retList;
}
Also used : RouteCalculateUnit(io.mycat.route.parser.druid.RouteCalculateUnit) Condition(com.alibaba.druid.stat.TableStat.Condition) ArrayList(java.util.ArrayList) RangeValue(io.mycat.sqlengine.mpp.RangeValue)

Example 3 with RouteCalculateUnit

use of io.mycat.route.parser.druid.RouteCalculateUnit in project Mycat-Server by MyCATApache.

the class ServerLoadDataInfileHandler method tryDirectRoute.

private RouteResultset tryDirectRoute(String sql, String[] lineList) {
    RouteResultset rrs = new RouteResultset(sql, ServerParse.INSERT);
    rrs.setLoadData(true);
    if (tableConfig == null && schema.getDataNode() != null) {
        //走默认节点
        RouteResultsetNode rrNode = new RouteResultsetNode(schema.getDataNode(), ServerParse.INSERT, sql);
        rrNode.setSource(rrs);
        rrs.setNodes(new RouteResultsetNode[] { rrNode });
        return rrs;
    } else if (tableConfig != null && tableConfig.isGlobalTable()) {
        ArrayList<String> dataNodes = tableConfig.getDataNodes();
        RouteResultsetNode[] rrsNodes = new RouteResultsetNode[dataNodes.size()];
        for (int i = 0, dataNodesSize = dataNodes.size(); i < dataNodesSize; i++) {
            String dataNode = dataNodes.get(i);
            RouteResultsetNode rrNode = new RouteResultsetNode(dataNode, ServerParse.INSERT, sql);
            rrsNodes[i] = rrNode;
            if (rrs.getDataNodeSlotMap().containsKey(dataNode)) {
                rrsNodes[i].setSlot(rrs.getDataNodeSlotMap().get(dataNode));
            }
            rrsNodes[i].setSource(rrs);
        }
        rrs.setNodes(rrsNodes);
        return rrs;
    } else if (tableConfig != null) {
        DruidShardingParseInfo ctx = new DruidShardingParseInfo();
        ctx.addTable(tableName);
        if (partitionColumnIndex == -1 || partitionColumnIndex >= lineList.length) {
            return null;
        } else {
            String value = lineList[partitionColumnIndex];
            RouteCalculateUnit routeCalculateUnit = new RouteCalculateUnit();
            routeCalculateUnit.addShardingExpr(tableName, getPartitionColumn(), parseFieldString(value, loadData.getEnclose()));
            ctx.addRouteCalculateUnit(routeCalculateUnit);
            try {
                SortedSet<RouteResultsetNode> nodeSet = new TreeSet<RouteResultsetNode>();
                for (RouteCalculateUnit unit : ctx.getRouteCalculateUnits()) {
                    RouteResultset rrsTmp = RouterUtil.tryRouteForTables(schema, ctx, unit, rrs, false, tableId2DataNodeCache);
                    if (rrsTmp != null) {
                        for (RouteResultsetNode node : rrsTmp.getNodes()) {
                            nodeSet.add(node);
                        }
                    }
                }
                RouteResultsetNode[] nodes = new RouteResultsetNode[nodeSet.size()];
                int i = 0;
                for (Iterator<RouteResultsetNode> iterator = nodeSet.iterator(); iterator.hasNext(); ) {
                    nodes[i] = (RouteResultsetNode) iterator.next();
                    i++;
                }
                rrs.setNodes(nodes);
                return rrs;
            } catch (SQLNonTransientException e) {
                throw new RuntimeException(e);
            }
        }
    }
    return null;
}
Also used : DruidShardingParseInfo(io.mycat.route.parser.druid.DruidShardingParseInfo) RouteCalculateUnit(io.mycat.route.parser.druid.RouteCalculateUnit) ArrayList(java.util.ArrayList) SQLNonTransientException(java.sql.SQLNonTransientException) TreeSet(java.util.TreeSet) RouteResultsetNode(io.mycat.route.RouteResultsetNode) RouteResultset(io.mycat.route.RouteResultset)

Example 4 with RouteCalculateUnit

use of io.mycat.route.parser.druid.RouteCalculateUnit in project Mycat-Server by MyCATApache.

the class DQLRouteTest method visitorParse.

@SuppressWarnings("unchecked")
private List<RouteCalculateUnit> visitorParse(RouteResultset rrs, SQLStatement stmt, MycatSchemaStatVisitor visitor) throws Exception {
    stmt.accept(visitor);
    List<List<Condition>> mergedConditionList = new ArrayList<List<Condition>>();
    if (visitor.hasOrCondition()) {
        // 包含or语句
        // TODO
        // 根据or拆分
        mergedConditionList = visitor.splitConditions();
    } else {
        // 不包含OR语句
        mergedConditionList.add(visitor.getConditions());
    }
    if (visitor.getAliasMap() != null) {
        for (Map.Entry<String, String> entry : visitor.getAliasMap().entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            if (key != null && key.indexOf("`") >= 0) {
                key = key.replaceAll("`", "");
            }
            if (value != null && value.indexOf("`") >= 0) {
                value = value.replaceAll("`", "");
            }
            // 表名前面带database的,去掉
            if (key != null) {
                int pos = key.indexOf(".");
                if (pos > 0) {
                    key = key.substring(pos + 1);
                }
            }
            if (key.equals(value)) {
                ctx.addTable(key.toUpperCase());
            }
            // else {
            // tableAliasMap.put(key, value);
            // }
            tableAliasMap.put(key.toUpperCase(), value);
        }
        visitor.getAliasMap().putAll(tableAliasMap);
        ctx.setTableAliasMap(tableAliasMap);
    }
    //利用反射机制单元测试DefaultDruidParser类的私有方法buildRouteCalculateUnits
    Class<?> clazz = Class.forName("io.mycat.route.parser.druid.impl.DefaultDruidParser");
    Method buildRouteCalculateUnits = clazz.getDeclaredMethod("buildRouteCalculateUnits", new Class[] { SchemaStatVisitor.class, List.class });
    //System.out.println("buildRouteCalculateUnits:\t" + buildRouteCalculateUnits);
    Object newInstance = clazz.newInstance();
    buildRouteCalculateUnits.setAccessible(true);
    Object returnValue = buildRouteCalculateUnits.invoke(newInstance, new Object[] { visitor, mergedConditionList });
    List<RouteCalculateUnit> retList = new ArrayList<RouteCalculateUnit>();
    if (returnValue instanceof ArrayList<?>) {
        retList.add(((ArrayList<RouteCalculateUnit>) returnValue).get(0));
    //retList = (ArrayList<RouteCalculateUnit>)returnValue;
    //System.out.println(taskList.get(0).getTablesAndConditions().values());			
    }
    return retList;
}
Also used : Condition(com.alibaba.druid.stat.TableStat.Condition) RouteCalculateUnit(io.mycat.route.parser.druid.RouteCalculateUnit) ArrayList(java.util.ArrayList) Method(java.lang.reflect.Method) ArrayList(java.util.ArrayList) List(java.util.List) HashMap(java.util.HashMap) Map(java.util.Map)

Example 5 with RouteCalculateUnit

use of io.mycat.route.parser.druid.RouteCalculateUnit in project Mycat-Server by MyCATApache.

the class DruidInsertParser method parserSingleInsert.

/**
	 * 单条insert(非批量)
	 * @param schema
	 * @param rrs
	 * @param partitionColumn
	 * @param tableName
	 * @param insertStmt
	 * @throws SQLNonTransientException
	 */
private void parserSingleInsert(SchemaConfig schema, RouteResultset rrs, String partitionColumn, String tableName, MySqlInsertStatement insertStmt) throws SQLNonTransientException {
    boolean isFound = false;
    for (int i = 0; i < insertStmt.getColumns().size(); i++) {
        if (partitionColumn.equalsIgnoreCase(StringUtil.removeBackquote(insertStmt.getColumns().get(i).toString()))) {
            //找到分片字段
            isFound = true;
            String column = StringUtil.removeBackquote(insertStmt.getColumns().get(i).toString());
            String value = StringUtil.removeBackquote(insertStmt.getValues().getValues().get(i).toString());
            RouteCalculateUnit routeCalculateUnit = new RouteCalculateUnit();
            routeCalculateUnit.addShardingExpr(tableName, column, value);
            ctx.addRouteCalculateUnit(routeCalculateUnit);
            //mycat是单分片键,找到了就返回
            break;
        }
    }
    if (!isFound) {
        //分片表的
        String msg = "bad insert sql (sharding column:" + partitionColumn + " not provided," + insertStmt;
        LOGGER.warn(msg);
        throw new SQLNonTransientException(msg);
    }
    //INSERT INTO TABLEName (a,b,c) VALUES (1,2,3) ON DUPLICATE KEY UPDATE c=c+1;
    if (insertStmt.getDuplicateKeyUpdate() != null) {
        List<SQLExpr> updateList = insertStmt.getDuplicateKeyUpdate();
        for (SQLExpr expr : updateList) {
            SQLBinaryOpExpr opExpr = (SQLBinaryOpExpr) expr;
            String column = StringUtil.removeBackquote(opExpr.getLeft().toString().toUpperCase());
            if (column.equals(partitionColumn)) {
                String msg = "Sharding column can't be updated: " + tableName + " -> " + partitionColumn;
                LOGGER.warn(msg);
                throw new SQLNonTransientException(msg);
            }
        }
    }
}
Also used : RouteCalculateUnit(io.mycat.route.parser.druid.RouteCalculateUnit) SQLNonTransientException(java.sql.SQLNonTransientException) SQLBinaryOpExpr(com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr) SQLExpr(com.alibaba.druid.sql.ast.SQLExpr)

Aggregations

RouteCalculateUnit (io.mycat.route.parser.druid.RouteCalculateUnit)7 SQLNonTransientException (java.sql.SQLNonTransientException)4 RouteResultset (io.mycat.route.RouteResultset)3 RouteResultsetNode (io.mycat.route.RouteResultsetNode)3 DruidShardingParseInfo (io.mycat.route.parser.druid.DruidShardingParseInfo)3 ArrayList (java.util.ArrayList)3 TreeSet (java.util.TreeSet)3 SQLStatement (com.alibaba.druid.sql.ast.SQLStatement)2 MySqlStatementParser (com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser)2 SQLStatementParser (com.alibaba.druid.sql.parser.SQLStatementParser)2 Condition (com.alibaba.druid.stat.TableStat.Condition)2 MycatSchemaStatVisitor (io.mycat.route.parser.druid.MycatSchemaStatVisitor)2 MycatStatementParser (io.mycat.route.parser.druid.MycatStatementParser)2 SQLSyntaxErrorException (java.sql.SQLSyntaxErrorException)2 SQLExpr (com.alibaba.druid.sql.ast.SQLExpr)1 SQLBinaryOpExpr (com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr)1 MySqlInsertStatement (com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlInsertStatement)1 SchemaConfig (io.mycat.config.model.SchemaConfig)1 RuleConfig (io.mycat.config.model.rule.RuleConfig)1 SlotFunction (io.mycat.route.function.SlotFunction)1