Example #1
0
  /**
   * @param schema
   * @param ctx
   * @param tc
   * @return true表示校验通过,false表示检验不通过
   */
  public static boolean checkRuleRequired(
      SchemaConfig schema,
      DruidShardingParseInfo ctx,
      RouteCalculateUnit routeUnit,
      TableConfig tc) {
    if (!tc.isRuleRequired()) {
      return true;
    }
    boolean hasRequiredValue = false;
    String tableName = tc.getName();
    if (routeUnit.getTablesAndConditions().get(tableName) == null
        || routeUnit.getTablesAndConditions().get(tableName).size() == 0) {
      hasRequiredValue = false;
    } else {
      for (Map.Entry<String, Set<ColumnRoutePair>> condition :
          routeUnit.getTablesAndConditions().get(tableName).entrySet()) {

        String colName = condition.getKey();
        // 条件字段是拆分字段
        if (colName.equals(tc.getPartitionColumn())) {
          hasRequiredValue = true;
          break;
        }
      }
    }
    return hasRequiredValue;
  }
Example #2
0
 /**
  * 根据标名随机获取一个节点
  *
  * @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;
 }
Example #3
0
 public static boolean processInsert(
     SchemaConfig schema, int sqlType, String origSQL, MySQLFrontConnection sc)
     throws SQLNonTransientException {
   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(sc, schema, sqlType, origSQL, tableName, primaryKey);
   }
   return processedInsert;
 }
Example #4
0
 public static boolean isAllGlobalTable(DruidShardingParseInfo ctx, SchemaConfig schema) {
   boolean isAllGlobal = false;
   for (String table : ctx.getTables()) {
     TableConfig tableConfig = schema.getTables().get(table);
     if (tableConfig != null && tableConfig.isGlobalTable()) {
       isAllGlobal = true;
     } else {
       return false;
     }
   }
   return isAllGlobal;
 }
Example #5
0
  /**
   * 修复DDL路由
   *
   * @return RouteResultset
   * @author aStoneGod
   */
  public static RouteResultset routeToDDLNode(
      RouteResultset rrs, int sqlType, String stmt, SchemaConfig schema)
      throws SQLSyntaxErrorException {
    // 检查表是否在配置文件中
    stmt = getFixedSql(stmt);
    String tablename = "";
    final String upStmt = stmt.toUpperCase();
    if (upStmt.startsWith("CREATE")) {
      tablename = RouterUtil.getTableName(stmt, RouterUtil.getCreateTablePos(upStmt, 0));
    } else if (upStmt.startsWith("DROP")) {
      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;
        if (tables != null && (tc = tables.get(tablename)) != null) {
          dataNodes = tc.getDataNodes();
        }
        Iterator<String> iterator1 = dataNodes.iterator();
        int nodeSize = dataNodes.size();
        RouteResultsetNode[] nodes = new RouteResultsetNode[nodeSize];

        for (int i = 0; i < nodeSize; i++) {
          String name = iterator1.next();
          nodes[i] = new RouteResultsetNode(name, sqlType, stmt);
        }
        rrs.setNodes(nodes);
      }
      return rrs;
    } else if (schema.getDataNode() != null) { // 默认节点ddl
      RouteResultsetNode[] nodes = new RouteResultsetNode[1];
      nodes[0] = new RouteResultsetNode(schema.getDataNode(), sqlType, stmt);
      rrs.setNodes(nodes);
      return rrs;
    }
    // 不在,返回null
    LOGGER.error("table not in schema----" + tablename);
    throw new SQLSyntaxErrorException("op table not in schema----" + tablename);
  }
