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;
}
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;
}
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;
}
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;
}
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);
}
}
}
}
Aggregations