use of java.sql.SQLNonTransientException in project Mycat_plus by coderczp.
the class DruidUpdateParser method confirmShardColumnNotUpdated.
private void confirmShardColumnNotUpdated(SQLUpdateStatement update, SchemaConfig schema, String tableName, String partitionColumn, String joinKey, RouteResultset rrs) throws SQLNonTransientException {
List<SQLUpdateSetItem> updateSetItem = update.getItems();
if (updateSetItem != null && updateSetItem.size() > 0) {
boolean hasParent = (schema.getTables().get(tableName).getParentTC() != null);
for (SQLUpdateSetItem item : updateSetItem) {
String column = StringUtil.removeBackquote(item.getColumn().toString().toUpperCase());
// 考虑别名,前面已经限制了update分片表的个数只能有一个,所以这里别名只能是分片表的
if (column.contains(StringUtil.TABLE_COLUMN_SEPARATOR)) {
column = column.substring(column.indexOf(".") + 1).trim().toUpperCase();
}
if (partitionColumn != null && partitionColumn.equals(column)) {
boolean canUpdate;
canUpdate = ((update.getWhere() != null) && shardColCanBeUpdated(update.getWhere(), partitionColumn, item.getValue(), false));
if (!canUpdate) {
String msg = "Sharding column can't be updated " + tableName + "->" + partitionColumn;
LOGGER.warn(msg);
throw new SQLNonTransientException(msg);
}
}
if (hasParent) {
if (column.equals(joinKey)) {
String msg = "Parent relevant column can't be updated " + tableName + "->" + joinKey;
LOGGER.warn(msg);
throw new SQLNonTransientException(msg);
}
rrs.setCacheAble(true);
}
}
}
}
use of java.sql.SQLNonTransientException 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 java.sql.SQLNonTransientException in project Mycat_plus by coderczp.
the class HintCatletHandler method route.
/**
* 从全局的schema列表中查询指定的schema是否存在, 如果存在则替换connection属性中原有的schema,
* 如果不存在,则throws SQLNonTransientException,表示指定的schema 不存在
*
* @param sysConfig
* @param schema
* @param sqlType
* @param realSQL
* @param charset
* @param info
* @param cachePool
* @param hintSQLValue
* @return
* @throws SQLNonTransientException
*/
@Override
public RouteResultset route(SystemConfig sysConfig, SchemaConfig schema, int sqlType, String realSQL, String charset, ServerConnection sc, LayerCachePool cachePool, String hintSQLValue, int hintSqlType, Map hintMap) throws SQLNonTransientException {
// sc.setEngineCtx ctx
String cateletClass = hintSQLValue;
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("load catelet class:" + hintSQLValue + " to run sql " + realSQL);
}
try {
Catlet catlet = (Catlet) MycatServer.getInstance().getCatletClassLoader().getInstanceofClass(cateletClass);
catlet.route(sysConfig, schema, sqlType, realSQL, charset, sc, cachePool);
catlet.processSQL(realSQL, new EngineCtx(sc.getSession2()));
} catch (Exception e) {
LOGGER.warn("catlet error " + e);
throw new SQLNonTransientException(e);
}
return null;
}
use of java.sql.SQLNonTransientException in project Mycat_plus by coderczp.
the class DruidMysqlRouteStrategyTest method testERroute.
public void testERroute() throws Exception {
SchemaConfig schema = schemaMap.get("TESTDB");
String sql = "insert into orders (id,name,customer_id) values(1,'testonly',1)";
RouteResultset rrs = routeStrategy.route(new SystemConfig(), schema, 1, sql, null, null, cachePool);
Assert.assertEquals(1, rrs.getNodes().length);
Assert.assertEquals(false, rrs.isCacheAble());
Assert.assertEquals("dn1", rrs.getNodes()[0].getName());
sql = "insert into orders (id,name,customer_id) values(1,'testonly',2000001)";
rrs = routeStrategy.route(new SystemConfig(), schema, 1, sql, null, null, cachePool);
Assert.assertEquals(false, rrs.isCacheAble());
Assert.assertEquals(1, rrs.getNodes().length);
Assert.assertEquals("dn2", rrs.getNodes()[0].getName());
// can't update join key
sql = "update orders set id=1 ,name='aaa' , customer_id=2000001";
String err = null;
try {
rrs = routeStrategy.route(new SystemConfig(), schema, 1, sql, null, null, cachePool);
} catch (SQLNonTransientException e) {
err = e.getMessage();
}
Assert.assertEquals(true, err.startsWith("Parent relevant column can't be updated ORDERS->CUSTOMER_ID"));
// route by parent rule ,update sql
sql = "update orders set id=1 ,name='aaa' where customer_id=2000001";
rrs = routeStrategy.route(new SystemConfig(), schema, 1, sql, null, null, cachePool);
Assert.assertEquals(true, rrs.isCacheAble());
Assert.assertEquals("dn2", rrs.getNodes()[0].getName());
// route by parent rule but can't find datanode
sql = "update orders set id=1 ,name='aaa' where customer_id=-1";
try {
rrs = routeStrategy.route(new SystemConfig(), schema, 1, sql, null, null, cachePool);
} catch (Exception e) {
err = e.getMessage();
}
Assert.assertEquals(true, err.startsWith("can't find datanode for sharding column:"));
// route by parent rule ,select sql
sql = "select * from orders where customer_id=2000001";
rrs = routeStrategy.route(new SystemConfig(), schema, 1, sql, null, null, cachePool);
Assert.assertEquals(true, rrs.isCacheAble());
Assert.assertEquals("dn2", rrs.getNodes()[0].getName());
// route by parent rule ,delete sql
sql = "delete from orders where customer_id=2000001";
rrs = routeStrategy.route(new SystemConfig(), schema, 1, sql, null, null, cachePool);
Assert.assertEquals("dn2", rrs.getNodes()[0].getName());
// test alias in column
sql = "select name as order_name from orders order by order_name limit 10,5";
rrs = routeStrategy.route(new SystemConfig(), schema, 1, sql, null, null, cachePool);
MySqlStatementParser parser = new MySqlStatementParser("SELECT name AS order_name FROM orders ORDER BY order_name LIMIT 0,15");
SQLStatement statement = parser.parseStatement();
// Assert.assertEquals(sql, rrs.getNodes()[0].getStatement());
}
use of java.sql.SQLNonTransientException in project Mycat-Server by MyCATApache.
the class DruidCreateTableParser method statementParse.
@Override
public void statementParse(SchemaConfig schema, RouteResultset rrs, SQLStatement stmt) throws SQLNonTransientException {
MySqlCreateTableStatement createStmt = (MySqlCreateTableStatement) stmt;
if (createStmt.getQuery() != null) {
String msg = "create table from other table not supported :" + stmt;
LOGGER.warn(msg);
throw new SQLNonTransientException(msg);
}
String tableName = StringUtil.removeBackquote(createStmt.getTableSource().toString().toUpperCase());
if (schema.getTables().containsKey(tableName)) {
TableConfig tableConfig = schema.getTables().get(tableName);
AbstractPartitionAlgorithm algorithm = tableConfig.getRule().getRuleAlgorithm();
if (algorithm instanceof SlotFunction) {
SQLColumnDefinition column = new SQLColumnDefinition();
column.setDataType(new SQLCharacterDataType("int"));
column.setName(new SQLIdentifierExpr("_slot"));
column.setComment(new SQLCharExpr("自动迁移算法slot,禁止修改"));
((SQLCreateTableStatement) stmt).getTableElementList().add(column);
String sql = createStmt.toString();
rrs.setStatement(sql);
ctx.setSql(sql);
}
}
ctx.addTable(tableName);
}
Aggregations