Example #6
0
 /** @return dataNodeIndex -&gt; [partitionKeysValueTuple+] */
 public static Set<String> ruleCalculate(TableConfig tc, Set<ColumnRoutePair> colRoutePairSet) {
   Set<String> routeNodeSet = new LinkedHashSet<String>();
   String col = tc.getRule().getColumn();
   RuleConfig rule = tc.getRule();
   AbstractPartitionAlgorithm algorithm = rule.getRuleAlgorithm();
   for (ColumnRoutePair colPair : colRoutePairSet) {
     if (colPair.colValue != null) {
       Integer nodeIndx = algorithm.calculate(colPair.colValue);
       if (nodeIndx == null) {
         throw new IllegalArgumentException(
             "can't find datanode for sharding column:" + col + " val:" + colPair.colValue);
       } else {
         String dataNode = tc.getDataNodes().get(nodeIndx);
         routeNodeSet.add(dataNode);
         colPair.setNodeId(nodeIndx);
       }
     } else if (colPair.rangeValue != null) {
       Integer[] nodeRange =
           algorithm.calculateRange(
               String.valueOf(colPair.rangeValue.beginValue),
               String.valueOf(colPair.rangeValue.endValue));
       if (nodeRange != null) {
         /** 不能确认 colPair的 nodeid是否会有其它影响 */
         if (nodeRange.length == 0) {
           routeNodeSet.addAll(tc.getDataNodes());
         } else {
           ArrayList<String> dataNodes = tc.getDataNodes();
           String dataNode = null;
           for (Integer nodeId : nodeRange) {
             dataNode = dataNodes.get(nodeId);
             routeNodeSet.add(dataNode);
           }
         }
       }
     }
   }
   return routeNodeSet;
 }
Example #7
0
 /**
  * 根据 ER分片规则获取路由集合
  *
  * @param stmt 执行的语句
  * @param rrs 数据路由集合
  * @param tc 表实体
  * @param joinKeyVal 连接属性
  * @return RouteResultset(数据路由集合)
  * @throws SQLNonTransientException
  * @author mycat
  */
 public static RouteResultset routeByERParentKey(
     MySQLFrontConnection sc,
     SchemaConfig schema,
     int sqlType,
     String stmt,
     RouteResultset rrs,
     TableConfig tc,
     String joinKeyVal)
     throws SQLNonTransientException {
   // only has one parent level and ER parent key is parent
   // table's partition key
   if (tc.isSecondLevel()
       && tc.getParentTC().getPartitionColumn().equals(tc.getParentKey())) { // using
     // parent
     // rule to
     // find
     // datanode
     Set<ColumnRoutePair> parentColVal = new HashSet<ColumnRoutePair>(1);
     ColumnRoutePair pair = new ColumnRoutePair(joinKeyVal);
     parentColVal.add(pair);
     Set<String> dataNodeSet = ruleCalculate(tc.getParentTC(), parentColVal);
     if (dataNodeSet.isEmpty() || dataNodeSet.size() > 1) {
       throw new SQLNonTransientException(
           "parent key can't find  valid datanode ,expect 1 but found: " + dataNodeSet.size());
     }
     String dn = dataNodeSet.iterator().next();
     if (LOGGER.isDebugEnabled()) {
       LOGGER.debug(
           "found partion node (using parent partion rule directly) for child table to insert  "
               + dn
               + " sql :"
               + stmt);
     }
     return RouterUtil.routeToSingleNode(rrs, dn, stmt);
   }
   return null;
 }
