use of java.sql.SQLNonTransientException in project Mycat-Server by MyCATApache.
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 java.sql.SQLNonTransientException in project Mycat-Server by MyCATApache.
the class DruidInsertParser method parserSingleInsert.
/**
* 单条insert(非批量)
* @param schema
* @param rrs
* @param partitionColumn
* @param tableName
* @param insertStmt
* @throws SQLNonTransientException
*/
private void parserSingleInsert(SchemaConfig schema, RouteResultset rrs, String partitionColumn, String tableName, MySqlInsertStatement insertStmt) throws SQLNonTransientException {
boolean isFound = false;
for (int i = 0; i < insertStmt.getColumns().size(); i++) {
if (partitionColumn.equalsIgnoreCase(StringUtil.removeBackquote(insertStmt.getColumns().get(i).toString()))) {
// 找到分片字段
isFound = true;
String column = StringUtil.removeBackquote(insertStmt.getColumns().get(i).toString());
String value = StringUtil.removeBackquote(insertStmt.getValues().getValues().get(i).toString());
RouteCalculateUnit routeCalculateUnit = new RouteCalculateUnit();
routeCalculateUnit.addShardingExpr(tableName, column, value);
ctx.addRouteCalculateUnit(routeCalculateUnit);
// mycat是单分片键,找到了就返回
break;
}
}
if (!isFound) {
// 分片表的
String msg = "bad insert sql (sharding column:" + partitionColumn + " not provided," + insertStmt;
LOGGER.warn(msg);
throw new SQLNonTransientException(msg);
}
// INSERT INTO TABLEName (a,b,c) VALUES (1,2,3) ON DUPLICATE KEY UPDATE c=c+1;
if (insertStmt.getDuplicateKeyUpdate() != null) {
List<SQLExpr> updateList = insertStmt.getDuplicateKeyUpdate();
for (SQLExpr expr : updateList) {
SQLBinaryOpExpr opExpr = (SQLBinaryOpExpr) expr;
String column = StringUtil.removeBackquote(opExpr.getLeft().toString().toUpperCase());
if (column.equals(partitionColumn)) {
String msg = "Sharding column can't be updated: " + tableName + " -> " + partitionColumn;
LOGGER.warn(msg);
throw new SQLNonTransientException(msg);
}
}
}
}
use of java.sql.SQLNonTransientException in project Mycat-Server by MyCATApache.
the class DruidSelectParser method tryRoute.
private void tryRoute(SchemaConfig schema, RouteResultset rrs, LayerCachePool cachePool) throws SQLNonTransientException {
if (rrs.isFinishedRoute()) {
// 避免重复路由
return;
}
// 无表的select语句直接路由带任一节点
if ((ctx.getTables() == null || ctx.getTables().size() == 0) && (ctx.getTableAliasMap() == null || ctx.getTableAliasMap().isEmpty())) {
rrs = RouterUtil.routeToSingleNode(rrs, schema.getRandomDataNode(), ctx.getSql());
rrs.setFinishedRoute(true);
return;
}
// RouterUtil.tryRouteForTables(schema, ctx, rrs, true, cachePool);
SortedSet<RouteResultsetNode> nodeSet = new TreeSet<RouteResultsetNode>();
boolean isAllGlobalTable = RouterUtil.isAllGlobalTable(ctx, schema);
for (RouteCalculateUnit unit : ctx.getRouteCalculateUnits()) {
RouteResultset rrsTmp = RouterUtil.tryRouteForTables(schema, ctx, unit, rrs, true, cachePool);
if (rrsTmp != null && rrsTmp.getNodes() != null) {
for (RouteResultsetNode node : rrsTmp.getNodes()) {
nodeSet.add(node);
}
}
if (isAllGlobalTable) {
// 都是全局表时只计算一遍路由
break;
}
}
if (nodeSet.size() == 0) {
Collection<String> stringCollection = ctx.getTableAliasMap().values();
for (String table : stringCollection) {
if (table != null && table.toLowerCase().contains("information_schema.")) {
rrs = RouterUtil.routeToSingleNode(rrs, schema.getRandomDataNode(), ctx.getSql());
rrs.setFinishedRoute(true);
return;
}
}
String msg = " find no Route:" + ctx.getSql();
LOGGER.warn(msg);
throw new SQLNonTransientException(msg);
}
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);
rrs.setFinishedRoute(true);
}
use of java.sql.SQLNonTransientException in project Mycat-Server by MyCATApache.
the class DruidSelectParser method changeSql.
/**
* 改写sql:需要加limit的加上
*/
@Override
public void changeSql(SchemaConfig schema, RouteResultset rrs, SQLStatement stmt, LayerCachePool cachePool) throws SQLNonTransientException {
tryRoute(schema, rrs, cachePool);
rrs.copyLimitToNodes();
SQLSelectStatement selectStmt = (SQLSelectStatement) stmt;
SQLSelectQuery sqlSelectQuery = selectStmt.getSelect().getQuery();
if (sqlSelectQuery instanceof MySqlSelectQueryBlock) {
MySqlSelectQueryBlock mysqlSelectQuery = (MySqlSelectQueryBlock) selectStmt.getSelect().getQuery();
int limitStart = 0;
int limitSize = schema.getDefaultMaxLimit();
// clear group having
SQLSelectGroupByClause groupByClause = mysqlSelectQuery.getGroupBy();
// Modified by winbill, 20160614, do NOT include having clause when routing to multiple nodes
if (groupByClause != null && groupByClause.getHaving() != null && isRoutMultiNode(schema, rrs)) {
groupByClause.setHaving(null);
}
Map<String, Map<String, Set<ColumnRoutePair>>> allConditions = getAllConditions();
boolean isNeedAddLimit = isNeedAddLimit(schema, rrs, mysqlSelectQuery, allConditions);
if (isNeedAddLimit) {
Limit limit = new Limit();
limit.setRowCount(new SQLIntegerExpr(limitSize));
mysqlSelectQuery.setLimit(limit);
rrs.setLimitSize(limitSize);
String sql = getSql(rrs, stmt, isNeedAddLimit);
rrs.changeNodeSqlAfterAddLimit(schema, getCurentDbType(), sql, 0, limitSize, true);
}
Limit limit = mysqlSelectQuery.getLimit();
if (limit != null && !isNeedAddLimit) {
SQLIntegerExpr offset = (SQLIntegerExpr) limit.getOffset();
SQLIntegerExpr count = (SQLIntegerExpr) limit.getRowCount();
if (offset != null) {
limitStart = offset.getNumber().intValue();
rrs.setLimitStart(limitStart);
}
if (count != null) {
limitSize = count.getNumber().intValue();
rrs.setLimitSize(limitSize);
}
if (isNeedChangeLimit(rrs)) {
Limit changedLimit = new Limit();
changedLimit.setRowCount(new SQLIntegerExpr(limitStart + limitSize));
if (offset != null) {
if (limitStart < 0) {
String msg = "You have an error in your SQL syntax; check the manual that " + "corresponds to your MySQL server version for the right syntax to use near '" + limitStart + "'";
throw new SQLNonTransientException(ErrorCode.ER_PARSE_ERROR + " - " + msg);
} else {
changedLimit.setOffset(new SQLIntegerExpr(0));
}
}
mysqlSelectQuery.setLimit(changedLimit);
String sql = getSql(rrs, stmt, isNeedAddLimit);
rrs.changeNodeSqlAfterAddLimit(schema, getCurentDbType(), sql, 0, limitStart + limitSize, true);
// 设置改写后的sql
ctx.setSql(sql);
} else {
rrs.changeNodeSqlAfterAddLimit(schema, getCurentDbType(), getCtx().getSql(), rrs.getLimitStart(), rrs.getLimitSize(), true);
// ctx.setSql(nativeSql);
}
}
if (rrs.isDistTable()) {
SQLTableSource from = mysqlSelectQuery.getFrom();
for (RouteResultsetNode node : rrs.getNodes()) {
SQLIdentifierExpr sqlIdentifierExpr = new SQLIdentifierExpr();
sqlIdentifierExpr.setParent(from);
sqlIdentifierExpr.setName(node.getSubTableName());
SQLExprTableSource from2 = new SQLExprTableSource(sqlIdentifierExpr);
from2.setAlias(from.getAlias());
mysqlSelectQuery.setFrom(from2);
node.setStatement(stmt.toString());
}
}
rrs.setCacheAble(isNeedCache(schema, rrs, mysqlSelectQuery, allConditions));
}
}
use of java.sql.SQLNonTransientException in project Mycat-Server by MyCATApache.
the class DruidUpdateParser method statementParse.
@Override
public void statementParse(SchemaConfig schema, RouteResultset rrs, SQLStatement stmt) throws SQLNonTransientException {
// 这里限制了update分片表的个数只能有一个
if (ctx.getTables() != null && getUpdateTableCount() > 1 && !schema.isNoSharding()) {
String msg = "multi table related update not supported,tables:" + ctx.getTables();
LOGGER.warn(msg);
throw new SQLNonTransientException(msg);
}
MySqlUpdateStatement update = (MySqlUpdateStatement) stmt;
String tableName = StringUtil.removeBackquote(update.getTableName().getSimpleName().toUpperCase());
TableConfig tc = schema.getTables().get(tableName);
if (RouterUtil.isNoSharding(schema, tableName)) {
// 整个schema都不分库或者该表不拆分
RouterUtil.routeForTableMeta(rrs, schema, tableName, rrs.getStatement());
rrs.setFinishedRoute(true);
return;
}
String partitionColumn = tc.getPartitionColumn();
String joinKey = tc.getJoinKey();
if (tc.isGlobalTable() || (partitionColumn == null && joinKey == null)) {
// 修改全局表 update 受影响的行数
RouterUtil.routeToMultiNode(false, rrs, tc.getDataNodes(), rrs.getStatement(), tc.isGlobalTable());
rrs.setFinishedRoute(true);
return;
}
confirmShardColumnNotUpdated(update, schema, tableName, partitionColumn, joinKey, rrs);
if (schema.getTables().get(tableName).isGlobalTable() && ctx.getRouteCalculateUnit().getTablesAndConditions().size() > 1) {
throw new SQLNonTransientException("global table is not supported in multi table related update " + tableName);
}
}
Aggregations