Search in sources :

Example 56 with SQLNonTransientException

use of java.sql.SQLNonTransientException in project Mycat-Server by MyCATApache.

the class DruidSelectParser method setLimitIFChange.

protected void setLimitIFChange(SQLStatement stmt, RouteResultset rrs, SchemaConfig schema, SQLBinaryOpExpr one, int firstrownum, int lastrownum) {
    rrs.setLimitStart(firstrownum);
    rrs.setLimitSize(lastrownum - firstrownum);
    LayerCachePool tableId2DataNodeCache = (LayerCachePool) MycatServer.getInstance().getCacheService().getCachePool("TableID2DataNodeCache");
    try {
        tryRoute(schema, rrs, tableId2DataNodeCache);
    } catch (SQLNonTransientException e) {
        throw new RuntimeException(e);
    }
    if (isNeedChangeLimit(rrs)) {
        one.setRight(new SQLIntegerExpr(0));
        String curentDbType = "db2".equalsIgnoreCase(this.getCurentDbType()) ? "oracle" : getCurentDbType();
        String sql = SQLUtils.toSQLString(stmt, curentDbType);
        ;
        rrs.changeNodeSqlAfterAddLimit(schema, getCurentDbType(), sql, 0, lastrownum, false);
        // 设置改写后的sql
        getCtx().setSql(sql);
    }
}
Also used : SQLNonTransientException(java.sql.SQLNonTransientException) LayerCachePool(io.mycat.cache.LayerCachePool) SQLIntegerExpr(com.alibaba.druid.sql.ast.expr.SQLIntegerExpr)

Example 57 with SQLNonTransientException

use of java.sql.SQLNonTransientException 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 58 with SQLNonTransientException

use of java.sql.SQLNonTransientException in project Mycat-Server by MyCATApache.

the class RouterUtil method routeByERParentKey.

/**
 * 根据 ER分片规则获取路由集合
 *
 * @param stmt            执行的语句
 * @param rrs      		     数据路由集合
 * @param tc	      	     表实体
 * @param joinKeyVal      连接属性
 * @return RouteResultset(数据路由集合)	 *
 * @throws SQLNonTransientException,IllegalShardingColumnValueException
 * @author mycat
 */
public static RouteResultset routeByERParentKey(ServerConnection sc, SchemaConfig schema, int sqlType, String stmt, RouteResultset rrs, TableConfig tc, String joinKeyVal) throws SQLNonTransientException {
    // 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, rrs.getDataNodeSlotMap());
        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;
}
Also used : SQLNonTransientException(java.sql.SQLNonTransientException) ColumnRoutePair(io.mycat.sqlengine.mpp.ColumnRoutePair) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet)

Example 59 with SQLNonTransientException

use of java.sql.SQLNonTransientException in project Mycat-Server by MyCATApache.

the class RouterUtil method processERChildTable.

/**
 * 该方法,返回是否是ER子表
 * @param schema
 * @param origSQL
 * @param sc
 * @return
 * @throws SQLNonTransientException
 *
 * 备注说明:
 *     edit by ding.w at 2017.4.28, 主要处理 CLIENT_MULTI_STATEMENTS(insert into ; insert into)的情况
 *     目前仅支持mysql,并COM_QUERY请求包中的所有insert语句要么全部是er表,要么全部不是
 */