Example #8
0
  /**
   * 处理分库表路由
   *
   * @param schema
   * @param tablesAndConditions
   * @param tablesRouteMap
   * @throws SQLNonTransientException
   */
  public static void findRouteWithcConditionsForTables(
      SchemaConfig schema,
      RouteResultset rrs,
      Map<String, Map<String, Set<ColumnRoutePair>>> tablesAndConditions,
      Map<String, Set<String>> tablesRouteMap,
      String sql,
      LayerCachePool cachePool,
      boolean isSelect)
      throws SQLNonTransientException {
    // 为分库表找路由
    for (Map.Entry<String, Map<String, Set<ColumnRoutePair>>> entry :
        tablesAndConditions.entrySet()) {
      String tableName = entry.getKey().toUpperCase();
      TableConfig tableConfig = schema.getTables().get(tableName);
      if (tableConfig == null) {
        String msg =
            "can't find table define in schema " + tableName + " schema:" + schema.getName();
        LOGGER.warn(msg);
        throw new SQLNonTransientException(msg);
      }
      // 全局表或者不分库的表略过(全局表后面再计算)
      if (tableConfig.isGlobalTable()
          || schema.getTables().get(tableName).getDataNodes().size() == 1) {
        continue;
      } else { // 非全局表:分库表、childTable、其他
        Map<String, Set<ColumnRoutePair>> columnsMap = entry.getValue();
        String joinKey = tableConfig.getJoinKey();
        String partionCol = tableConfig.getPartitionColumn();
        String primaryKey = tableConfig.getPrimaryKey();
        boolean isFoundPartitionValue =
            partionCol != null && entry.getValue().get(partionCol) != null;
        boolean isLoadData = false;
        if (LOGGER.isDebugEnabled()) {
          if (sql.startsWith(LoadData.loadDataHint)
              || rrs.isLoadData()) { // 由于load data一次会计算很多路由数据,如果输出此日志会极大降低load data的性能
            isLoadData = true;
          }
        }
        if (entry.getValue().get(primaryKey) != null
            && entry.getValue().size() == 1
            && !isLoadData) { // 主键查找
          // try by primary key if found in cache
          Set<ColumnRoutePair> primaryKeyPairs = entry.getValue().get(primaryKey);
          if (primaryKeyPairs != null) {
            if (LOGGER.isDebugEnabled()) {
              LOGGER.debug("try to find cache by primary key ");
            }
            String tableKey = schema.getName() + '_' + tableName;
            boolean allFound = true;
            for (ColumnRoutePair pair : primaryKeyPairs) { // 可能id in(1,2,3)多主键
              String cacheKey = pair.colValue;
              String dataNode = (String) cachePool.get(tableKey, cacheKey);
              if (dataNode == null) {
                allFound = false;
                continue;
              } else {
                if (tablesRouteMap.get(tableName) == null) {
                  tablesRouteMap.put(tableName, new HashSet<String>());
                }
                tablesRouteMap.get(tableName).add(dataNode);
                continue;
              }
            }
            if (!allFound) {
              // need cache primary key ->datanode relation
              if (isSelect && tableConfig.getPrimaryKey() != null) {
                rrs.setPrimaryKey(tableKey + '.' + tableConfig.getPrimaryKey());
              }
            } else { // 主键缓存中找到了就执行循环的下一轮
              continue;
            }
          }
        }
        if (isFoundPartitionValue) { // 分库表
          Set<ColumnRoutePair> partitionValue = columnsMap.get(partionCol);
          if (partitionValue == null || partitionValue.size() == 0) {
            if (tablesRouteMap.get(tableName) == null) {
              tablesRouteMap.put(tableName, new HashSet<String>());
            }
            tablesRouteMap.get(tableName).addAll(tableConfig.getDataNodes());
          } else {
            for (ColumnRoutePair pair : partitionValue) {
              if (pair.colValue != null) {
                Integer nodeIndex =
                    tableConfig.getRule().getRuleAlgorithm().calculate(pair.colValue);
                if (nodeIndex == null) {
                  String msg =
                      "can't find any valid datanode :"
                          + tableConfig.getName()
                          + " -> "
                          + tableConfig.getPartitionColumn()
                          + " -> "
                          + pair.colValue;
                  LOGGER.warn(msg);
                  throw new SQLNonTransientException(msg);
                }
                String node = tableConfig.getDataNodes().get(nodeIndex);
                if (node != null) {
                  if (tablesRouteMap.get(tableName) == null) {
                    tablesRouteMap.put(tableName, new HashSet<String>());
                  }
                  tablesRouteMap.get(tableName).add(node);
                }
              }
              if (pair.rangeValue != null) {
                Integer[] nodeIndexs =
                    tableConfig
                        .getRule()
                        .getRuleAlgorithm()
                        .calculateRange(
                            pair.rangeValue.beginValue.toString(),
                            pair.rangeValue.endValue.toString());
                for (Integer idx : nodeIndexs) {
                  String node = tableConfig.getDataNodes().get(idx);
                  if (node != null) {
                    if (tablesRouteMap.get(tableName) == null) {
                      tablesRouteMap.put(tableName, new HashSet<String>());
                    }
                    tablesRouteMap.get(tableName).add(node);
                  }
                }
              }
            }
          }
        } else if (joinKey != null
            && columnsMap.get(joinKey) != null
            && columnsMap.get(joinKey).size()
                != 0) { // childTable  (如果是select 语句的父子表join)之前要找到root table,将childTable移除,只留下root
                        // table
          Set<ColumnRoutePair> joinKeyValue = columnsMap.get(joinKey);

          ColumnRoutePair joinCol = null;

          Set<String> dataNodeSet = ruleByJoinValueCalculate(rrs, tableConfig, joinKeyValue);

          if (dataNodeSet.isEmpty()) {
            throw new SQLNonTransientException("parent key can't find any valid datanode ");
          }
          if (LOGGER.isDebugEnabled()) {
            LOGGER.debug(
                "found partion nodes (using parent partion rule directly) for child table to update  "
                    + Arrays.toString(dataNodeSet.toArray())
                    + " sql :"
                    + sql);
          }
          if (dataNodeSet.size() > 1) {
            routeToMultiNode(rrs.isCacheAble(), rrs, dataNodeSet, sql);
            rrs.setFinishedRoute(true);
            return;
          } else {
            rrs.setCacheAble(true);
            routeToSingleNode(rrs, dataNodeSet.iterator().next(), sql);
            return;
          }

        } else {
          // 没找到拆分字段,该表的所有节点都路由
          if (tablesRouteMap.get(tableName) == null) {
            tablesRouteMap.put(tableName, new HashSet<String>());
          }
          tablesRouteMap.get(tableName).addAll(tableConfig.getDataNodes());
        }
      }
    }
  }
