Search in sources :

Example 26 with TableConfig

use of io.mycat.config.model.TableConfig in project Mycat-Server by MyCATApache.

the class RouterUtil method processInsert.

public static boolean processInsert(SchemaConfig schema, int sqlType, String origSQL, ServerConnection 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;
}
Also used : TableConfig(io.mycat.config.model.TableConfig)

Example 27 with TableConfig

use of io.mycat.config.model.TableConfig 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 28 with TableConfig

use of io.mycat.config.model.TableConfig in project Mycat-Server by MyCATApache.

the class RouterUtil method routeToDDLNode.

/**
 * 修复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")) {
        if (upStmt.contains("CREATE INDEX ") || upStmt.contains("CREATE UNIQUE INDEX ")) {
            tablename = RouterUtil.getTableName(stmt, RouterUtil.getCreateIndexPos(upStmt, 0));
        } else {
            tablename = RouterUtil.getTableName(stmt, RouterUtil.getCreateTablePos(upStmt, 0));
        }
    } else if (upStmt.startsWith("DROP")) {
        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);
}
Also used : RouteResultsetNode(io.mycat.route.RouteResultsetNode) ArrayList(java.util.ArrayList) SQLSyntaxErrorException(java.sql.SQLSyntaxErrorException) TableConfig(io.mycat.config.model.TableConfig) SlotFunction(io.mycat.route.function.SlotFunction)

Example 29 with TableConfig

use of io.mycat.config.model.TableConfig in project Mycat-Server by MyCATApache.

the class ExplainHandler method isMycatSeq.

private static boolean isMycatSeq(String stmt, SchemaConfig schema) {
    if (pattern.matcher(stmt).find()) {
        return true;
    }
    SQLStatementParser parser = new MySqlStatementParser(stmt);
    MySqlInsertStatement statement = (MySqlInsertStatement) parser.parseStatement();
    String tableName = statement.getTableName().getSimpleName();
    TableConfig tableConfig = schema.getTables().get(tableName.toUpperCase());
    if (tableConfig == null) {
        return false;
    }
    if (tableConfig.isAutoIncrement()) {
        boolean isHasIdInSql = false;
        String primaryKey = tableConfig.getPrimaryKey();
        List<SQLExpr> columns = statement.getColumns();
        for (SQLExpr column : columns) {
            String columnName = column.toString();
            if (primaryKey.equalsIgnoreCase(columnName)) {
                isHasIdInSql = true;
                break;
            }
        }
        if (!isHasIdInSql) {
            return true;
        }
    }
    return false;
}
Also used : SQLStatementParser(com.alibaba.druid.sql.parser.SQLStatementParser) TableConfig(io.mycat.config.model.TableConfig) MySqlInsertStatement(com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlInsertStatement) MySqlStatementParser(com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser) SQLExpr(com.alibaba.druid.sql.ast.SQLExpr)

Example 30 with TableConfig

use of io.mycat.config.model.TableConfig in project Mycat-Server by MyCATApache.

the class MigrateHandler method handle.

public static void handle(String stmt, ServerConnection c) {
    Map<String, String> map = parse(stmt);
    String table = map.get("table");
    String add = map.get("add");
    if (table == null) {
        writeErrMessage(c, "table cannot be null");
        return;
    }
    if (add == null) {
        writeErrMessage(c, "add cannot be null");
        return;
    }
    String taskID = getUUID();
    try {
        SchemaConfig schemaConfig = MycatServer.getInstance().getConfig().getSchemas().get(c.getSchema());
        TableConfig tableConfig = schemaConfig.getTables().get(table.toUpperCase());
        AbstractPartitionAlgorithm algorithm = tableConfig.getRule().getRuleAlgorithm();
        if (!(algorithm instanceof PartitionByCRC32PreSlot)) {
            writeErrMessage(c, "table: " + table + " rule is not be PartitionByCRC32PreSlot");
            return;
        }
        Map<Integer, List<Range>> integerListMap = ((PartitionByCRC32PreSlot) algorithm).getRangeMap();
        integerListMap = (Map<Integer, List<Range>>) ObjectUtil.copyObject(integerListMap);
        ArrayList<String> oldDataNodes = tableConfig.getDataNodes();
        List<String> newDataNodes = Splitter.on(",").omitEmptyStrings().trimResults().splitToList(add);
        Map<String, List<MigrateTask>> tasks = MigrateUtils.balanceExpand(table, integerListMap, oldDataNodes, newDataNodes, PartitionByCRC32PreSlot.DEFAULT_SLOTS_NUM);
        CuratorTransactionFinal transactionFinal = null;
        String taskBase = ZKUtils.getZKBasePath() + "migrate/" + c.getSchema();
        String taskPath = taskBase + "/" + taskID;
        CuratorFramework client = ZKUtils.getConnection();
        // 校验 之前同一个表的迁移任务未完成,则jzhi禁止继续
        if (client.checkExists().forPath(taskBase) != null) {
            List<String> childTaskList = client.getChildren().forPath(taskBase);
            for (String child : childTaskList) {
                TaskNode taskNode = JSON.parseObject(ZKUtils.getConnection().getData().forPath(taskBase + "/" + child), TaskNode.class);
                if (taskNode.getSchema().equalsIgnoreCase(c.getSchema()) && table.equalsIgnoreCase(taskNode.getTable()) && taskNode.getStatus() < 5) {
                    writeErrMessage(c, "table: " + table + " previous migrate task is still running,on the same time one table only one task");
                    return;
                }
            }
        }
        client.create().creatingParentsIfNeeded().forPath(taskPath);
        TaskNode taskNode = new TaskNode();
        taskNode.setSchema(c.getSchema());
        taskNode.setSql(stmt);
        taskNode.setTable(table);
        taskNode.setAdd(add);
        taskNode.setStatus(0);
        Map<String, Integer> fromNodeSlaveIdMap = new HashMap<>();
        List<MigrateTask> allTaskList = new ArrayList<>();
        for (Map.Entry<String, List<MigrateTask>> entry : tasks.entrySet()) {
            String key = entry.getKey();
            List<MigrateTask> value = entry.getValue();
            for (MigrateTask migrateTask : value) {
                migrateTask.setSchema(c.getSchema());
                // 分配slaveid只需要一个dataHost分配一个即可,后续任务执行模拟从节点只需要一个dataHost一个
                String dataHost = getDataHostNameFromNode(migrateTask.getFrom());
                if (fromNodeSlaveIdMap.containsKey(dataHost)) {
                    migrateTask.setSlaveId(fromNodeSlaveIdMap.get(dataHost));
                } else {
                    migrateTask.setSlaveId(getSlaveIdFromZKForDataNode(migrateTask.getFrom()));
                    fromNodeSlaveIdMap.put(dataHost, migrateTask.getSlaveId());
                }
            }
            allTaskList.addAll(value);
        }
        transactionFinal = client.inTransaction().setData().forPath(taskPath, JSON.toJSONBytes(taskNode)).and();
        // 合并成dataHost级别任务
        Map<String, List<MigrateTask>> dataHostMigrateMap = mergerTaskForDataHost(allTaskList);
        for (Map.Entry<String, List<MigrateTask>> entry : dataHostMigrateMap.entrySet()) {
            String key = entry.getKey();
            List<MigrateTask> value = entry.getValue();
            String path = taskPath + "/" + key;
            transactionFinal = transactionFinal.create().forPath(path, JSON.toJSONBytes(value)).and();
        }
        transactionFinal.commit();
    } catch (Exception e) {
        LOGGER.error("migrate error", e);
        writeErrMessage(c, "migrate error:" + e);
        return;
    }
    writePackToClient(c, taskID);
    LOGGER.info("task start", new Date());
}
Also used : AbstractPartitionAlgorithm(io.mycat.route.function.AbstractPartitionAlgorithm) TaskNode(io.mycat.migrate.TaskNode) SchemaConfig(io.mycat.config.model.SchemaConfig) MigrateTask(io.mycat.migrate.MigrateTask) CuratorFramework(org.apache.curator.framework.CuratorFramework) CuratorTransactionFinal(org.apache.curator.framework.api.transaction.CuratorTransactionFinal) TableConfig(io.mycat.config.model.TableConfig) PartitionByCRC32PreSlot(io.mycat.route.function.PartitionByCRC32PreSlot)

Aggregations

TableConfig (io.mycat.config.model.TableConfig)84 SchemaConfig (io.mycat.config.model.SchemaConfig)26 SQLNonTransientException (java.sql.SQLNonTransientException)26 Test (org.junit.Test)18 RuleConfig (io.mycat.config.model.rule.RuleConfig)16 RouteResultset (io.mycat.route.RouteResultset)14 AbstractPartitionAlgorithm (io.mycat.route.function.AbstractPartitionAlgorithm)14 HashMap (java.util.HashMap)14 MySqlStatementParser (com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser)12 SlotFunction (io.mycat.route.function.SlotFunction)12 ArrayList (java.util.ArrayList)12 SQLStatement (com.alibaba.druid.sql.ast.SQLStatement)10 MySqlInsertStatement (com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlInsertStatement)8 PhysicalDBNode (io.mycat.backend.datasource.PhysicalDBNode)8 ConfigException (io.mycat.config.util.ConfigException)8 RouteResultsetNode (io.mycat.route.RouteResultsetNode)8 HashSet (java.util.HashSet)8 SQLCharExpr (com.alibaba.druid.sql.ast.expr.SQLCharExpr)6 SQLIdentifierExpr (com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr)6 CacheService (io.mycat.cache.CacheService)6