public static boolean processERChildTable(final SchemaConfig schema, final String origSQL, final ServerConnection sc) throws SQLNonTransientException {
    MySqlStatementParser parser = new MySqlStatementParser(origSQL);
    List<SQLStatement> statements = parser.parseStatementList();
    if (statements == null || statements.isEmpty()) {
        throw new SQLNonTransientException(String.format("无效的SQL语句:%s", origSQL));
    }
    // 是否是er表
    boolean erFlag = false;
    for (SQLStatement stmt : statements) {
        MySqlInsertStatement insertStmt = (MySqlInsertStatement) stmt;
        String tableName = insertStmt.getTableName().getSimpleName().toUpperCase();
        final TableConfig tc = schema.getTables().get(tableName);
        if (null != tc && tc.isChildTable()) {
            erFlag = true;
            String sql = insertStmt.toString();
            final RouteResultset rrs = new RouteResultset(sql, ServerParse.INSERT);
            String joinKey = tc.getJoinKey();
            // 因为是Insert语句,用MySqlInsertStatement进行parse
            // MySqlInsertStatement insertStmt = (MySqlInsertStatement) (new MySqlStatementParser(origSQL)).parseInsert();
            // 判断条件完整性,取得解析后语句列中的joinkey列的index
            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);
            }
            // 取得joinkey的值
            String joinKeyVal = insertStmt.getValues().getValues().get(joinKeyIndex).toString();
            // 解决bug #938,当关联字段的值为char类型时,去掉前后"'"
            String realVal = joinKeyVal;
            if (joinKeyVal.startsWith("'") && joinKeyVal.endsWith("'") && joinKeyVal.length() > 2) {
                realVal = joinKeyVal.substring(1, joinKeyVal.length() - 1);
            }
            // try to route by ER parent partion key
            // 如果是二级子表(父表不再有父表),并且分片字段正好是joinkey字段,调用routeByERParentKey
            RouteResultset theRrs = RouterUtil.routeByERParentKey(sc, schema, ServerParse.INSERT, sql, rrs, tc, realVal);
            if (theRrs != 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);
                }
                // 继续处理下一条
                continue;
            }
            // route by sql query root parent's datanode
            // 如果不是二级子表或者分片字段不是joinKey字段结果为空,则启动异步线程去后台分片查询出datanode
            // 只要查询出上一级表的parentkey字段的对应值在哪个分片即可
            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());
                    return fetchHandler.execute(schema.getName(), findRootTBSql, tc.getRootParent().getDataNodes(), sc);
                }
            });
            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);
                        if (!sc.isAutocommit()) {
                            // 处于事务下失败, 必须回滚
                            sc.setTxInterrupt("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);
                    }
                    // 找到分片,进行插入(和其他的一样,需要判断是否需要全局自增ID)
                    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());
        } else if (erFlag) {
            throw new SQLNonTransientException(String.format("%s包含不是ER分片的表", origSQL));
        }
    }
    return erFlag;
}
Also used : FetchStoreNodeOfChildTableHandler(io.mycat.backend.mysql.nio.handler.FetchStoreNodeOfChildTableHandler) 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) SQLNonTransientException(java.sql.SQLNonTransientException) TableConfig(io.mycat.config.model.TableConfig) MySqlStatementParser(com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser) RouteResultset(io.mycat.route.RouteResultset)

Example 60 with SQLNonTransientException

use of java.sql.SQLNonTransientException in project Mycat-Server by MyCATApache.

the class RouterUtil method ruleByJoinValueCalculate.

/**
 * @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<ColumnRoutePair> it = colRoutePairSet.iterator();
        ColumnRoutePair joinCol = it.next();
        joinValue = joinCol.colValue;
    }
    Set<String> retNodeSet = new LinkedHashSet<String>();
    Set<String> nodeSet;
    if (tc.isSecondLevel() && tc.getParentTC().getPartitionColumn().equals(tc.getParentKey())) {
        // using
        // parent
        // rule to
        // find
        // datanode
        nodeSet = ruleCalculate(tc.getParentTC(), colRoutePairSet, rrs.getDataNodeSlotMap());
        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);
        // }
        return retNodeSet;
    } else {
        retNodeSet.addAll(tc.getParentTC().getDataNodes());
    }
    return retNodeSet;
}
Also used : LinkedHashSet(java.util.LinkedHashSet) SQLNonTransientException(java.sql.SQLNonTransientException) ColumnRoutePair(io.mycat.sqlengine.mpp.ColumnRoutePair)

Aggregations

SQLNonTransientException (java.sql.SQLNonTransientException)125 TableConfig (io.mycat.config.model.TableConfig)26 SQLException (java.sql.SQLException)23 Test (org.testng.annotations.Test)19 BaseTest (util.BaseTest)19 RouteResultset (io.mycat.route.RouteResultset)17 TableConfig (com.actiontech.dble.config.model.TableConfig)15 HashMap (java.util.HashMap)14 MySqlStatementParser (com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser)13 RouteResultsetNode (io.mycat.route.RouteResultsetNode)13 HashSet (java.util.HashSet)13 SQLExpr (com.alibaba.druid.sql.ast.SQLExpr)12 ColumnRoutePair (io.mycat.sqlengine.mpp.ColumnRoutePair)12 LinkedHashSet (java.util.LinkedHashSet)12 SchemaConfig (com.actiontech.dble.config.model.SchemaConfig)11 SQLStatement (com.alibaba.druid.sql.ast.SQLStatement)11 SchemaInfo (com.actiontech.dble.server.util.SchemaUtil.SchemaInfo)10 Map (java.util.Map)10 SlotFunction (io.mycat.route.function.SlotFunction)9 SQLExprTableSource (com.alibaba.druid.sql.ast.statement.SQLExprTableSource)8