前面,我们已经讲过了Mycat如何判断sql类型,然后针对不同类型的sql就行不同的处理【Mycat原理解析-SQL语句的处理】,下面,我们来看看其中的DDL语句,Mycat是怎么处理的。
结合ServerParse.java
中的代码,我们来看看Mycat支持的常见的DDL语句的。
- CREATE:create index
- DROP:drop index
- TRUNCATE:truncate table
- ALTER:alter table
针对DDL语句,Mycat没有提供专门的Handler,而是使用统一的ServerConnection.execute()
方法进行处理。下图展示了一条DDL语句简要的处理过程。
跟普通语句不同的地方就在于DDL语句的路由部分,下面来看看DDL语句路由部分的代码。
public static RouteResultset routeToDDLNode(RouteResultset rrs, int sqlType, String stmt,SchemaConfig schema) throws SQLSyntaxErrorException {
stmt = getFixedSql(stmt);
String tablename = "";
final String upStmt = stmt.toUpperCase();
//CREATE语句
if(upStmt.startsWith("CREATE")){
//CREATE INDEX语句
if (upStmt.contains("CREATE INDEX ")){
tablename = RouterUtil.getTableName(stmt, RouterUtil.getCreateIndexPos(upStmt, 0));
}else {
tablename = RouterUtil.getTableName(stmt, RouterUtil.getCreateTablePos(upStmt, 0));
}
//DROP语句
}else if(upStmt.startsWith("DROP")){
//DROP INDEX语句
if (upStmt.contains("DROP INDEX ")){
tablename = RouterUtil.getTableName(stmt, RouterUtil.getDropIndexPos(upStmt, 0));
}else {
tablename = RouterUtil.getTableName(stmt, RouterUtil.getDropTablePos(upStmt, 0));
}
}else if(upStmt.startsWith("ALTER")){
tablename = RouterUtil.getTableName(stmt, RouterUtil.getAlterTablePos(upStmt, 0));
}else if (upStmt.startsWith("TRUNCATE")){
tablename = RouterUtil.getTableName(stmt, RouterUtil.getTruncateTablePos(upStmt, 0));
}
tablename = tablename.toUpperCase();
if (schema.getTables().containsKey(tablename)){
if(ServerParse.DDL==sqlType){
List<String> dataNodes = new ArrayList<>();
Map<String, TableConfig> tables = schema.getTables();
TableConfig tc=tables.get(tablename);
if (tables != null && (tc != null)) {
dataNodes = tc.getDataNodes();
}
boolean isSlotFunction= tc.getRule() != null && tc.getRule().getRuleAlgorithm() instanceof SlotFunction;
Iterator<String> iterator1 = dataNodes.iterator();
int nodeSize = dataNodes.size();
RouteResultsetNode[] nodes = new RouteResultsetNode[nodeSize];
if(isSlotFunction){
stmt=changeCreateTable(schema,tablename,stmt);
}
for(int i=0;i<nodeSize;i++){
String name = iterator1.next();
nodes[i] = new RouteResultsetNode(name, sqlType, stmt);
nodes[i].setSource(rrs);
if(rrs.getDataNodeSlotMap().containsKey(name)){
nodes[i].setSlot(rrs.getDataNodeSlotMap().get(name));
} else if(isSlotFunction){
nodes[i].setSlot(-1);
}
}
rrs.setNodes(nodes);
}
return rrs;
}else if(schema.getDataNode()!=null){ //默认节点ddl
RouteResultsetNode[] nodes = new RouteResultsetNode[1];
nodes[0] = new RouteResultsetNode(schema.getDataNode(), sqlType, stmt);
nodes[0].setSource(rrs);
rrs.setNodes(nodes);
return rrs;
}
//both tablename and defaultnode null
LOGGER.error("table not in schema----"+tablename);
throw new SQLSyntaxErrorException("op table not in schema----"+tablename);
}
上面的代码主要做了下面两件事:
- 确定逻辑表名
- 构造RouteResultset对象(构造规则是每个dataNode对应一个RouteResultsetNode)。果逻辑库存在该表,根据TableConfig的配置来构造,如果不存在,根据逻辑库默认的dataNode来构造。