Example #9
0
  /**
   * 单表路由
   *
   * @param schema
   * @param ctx
   * @param tableName
   * @param rrs
   * @param isSelect
   * @return
   * @throws SQLNonTransientException
   */
  public static RouteResultset tryRouteForOneTable(
      SchemaConfig schema,
      DruidShardingParseInfo ctx,
      RouteCalculateUnit routeUnit,
      String tableName,
      RouteResultset rrs,
      boolean isSelect,
      LayerCachePool cachePool)
      throws SQLNonTransientException {
    if (isNoSharding(schema, tableName)) {
      return routeToSingleNode(rrs, schema.getDataNode(), ctx.getSql());
    }

    TableConfig tc = schema.getTables().get(tableName);
    if (tc == null) {
      String msg = "can't find table define in schema " + tableName + " schema:" + schema.getName();
      LOGGER.warn(msg);
      throw new SQLNonTransientException(msg);
    }
    if (tc.isGlobalTable()) { // 全局表
      if (isSelect) {
        // global select ,not cache route result
        rrs.setCacheAble(false);
        return routeToSingleNode(rrs, tc.getRandomDataNode(), ctx.getSql());
      } else { // insert into 全局表的记录
        return routeToMultiNode(false, rrs, tc.getDataNodes(), ctx.getSql(), true);
      }
    } else { // 单表或者分库表
      if (!checkRuleRequired(schema, ctx, routeUnit, tc)) {
        throw new IllegalArgumentException(
            "route rule for table " + tc.getName() + " is required: " + ctx.getSql());
      }
      if (tc.getPartitionColumn() == null && !tc.isSecondLevel()) { // 单表且不是childTable
        //				return RouterUtil.routeToSingleNode(rrs, tc.getDataNodes().get(0),ctx.getSql());
        return routeToMultiNode(rrs.isCacheAble(), rrs, tc.getDataNodes(), ctx.getSql());
      } else {
        // 每个表对应的路由映射
        Map<String, Set<String>> tablesRouteMap = new HashMap<String, Set<String>>();
        if (routeUnit.getTablesAndConditions() != null
            && routeUnit.getTablesAndConditions().size() > 0) {
          RouterUtil.findRouteWithcConditionsForTables(
              schema,
              rrs,
              routeUnit.getTablesAndConditions(),
              tablesRouteMap,
              ctx.getSql(),
              cachePool,
              isSelect);
          if (rrs.isFinishedRoute()) {
            return rrs;
          }
        }

        if (tablesRouteMap.get(tableName) == null) {
          return routeToMultiNode(rrs.isCacheAble(), rrs, tc.getDataNodes(), ctx.getSql());
        } else {
          //					boolean isCache = rrs.isCacheAble();
          //					if(tablesRouteMap.get(tableName).size() > 1) {
          //
          //					}
          return routeToMultiNode(
              rrs.isCacheAble(), rrs, tablesRouteMap.get(tableName), ctx.getSql());
        }
      }
    }
  }
