package org.opencloudb.route.util; import java.util.Collection; import java.util.Map; import org.apache.log4j.Logger; import org.opencloudb.MycatSystem; import org.opencloudb.cache.LayerCachePool; import org.opencloudb.config.model.SchemaConfig; import org.opencloudb.config.model.SystemConfig; import org.opencloudb.config.model.TableConfig; import org.opencloudb.net.FrontSession; import org.opencloudb.route.RouteResultset; import org.opencloudb.route.RouteResultsetNode; import org.opencloudb.route.SessionSQLPair; import org.opencloudb.util.StringUtil; /** * 从ServerRouterUtil中抽取的一些公用方法,路由解析工具类 * @author wang.dw * */ public class RouterUtil { private static final Logger LOGGER = Logger.getLogger(RouterUtil.class); /** * 移除执行语句中的数据库名 * * @param stmt * 执行语句 * @param schema * 数据库名 * @return 执行语句 * @author mycat */ public static String removeSchema(String stmt, String schema) { final String upStmt = stmt.toUpperCase(); final String upSchema = schema.toUpperCase() + "."; int strtPos = 0; int indx = 0; boolean flag = false; indx = upStmt.indexOf(upSchema, strtPos); if (indx < 0) { StringBuilder sb = new StringBuilder("`").append( schema.toUpperCase()).append("`."); indx = upStmt.indexOf(sb.toString(), strtPos); flag = true; if (indx < 0) { return stmt; } } StringBuilder sb = new StringBuilder(); while (indx > 0) { sb.append(stmt.substring(strtPos, indx)); strtPos = indx + upSchema.length(); if (flag) { strtPos += 2; } indx = upStmt.indexOf(upSchema, strtPos); } sb.append(stmt.substring(strtPos)); return sb.toString(); } /** * 获取第一个节点作为路由 * * @param rrs * 数据路由集合 * @param dataNode * 数据库所在节点 * @param stmt * 执行语句 * @return 数据路由集合 * @author mycat */ public static RouteResultset routeToSingleNode(RouteResultset rrs, String dataNode, String stmt) { if (dataNode == null) { return rrs; } RouteResultsetNode[] nodes = new RouteResultsetNode[1]; nodes[0] = new RouteResultsetNode(dataNode, rrs.getSqlType(), stmt); rrs.setNodes(nodes); return rrs; } /** * 获取table名字 * * @param stmt * 执行语句 * @param repPos * 开始位置和位数 * @return 表名 * @author mycat */ public static String getTableName(String stmt, int[] repPos) { int startPos = repPos[0]; int secInd = stmt.indexOf(' ', startPos + 1); if (secInd < 0) { secInd = stmt.length(); } repPos[1] = secInd; String tableName = stmt.substring(startPos, secInd).trim(); int ind2 = tableName.indexOf('.'); if (ind2 > 0) { tableName = tableName.substring(ind2 + 1); } return tableName; } /** * 获取语句中前关键字位置和占位个数表名位置 * * @param upStmt * 执行语句 * @param start * 开始位置 * @return int[]关键字位置和占位个数 * @author mycat */ public static int[] getCreateTablePos(String upStmt, int start) { String token1 = " CREATE "; String token2 = " TABLE "; int createInd = upStmt.indexOf(token1, start); int tabInd = upStmt.indexOf(token2, start); // 既包含CREATE又包含TABLE,且CREATE关键字在TABLE关键字之前 if (createInd > 0 && tabInd > 0 && tabInd > createInd) { return new int[] { tabInd, token2.length() }; } else { return new int[] { -1, token2.length() };// 不满足条件时,只关注第一个返回值为-1,第二个任意 } } /** * 获取语句中前关键字位置和占位个数表名位置 * * @param upStmt * 执行语句 * @param start * 开始位置 * @return int[]关键字位置和占位个数 * @author mycat */ public static int[] getSpecPos(String upStmt, int start) { String token1 = " FROM "; String token2 = " IN "; int tabInd1 = upStmt.indexOf(token1, start); int tabInd2 = upStmt.indexOf(token2, start); if (tabInd1 > 0) { if (tabInd2 < 0) { return new int[] { tabInd1, token1.length() }; } return (tabInd1 < tabInd2) ? new int[] { tabInd1, token1.length() } : new int[] { tabInd2, token2.length() }; } else { return new int[] { tabInd2, token2.length() }; } } /** * 获取开始位置后的 LIKE、WHERE 位置 如果不含 LIKE、WHERE 则返回执行语句的长度 * * @param upStmt * 执行sql * @param start * 开发位置 * @return int * @author mycat */ public static int getSpecEndPos(String upStmt, int start) { int tabInd = upStmt.indexOf(" LIKE ", start); if (tabInd < 0) { tabInd = upStmt.indexOf(" WHERE ", start); } if (tabInd < 0) { return upStmt.length(); } return tabInd; } public static boolean processWithMycatSeq(SystemConfig sysConfig, SchemaConfig schema, int sqlType, String origSQL, String charset, FrontSession session, LayerCachePool cachePool){ // check if origSQL is with global sequence // @micmiu it is just a simple judgement if (origSQL.indexOf(" MYCATSEQ_") != -1) { processSQL(session,schema,origSQL,sqlType); return true; } return false; } public static void processSQL(FrontSession session,SchemaConfig schema,String sql,int sqlType){ MycatSystem.getInstance().getSequnceProcessor().addNewSql(new SessionSQLPair(session, schema, sql, sqlType)); } public static boolean processInsert(SystemConfig sysConfig, SchemaConfig schema, int sqlType, String origSQL, String charset, FrontSession session, LayerCachePool cachePool){ String tableName = StringUtil.getTableName(origSQL).toUpperCase(); TableConfig tableConfig = schema.getTables().get(tableName); boolean processedInsert=false; if (null != tableConfig && tableConfig.isAutoIncrement()) { String primaryKey = tableConfig.getPrimaryKey(); processedInsert=processInsert(session,schema,sqlType,origSQL,tableName,primaryKey); } return processedInsert; } private static boolean isPKInFields(String origSQL,String primaryKey,int firstLeftBracketIndex,int firstRightBracketIndex){ boolean isPrimaryKeyInFields=false; String upperSQL=origSQL.substring(firstLeftBracketIndex,firstRightBracketIndex+1).toUpperCase(); for(int pkOffset=0,primaryKeyLength=primaryKey.length(),pkStart=0;;){ pkStart=upperSQL.indexOf(primaryKey, pkOffset); if(pkStart>=0 && pkStart<firstRightBracketIndex){ char pkSide=upperSQL.charAt(pkStart-1); if(pkSide<=' ' || pkSide=='`' || pkSide==',' || pkSide=='('){ pkSide=upperSQL.charAt(pkStart+primaryKey.length()); isPrimaryKeyInFields=pkSide<=' ' || pkSide=='`' || pkSide==',' || pkSide==')'; } if(isPrimaryKeyInFields){ break; } pkOffset=pkStart+primaryKeyLength; }else{ break; } } return isPrimaryKeyInFields; } public static boolean processInsert(FrontSession session,SchemaConfig schema,int sqlType,String origSQL,String tableName,String primaryKey){ int firstLeftBracketIndex = origSQL.indexOf("(") + 1; int firstRightBracketIndex = origSQL.indexOf(")"); boolean processedInsert=!isPKInFields(origSQL,primaryKey,firstLeftBracketIndex,firstRightBracketIndex); if(processedInsert){ processInsert(session,schema,sqlType,origSQL,tableName,primaryKey,firstLeftBracketIndex,firstRightBracketIndex); } return processedInsert; } private static void processInsert(FrontSession session,SchemaConfig schema,int sqlType,String origSQL,String tableName,String primaryKey,int firstLeftBracketIndex,int lastLeftBracketIndex){ int primaryKeyLength=primaryKey.length(); int insertSegOffset=firstLeftBracketIndex; String mycatSeqPrefix="next value for MYCATSEQ_"; int mycatSeqPrefixLength=mycatSeqPrefix.length(); int tableNameLength=tableName.length(); char[] newSQLBuf=new char[origSQL.length()+primaryKeyLength+mycatSeqPrefixLength+tableNameLength+2]; origSQL.getChars(0, firstLeftBracketIndex, newSQLBuf, 0); primaryKey.getChars(0,primaryKeyLength,newSQLBuf,insertSegOffset); insertSegOffset+=primaryKeyLength; newSQLBuf[insertSegOffset]=','; insertSegOffset++; origSQL.getChars(firstLeftBracketIndex,lastLeftBracketIndex,newSQLBuf,insertSegOffset); insertSegOffset+=lastLeftBracketIndex-firstLeftBracketIndex; mycatSeqPrefix.getChars(0, mycatSeqPrefixLength, newSQLBuf, insertSegOffset); insertSegOffset+=mycatSeqPrefixLength; tableName.getChars(0,tableNameLength,newSQLBuf,insertSegOffset); insertSegOffset+=tableNameLength; newSQLBuf[insertSegOffset]=','; insertSegOffset++; origSQL.getChars(lastLeftBracketIndex, origSQL.length(), newSQLBuf, insertSegOffset); processSQL(session,schema,new String(newSQLBuf),sqlType); } public static RouteResultset routeToMultiNode(boolean cache,RouteResultset rrs, Collection<String> dataNodes, String stmt) { RouteResultsetNode[] nodes = new RouteResultsetNode[dataNodes.size()]; int i = 0; for (String dataNode : dataNodes) { nodes[i++] = new RouteResultsetNode(dataNode, rrs.getSqlType(), stmt); } rrs.setCacheAble(cache); rrs.setNodes(nodes); return rrs; } public static void routeForTableMeta(RouteResultset rrs, SchemaConfig schema, String tableName, String sql) { String dataNode = getMetaReadDataNode(schema, tableName); RouteResultsetNode[] nodes = new RouteResultsetNode[1]; nodes[0] = new RouteResultsetNode(dataNode, rrs.getSqlType(), sql); rrs.setNodes(nodes); } /** * 根据标名随机获取一个节点 * * @param schema * 数据库名 * @param table * 表名 * @return 数据节点 * @author mycat */ private static String getMetaReadDataNode(SchemaConfig schema, String table) { // Table名字被转化为大写的,存储在schema table = table.toUpperCase(); String dataNode = null; Map<String, TableConfig> tables = schema.getTables(); TableConfig tc; if (tables != null && (tc = tables.get(table)) != null) { dataNode = tc.getRandomDataNode(); } return dataNode; } }