use of io.mycat.config.model.TableConfig in project Mycat_plus by coderczp.
the class DruidInsertParser method parserBatchInsert.
/**
* insert into .... select .... 或insert into table() values (),(),....
* @param schema
* @param rrs
* @param insertStmt
* @throws SQLNonTransientException
*/
private void parserBatchInsert(SchemaConfig schema, RouteResultset rrs, String partitionColumn, String tableName, MySqlInsertStatement insertStmt) throws SQLNonTransientException {
// insert into table() values (),(),....
if (insertStmt.getValuesList().size() > 1) {
// 字段列数
int columnNum = insertStmt.getColumns().size();
int shardingColIndex = getShardingColIndex(insertStmt, partitionColumn);
if (shardingColIndex == -1) {
String msg = "bad insert sql (sharding column:" + partitionColumn + " not provided," + insertStmt;
LOGGER.warn(msg);
throw new SQLNonTransientException(msg);
} else {
List<ValuesClause> valueClauseList = insertStmt.getValuesList();
Map<Integer, List<ValuesClause>> nodeValuesMap = new HashMap<Integer, List<ValuesClause>>();
Map<Integer, Integer> slotsMap = new HashMap<>();
TableConfig tableConfig = schema.getTables().get(tableName);
AbstractPartitionAlgorithm algorithm = tableConfig.getRule().getRuleAlgorithm();
for (ValuesClause valueClause : valueClauseList) {
if (valueClause.getValues().size() != columnNum) {
String msg = "bad insert sql columnSize != valueSize:" + columnNum + " != " + valueClause.getValues().size() + "values:" + valueClause;
LOGGER.warn(msg);
throw new SQLNonTransientException(msg);
}
SQLExpr expr = valueClause.getValues().get(shardingColIndex);
String shardingValue = null;
if (expr instanceof SQLIntegerExpr) {
SQLIntegerExpr intExpr = (SQLIntegerExpr) expr;
shardingValue = intExpr.getNumber() + "";
} else if (expr instanceof SQLCharExpr) {
SQLCharExpr charExpr = (SQLCharExpr) expr;
shardingValue = charExpr.getText();
}
Integer nodeIndex = algorithm.calculate(shardingValue);
if (algorithm instanceof SlotFunction) {
slotsMap.put(nodeIndex, ((SlotFunction) algorithm).slotValue());
}
// 没找到插入的分片
if (nodeIndex == null) {
String msg = "can't find any valid datanode :" + tableName + " -> " + partitionColumn + " -> " + shardingValue;
LOGGER.warn(msg);
throw new SQLNonTransientException(msg);
}
if (nodeValuesMap.get(nodeIndex) == null) {
nodeValuesMap.put(nodeIndex, new ArrayList<ValuesClause>());
}
nodeValuesMap.get(nodeIndex).add(valueClause);
}
RouteResultsetNode[] nodes = new RouteResultsetNode[nodeValuesMap.size()];
int count = 0;
for (Map.Entry<Integer, List<ValuesClause>> node : nodeValuesMap.entrySet()) {
Integer nodeIndex = node.getKey();
List<ValuesClause> valuesList = node.getValue();
insertStmt.setValuesList(valuesList);
nodes[count] = new RouteResultsetNode(tableConfig.getDataNodes().get(nodeIndex), rrs.getSqlType(), insertStmt.toString());
if (algorithm instanceof SlotFunction) {
nodes[count].setSlot(slotsMap.get(nodeIndex));
nodes[count].setStatement(ParseUtil.changeInsertAddSlot(nodes[count].getStatement(), nodes[count].getSlot()));
}
nodes[count++].setSource(rrs);
}
rrs.setNodes(nodes);
rrs.setFinishedRoute(true);
}
} else if (insertStmt.getQuery() != null) {
// insert into .... select ....
String msg = "TODO:insert into .... select .... not supported!";
LOGGER.warn(msg);
throw new SQLNonTransientException(msg);
}
}
use of io.mycat.config.model.TableConfig in project Mycat_plus by coderczp.
the class DruidLockTableParser method statementParse.
@Override
public void statementParse(SchemaConfig schema, RouteResultset rrs, SQLStatement stmt) throws SQLNonTransientException {
MySqlLockTableStatement lockTableStat = (MySqlLockTableStatement) stmt;
String table = lockTableStat.getTableSource().toString().toUpperCase();
TableConfig tableConfig = schema.getTables().get(table);
if (tableConfig == null) {
String msg = "can't find table define of " + table + " in schema:" + schema.getName();
LOGGER.warn(msg);
throw new SQLNonTransientException(msg);
}
LockType lockType = lockTableStat.getLockType();
if (LockType.WRITE != lockType && LockType.READ != lockType) {
String msg = "lock type must be write or read";
LOGGER.warn(msg);
throw new SQLNonTransientException(msg);
}
List<String> dataNodes = tableConfig.getDataNodes();
RouteResultsetNode[] nodes = new RouteResultsetNode[dataNodes.size()];
for (int i = 0; i < dataNodes.size(); i++) {
nodes[i] = new RouteResultsetNode(dataNodes.get(i), ServerParse.LOCK, stmt.toString());
}
rrs.setNodes(nodes);
rrs.setFinishedRoute(true);
}
use of io.mycat.config.model.TableConfig in project Mycat_plus by coderczp.
the class DruidMycatRouteStrategy method routeNormalSqlWithAST.
@Override
public RouteResultset routeNormalSqlWithAST(SchemaConfig schema, String stmt, RouteResultset rrs, String charset, LayerCachePool cachePool, int sqlType, ServerConnection sc) throws SQLNonTransientException {
/**
* 只有mysql时只支持mysql语法
*/
SQLStatementParser parser = null;
if (schema.isNeedSupportMultiDBType()) {
parser = new MycatStatementParser(stmt);
} else {
parser = new MySqlStatementParser(stmt);
}
MycatSchemaStatVisitor visitor = null;
SQLStatement statement;
/**
* 解析出现问题统一抛SQL语法错误
*/
try {
statement = parser.parseStatement();
visitor = new MycatSchemaStatVisitor();
} catch (Exception t) {
LOGGER.error("DruidMycatRouteStrategyError", t);
throw new SQLSyntaxErrorException(t);
}
/**
* 检验unsupported statement
*/
checkUnSupportedStatement(statement);
DruidParser druidParser = DruidParserFactory.create(schema, statement, visitor);
druidParser.parser(schema, rrs, statement, stmt, cachePool, visitor);
DruidShardingParseInfo ctx = druidParser.getCtx();
rrs.setTables(ctx.getTables());
if (visitor.isSubqueryRelationOr()) {
String err = "In subQuery,the or condition is not supported.";
LOGGER.error(err);
throw new SQLSyntaxErrorException(err);
}
/* 按照以下情况路由
1.2.1 可以直接路由.
1.2.2 两个表夸库join的sql.调用calat
1.2.3 需要先执行subquery 的sql.把subquery拆分出来.获取结果后,与outerquery
*/
// add huangyiming 分片规则不一样的且表中带查询条件的则走Catlet
List<String> tables = ctx.getTables();
SchemaConfig schemaConf = MycatServer.getInstance().getConfig().getSchemas().get(schema.getName());
int index = 0;
RuleConfig firstRule = null;
boolean directRoute = true;
Set<String> firstDataNodes = new HashSet<String>();
Map<String, TableConfig> tconfigs = schemaConf == null ? null : schemaConf.getTables();
Map<String, RuleConfig> rulemap = new HashMap<>();
if (tconfigs != null) {
for (String tableName : tables) {
TableConfig tc = tconfigs.get(tableName);
if (tc == null) {
// add 别名中取
Map<String, String> tableAliasMap = ctx.getTableAliasMap();
if (tableAliasMap != null && tableAliasMap.get(tableName) != null) {
tc = schemaConf.getTables().get(tableAliasMap.get(tableName));
}
}
if (index == 0) {
if (tc != null) {
firstRule = tc.getRule();
// 没有指定分片规则时,不做处理
if (firstRule == null) {
continue;
}
firstDataNodes.addAll(tc.getDataNodes());
rulemap.put(tc.getName(), firstRule);
}
} else {
if (tc != null) {
// ER关系表的时候是可能存在字表中没有tablerule的情况,所以加上判断
RuleConfig ruleCfg = tc.getRule();
if (ruleCfg == null) {
// 没有指定分片规则时,不做处理
continue;
}
Set<String> dataNodes = new HashSet<String>();
dataNodes.addAll(tc.getDataNodes());
rulemap.put(tc.getName(), ruleCfg);
// 如果匹配规则不相同或者分片的datanode不相同则需要走子查询处理
if (firstRule != null && ((ruleCfg != null && !ruleCfg.getRuleAlgorithm().equals(firstRule.getRuleAlgorithm())) || (!dataNodes.equals(firstDataNodes)))) {
directRoute = false;
break;
}
}
}
index++;
}
}
RouteResultset rrsResult = rrs;
if (directRoute) {
// 直接路由
if (!RouterUtil.isAllGlobalTable(ctx, schemaConf)) {
if (rulemap.size() > 1 && !checkRuleField(rulemap, visitor)) {
String err = "In case of slice table,there is no rule field in the relationship condition!";
LOGGER.error(err);
throw new SQLSyntaxErrorException(err);
}
}
rrsResult = directRoute(rrs, ctx, schema, druidParser, statement, cachePool);
} else {
int subQuerySize = visitor.getSubQuerys().size();
if (subQuerySize == 0 && ctx.getTables().size() == 2) {
// 两表关联,考虑使用catlet
if (!visitor.getRelationships().isEmpty()) {
rrs.setCacheAble(false);
rrs.setFinishedRoute(true);
rrsResult = catletRoute(schema, ctx.getSql(), charset, sc);
} else {
rrsResult = directRoute(rrs, ctx, schema, druidParser, statement, cachePool);
}
} else if (subQuerySize == 1) {
// 只涉及一张表的子查询,使用 MiddlerResultHandler 获取中间结果后,改写原有 sql 继续执行 TODO 后期可能会考虑多个子查询的情况.
SQLSelect sqlselect = visitor.getSubQuerys().iterator().next();
if (!visitor.getRelationships().isEmpty()) {
// 当 inner query 和 outer query 有关联条件时,暂不支持
String err = "In case of slice table,sql have different rules,the relationship condition is not supported.";
LOGGER.error(err);
throw new SQLSyntaxErrorException(err);
} else {
SQLSelectQuery sqlSelectQuery = sqlselect.getQuery();
if (((MySqlSelectQueryBlock) sqlSelectQuery).getFrom() instanceof SQLExprTableSource) {
rrs.setCacheAble(false);
rrs.setFinishedRoute(true);
rrsResult = middlerResultRoute(schema, charset, sqlselect, sqlType, statement, sc);
}
}
} else if (subQuerySize >= 2) {
String err = "In case of slice table,sql has different rules,currently only one subQuery is supported.";
LOGGER.error(err);
throw new SQLSyntaxErrorException(err);
}
}
return rrsResult;
}
use of io.mycat.config.model.TableConfig in project Mycat_plus by coderczp.
the class DruidParserFactory method getDruidParserForMultiDB.
private static DruidParser getDruidParserForMultiDB(SchemaConfig schema, SQLStatement statement, SchemaStatVisitor visitor) {
DruidParser parser = null;
// 先解出表,判断表所在db的类型,再根据不同db类型返回不同的解析
/**
* 不能直接使用visitor变量,防止污染后续sql解析
* @author SvenAugustus
*/
SchemaStatVisitor _visitor = SchemaStatVisitorFactory.create(schema);
List<String> tables = parseTables(statement, _visitor);
for (String table : tables) {
Set<String> dbTypes = null;
TableConfig tableConfig = schema.getTables().get(table);
if (tableConfig == null) {
dbTypes = new HashSet<>();
dbTypes.add(schema.getDefaultDataNodeDbType());
} else {
dbTypes = tableConfig.getDbTypes();
}
if (dbTypes.contains("oracle")) {
parser = new DruidSelectOracleParser();
break;
} else if (dbTypes.contains("db2")) {
parser = new DruidSelectDb2Parser();
break;
} else if (dbTypes.contains("sqlserver")) {
parser = new DruidSelectSqlServerParser();
break;
} else if (dbTypes.contains("postgresql")) {
parser = new DruidSelectPostgresqlParser();
break;
}
}
return parser;
}
use of io.mycat.config.model.TableConfig in project Mycat_plus by coderczp.
the class ConfigComparer method loadMigratorTables.
/*
* 加载迁移表信息,tables大小为0表示迁移schema下所有表
*/
private void loadMigratorTables(String schemaName, String[] tables) {
if (!DataMigratorUtil.isKeyExistIgnoreCase(oldSchemas, schemaName)) {
throw new ConfigException("oldSchema:" + schemaName + " is not exists!");
}
if (!DataMigratorUtil.isKeyExistIgnoreCase(newSchemas, schemaName)) {
throw new ConfigException("newSchema:" + schemaName + " is not exists!");
}
Map<String, TableConfig> oldTables = DataMigratorUtil.getValueIgnoreCase(oldSchemas, schemaName).getTables();
Map<String, TableConfig> newTables = DataMigratorUtil.getValueIgnoreCase(newSchemas, schemaName).getTables();
if (tables.length > 0) {
// 指定schema下的表进行迁移
for (int i = 0; i < tables.length; i++) {
TableConfig oldTable = DataMigratorUtil.getValueIgnoreCase(oldTables, tables[i]);
TableConfig newTable = DataMigratorUtil.getValueIgnoreCase(newTables, tables[i]);
loadMigratorTable(oldTable, newTable, schemaName, tables[i]);
}
} else {
// 迁移schema下所有的表
// 校验新旧schema中的table配置是否一致
Set<String> oldSet = oldTables.keySet();
Set<String> newSet = newTables.keySet();
if (!oldSet.equals(newSet)) {
throw new ConfigException("new & old table config is not equal!");
}
for (String tableName : oldSet) {
TableConfig oldTable = oldTables.get(tableName);
TableConfig newTable = newTables.get(tableName);
loadMigratorTable(oldTable, newTable, schemaName, tableName);
}
}
}
Aggregations