Example #10
0
  /**
   * 多表路由
   *
   * @param schema
   * @param ctx
   * @param tables
   * @param rrs
   * @param isSelect
   * @return
   * @throws SQLNonTransientException
   */
  public static RouteResultset tryRouteForTables(
      SchemaConfig schema,
      DruidShardingParseInfo ctx,
      RouteCalculateUnit routeUnit,
      RouteResultset rrs,
      boolean isSelect,
      LayerCachePool cachePool)
      throws SQLNonTransientException {
    List<String> tables = ctx.getTables();
    if (schema.isNoSharding() || (tables.size() >= 1 && isNoSharding(schema, tables.get(0)))) {
      return routeToSingleNode(rrs, schema.getDataNode(), ctx.getSql());
    }

    // 只有一个表的
    if (tables.size() == 1) {
      return RouterUtil.tryRouteForOneTable(
          schema, ctx, routeUnit, tables.get(0), rrs, isSelect, cachePool);
    }

    Set<String> retNodesSet = new HashSet<String>();
    // 每个表对应的路由映射
    Map<String, Set<String>> tablesRouteMap = new HashMap<String, Set<String>>();

    // 分库解析信息不为空
    Map<String, Map<String, Set<ColumnRoutePair>>> tablesAndConditions =
        routeUnit.getTablesAndConditions();
    if (tablesAndConditions != null && tablesAndConditions.size() > 0) {
      // 为分库表找路由
      RouterUtil.findRouteWithcConditionsForTables(
          schema, rrs, tablesAndConditions, tablesRouteMap, ctx.getSql(), cachePool, isSelect);
      if (rrs.isFinishedRoute()) {
        return rrs;
      }
    }

    // 为全局表和单库表找路由
    for (String tableName : tables) {
      TableConfig tableConfig = schema.getTables().get(tableName.toUpperCase());
      if (tableConfig == null) {
        String msg =
            "can't find table define in schema " + tableName + " schema:" + schema.getName();
        LOGGER.warn(msg);
        throw new SQLNonTransientException(msg);
      }
      if (tableConfig.isGlobalTable()) { // 全局表
        if (tablesRouteMap.get(tableName) == null) {
          tablesRouteMap.put(tableName, new HashSet<String>());
        }
        tablesRouteMap.get(tableName).addAll(tableConfig.getDataNodes());
      } else if (tablesRouteMap.get(tableName) == null) { // 余下的表都是单库表
        tablesRouteMap.put(tableName, new HashSet<String>());
        tablesRouteMap.get(tableName).addAll(tableConfig.getDataNodes());
      }
    }

    boolean isFirstAdd = true;
    for (Map.Entry<String, Set<String>> entry : tablesRouteMap.entrySet()) {
      if (entry.getValue() == null || entry.getValue().size() == 0) {
        throw new SQLNonTransientException("parent key can't find any valid datanode ");
      } else {
        if (isFirstAdd) {
          retNodesSet.addAll(entry.getValue());
          isFirstAdd = false;
        } else {
          retNodesSet.retainAll(entry.getValue());
          if (retNodesSet.size() == 0) { // 两个表的路由无交集
            String errMsg =
                "invalid route in sql, multi tables found but datanode has no intersection "
                    + " sql:"
                    + ctx.getSql();
            LOGGER.warn(errMsg);
            throw new SQLNonTransientException(errMsg);
          }
        }
      }
    }

    if (retNodesSet != null && retNodesSet.size() > 0) {
      if (retNodesSet.size() > 1 && isAllGlobalTable(ctx, schema)) {
        // mulit routes ,not cache route result
        if (isSelect) {
          rrs.setCacheAble(false);
          routeToSingleNode(rrs, retNodesSet.iterator().next(), ctx.getSql());
        } else { // delete 删除全局表的记录
          routeToMultiNode(isSelect, rrs, retNodesSet, ctx.getSql(), true);
        }

      } else {
        routeToMultiNode(isSelect, rrs, retNodesSet, ctx.getSql());
      }
    }
    return rrs;
  }
Example #11
0
  /** @return dataNodeIndex -&gt; [partitionKeysValueTuple+] */
  public static Set<String> ruleByJoinValueCalculate(
      RouteResultset rrs, TableConfig tc, Set<ColumnRoutePair> colRoutePairSet)
      throws SQLNonTransientException {

    String joinValue = "";

    if (colRoutePairSet.size() > 1) {
      LOGGER.warn("joinKey can't have multi Value");
    } else {
      Iterator it = colRoutePairSet.iterator();
      ColumnRoutePair joinCol = (ColumnRoutePair) it.next();
      joinValue = joinCol.colValue;
    }

    Set<String> retNodeSet = new LinkedHashSet<String>();

    Set<String> nodeSet = new LinkedHashSet<String>();
    if (tc.isSecondLevel()
        && tc.getParentTC().getPartitionColumn().equals(tc.getParentKey())) { // using
      // parent
      // rule to
      // find
      // datanode

      nodeSet = ruleCalculate(tc.getParentTC(), colRoutePairSet);
      if (nodeSet.isEmpty()) {
        throw new SQLNonTransientException(
            "parent key can't find  valid datanode ,expect 1 but found: " + nodeSet.size());
      }
      if (LOGGER.isDebugEnabled()) {
        LOGGER.debug(
            "found partion node (using parent partion rule directly) for child table to insert  "
                + nodeSet
                + " sql :"
                + rrs.getStatement());
      }
      retNodeSet.addAll(nodeSet);

      //			for(ColumnRoutePair pair : colRoutePairSet) {
      //				nodeSet = ruleCalculate(tc.getParentTC(),colRoutePairSet);
      //				if (nodeSet.isEmpty() || nodeSet.size() > 1) {//an exception would be thrown, if sql was
      // executed on more than on sharding
      //					throw new SQLNonTransientException(
      //							"parent key can't find  valid datanode ,expect 1 but found: "
      //									+ nodeSet.size());
      //				}
      //				String dn = nodeSet.iterator().next();
      //				if (LOGGER.isDebugEnabled()) {
      //					LOGGER.debug("found partion node (using parent partion rule directly) for child table
      // to insert  "
      //							+ dn + " sql :" + rrs.getStatement());
      //				}
      //				retNodeSet.addAll(nodeSet);
      //			}
      return retNodeSet;
    } else {
      retNodeSet.addAll(tc.getParentTC().getDataNodes());
    }

    return retNodeSet;
  }
Example #12
0
  public static boolean processERChildTable(
      final SchemaConfig schema, final String origSQL, final MySQLFrontConnection sc)
      throws SQLNonTransientException {
    String tableName = StringUtil.getTableName(origSQL).toUpperCase();
    final TableConfig tc = schema.getTables().get(tableName);

    if (null != tc && tc.isChildTable()) {
      final RouteResultset rrs = new RouteResultset(origSQL, ServerParse.INSERT);
      String joinKey = tc.getJoinKey();
      MySqlInsertStatement insertStmt =
          (MySqlInsertStatement) (new MySqlStatementParser(origSQL)).parseInsert();
      int joinKeyIndex = getJoinKeyIndex(insertStmt.getColumns(), joinKey);

      if (joinKeyIndex == -1) {
        String inf = "joinKey not provided :" + tc.getJoinKey() + "," + insertStmt;
        LOGGER.warn(inf);
        throw new SQLNonTransientException(inf);
      }
      if (isMultiInsert(insertStmt)) {
        String msg = "ChildTable multi insert not provided";
        LOGGER.warn(msg);
        throw new SQLNonTransientException(msg);
      }

      String joinKeyVal = insertStmt.getValues().getValues().get(joinKeyIndex).toString();

      String sql = insertStmt.toString();

      // try to route by ER parent partion key
      // RouteResultset theRrs = RouterUtil.routeByERParentKey(sc,schema,ServerParse.INSERT,sql,
      // rrs, tc, joinKeyVal);

      if (null != null) {
        boolean processedInsert = false;
        if (sc != null && tc.isAutoIncrement()) {
          String primaryKey = tc.getPrimaryKey();
          processedInsert =
              processInsert(sc, schema, ServerParse.INSERT, sql, tc.getName(), primaryKey);
        }
        if (processedInsert == false) {
          rrs.setFinishedRoute(true);
          sc.getSession2().execute(rrs, ServerParse.INSERT);
        }
        return true;
      }

      // route by sql query root parent's datanode
      final String findRootTBSql = tc.getLocateRTableKeySql().toLowerCase() + joinKeyVal;
      if (LOGGER.isDebugEnabled()) {
        LOGGER.debug("find root parent's node sql " + findRootTBSql);
      }

      ListenableFuture<String> listenableFuture =
          MycatServer.getInstance()
              .getListeningExecutorService()
              .submit(
                  new Callable<String>() {
                    @Override
                    public String call() throws Exception {
                      FetchStoreNodeOfChildTableHandler fetchHandler =
                          new FetchStoreNodeOfChildTableHandler();
                      return fetchHandler.execute(
                          schema.getName(), findRootTBSql, tc.getRootParent().getDataNodes());
                    }
                  });

      Futures.addCallback(
          listenableFuture,
          new FutureCallback<String>() {
            @Override
            public void onSuccess(String result) {
              if (Strings.isNullOrEmpty(result)) {
                StringBuilder s = new StringBuilder();
                LOGGER.warn(
                    s.append(sc.getSession2()).append(origSQL).toString()
                        + " err:"
                        + "can't find (root) parent sharding node for sql:"
                        + origSQL);
                sc.writeErrMessage(
                    ErrorCode.ER_PARSE_ERROR,
                    "can't find (root) parent sharding node for sql:" + origSQL);
                return;
              }

              if (LOGGER.isDebugEnabled()) {
                LOGGER.debug(
                    "found partion node for child table to insert " + result + " sql :" + origSQL);
              }
              boolean processedInsert = false;
              if (sc != null && tc.isAutoIncrement()) {
                try {
                  String primaryKey = tc.getPrimaryKey();
                  processedInsert =
                      processInsert(
                          sc, schema, ServerParse.INSERT, origSQL, tc.getName(), primaryKey);
                } catch (SQLNonTransientException e) {
                  LOGGER.warn("sequence processInsert error,", e);
                  sc.writeErrMessage(
                      ErrorCode.ER_PARSE_ERROR, "sequence processInsert error," + e.getMessage());
                }
              }
              if (processedInsert == false) {
                RouteResultset executeRrs = RouterUtil.routeToSingleNode(rrs, result, origSQL);
                sc.getSession2().execute(executeRrs, ServerParse.INSERT);
              }
            }

            @Override
            public void onFailure(Throwable t) {
              StringBuilder s = new StringBuilder();
              LOGGER.warn(
                  s.append(sc.getSession2()).append(origSQL).toString() + " err:" + t.getMessage());
              sc.writeErrMessage(ErrorCode.ER_PARSE_ERROR, t.getMessage() + " " + s.toString());
            }
          },
          MycatServer.getInstance().getListeningExecutorService());
      return true;
    }
    return false;
  }