Merge branch 'master' into issue-303

This commit is contained in:
tiger.yan
2017-10-31 13:18:38 +08:00
committed by GitHub
100 changed files with 2805 additions and 1145 deletions
+3
View File
@@ -0,0 +1,3 @@
Reason:(Fixes #. or Improve #.)
Type:
Influences
+3
View File
@@ -45,6 +45,9 @@ Read the [Roadmap](./docs/ROADMAP.md).
## Quick start
Read the [Quick Start](./docs/QUICKSTART.md).
## Documentation
+ [简体中文](https://github.com/actiontech/dble/wiki)
+ English(Comming soon)
## Contributing
+2 -1
View File
@@ -4,7 +4,8 @@ Get package from https://github.com/actiontech/dble/releases
## 2.Prepare
### 2.1 MySQL
Make sure there is at least one MySQL Instance with url $url(e.g., localhost:3306) ,$user(e.g., test) and $passworde.g., testPsw in your machine.
Make sure there is at least one MySQL Instance with url $url(e.g., localhost:3306) ,$user(e.g., test) and $passworde.g., testPsw in your machine.
You also need to make sure that the url(localhost/127.0.0.1/other IP) can connect to MySQL, otherwise,you will get an error "NO ROUTE TO HOST" later. So Check your configurations of “/etc/hosts” ,“/etc/hosts.allow” ,“/etc/hosts.deny”
Add 4 database ,the SQL as below:
```
+4 -4
View File
@@ -47,16 +47,16 @@
<!-- subquery need to refactor -->
<Match>
<Class name="com.actiontech.dble.plan.common.item.subquery.ItemSinglerowSubselect"/>
<Class name="com.actiontech.dble.plan.common.item.subquery.ItemScalarSubQuery"/>
</Match>
<Match>
<Class name="com.actiontech.dble.plan.common.item.subquery.ItemAllanySubselect"/>
<Class name="com.actiontech.dble.plan.common.item.subquery.ItemAllAnySubQuery"/>
</Match>
<Match>
<Class name="com.actiontech.dble.plan.common.item.subquery.ItemExistsSubselect"/>
<Class name="com.actiontech.dble.plan.common.item.subquery.ItemExistsSubQuery"/>
</Match>
<Match>
<Class name="com.actiontech.dble.plan.common.item.subquery.ItemMaxminSubselect"/>
<Class name="com.actiontech.dble.plan.common.item.subquery.ItemMaxminSubQuery"/>
</Match>
<!-- subquery need to refactor end -->
@@ -31,6 +31,8 @@ import com.actiontech.dble.net.*;
import com.actiontech.dble.route.RouteService;
import com.actiontech.dble.route.sequence.handler.*;
import com.actiontech.dble.server.ServerConnectionFactory;
import com.actiontech.dble.server.variables.SysVarsExtractor;
import com.actiontech.dble.server.variables.SystemVariables;
import com.actiontech.dble.server.util.GlobalTableUtil;
import com.actiontech.dble.sqlengine.OneRawSQLQueryResultHandler;
import com.actiontech.dble.sqlengine.SQLJob;
@@ -127,7 +129,7 @@ public final class DbleServer {
this.isOnline = new AtomicBoolean(true);
//initialized the cache service
cacheService = new CacheService(config.getSystem().isLowerCaseTableNames());
cacheService = new CacheService(SystemVariables.getSysVars().isLowerCaseTableNames());
//initialized the router cache and primary cache
routerService = new RouteService(cacheService);
@@ -268,6 +270,27 @@ public final class DbleServer {
SystemConfig.getHomePath();
}
/* the function is only for Cyclomatic complexity of startup() */
private void pullVarAndMeta() throws IOException {
SysVarsExtractor extractor = new SysVarsExtractor(config);
try {
extractor.extract();
} catch (Exception e) {
throw new IOException(e);
}
this.config.reviseSchemas();
tmManager = new ProxyMetaManager();
if (!this.getConfig().isDataHostWithoutWR()) {
//init tmManager
try {
tmManager.init(this.getConfig());
} catch (Exception e) {
throw new IOException(e);
}
}
}
public void startup() throws IOException {
SystemConfig system = config.getSystem();
@@ -385,17 +408,7 @@ public final class DbleServer {
txnLogProcessor.start();
}
tmManager = new ProxyMetaManager();
if (!this.getConfig().isDataHostWithoutWR()) {
//init tmManager
try {
tmManager.init(this.getConfig());
} catch (Exception e) {
throw new IOException(e);
}
}
pullVarAndMeta();
//XA Init recovery Log
LOGGER.info("===============================================");
@@ -18,8 +18,8 @@ import com.actiontech.dble.route.RouteResultsetNode;
import com.actiontech.dble.route.parser.util.Pair;
import com.actiontech.dble.server.NonBlockingSession;
import com.actiontech.dble.server.ServerConnection;
import com.actiontech.dble.server.SystemVariables;
import com.actiontech.dble.server.parser.ServerParse;
import com.actiontech.dble.server.variables.SystemVariables;
import com.actiontech.dble.util.StringUtil;
import com.actiontech.dble.util.TimeUtil;
import com.actiontech.dble.util.exception.UnknownTxIsolationException;
@@ -148,7 +148,7 @@ public class MySQLConnection extends BackendAIOConnection {
this.txIsolation = -1;
this.autocommit = true;
//TODO:CHECK
this.setCharacterSet(SystemVariables.getDefaultValue("character_set_server"));
this.setCharacterSet(SystemVariables.getSysVars().getDefaultValue("character_set_server"));
this.usrVariables.clear();
this.sysVariables.clear();
}
@@ -238,7 +238,7 @@ public class MySQLConnection extends BackendAIOConnection {
packet.setClientFlags(clientFlags);
packet.setMaxPacketSize(maxPacketSize);
//TODO:CHECK
int charsetIndex = CharsetUtil.getCharsetDefaultIndex(SystemVariables.getDefaultValue("character_set_server"));
int charsetIndex = CharsetUtil.getCharsetDefaultIndex(SystemVariables.getSysVars().getDefaultValue("character_set_server"));
packet.setCharsetIndex(charsetIndex);
packet.setUser(user);
@@ -428,7 +428,12 @@ public class MySQLConnection extends BackendAIOConnection {
}
//tmp now = backend -(backend &&frontend)
for (Map.Entry<String, String> entry : tmpSysVars.entrySet()) {
String value = SystemVariables.getDefaultValue(entry.getKey());
String value = SystemVariables.getSysVars().getDefaultValue(entry.getKey());
try {
Long.parseLong(value);
} catch (NumberFormatException e) {
value = "`" + value + "`";
}
setVars.add(new Pair<>(entry.getKey(), value));
toResetSys.add(entry.getKey());
}
@@ -11,6 +11,7 @@ import com.actiontech.dble.net.mysql.RowDataPacket;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
@@ -21,16 +22,19 @@ public class NewConnectionRespHandler implements ResponseHandler {
private ReentrantLock lock = new ReentrantLock();
private Condition initiated = lock.newCondition();
public BackendConnection getBackConn() {
public BackendConnection getBackConn() throws IOException {
lock.lock();
try {
while (backConn == null) {
if (backConn == null) {
initiated.await();
}
if (backConn == null) {
throw new IOException("get backend connection error ");
}
return backConn;
} catch (InterruptedException e) {
LOGGER.warn("getBackConn " + e);
return null;
throw new IOException(e.getMessage());
} finally {
lock.unlock();
}
@@ -39,7 +43,12 @@ public class NewConnectionRespHandler implements ResponseHandler {
@Override
public void connectionError(Throwable e, BackendConnection conn) {
LOGGER.warn(conn + " connectionError " + e);
lock.lock();
try {
initiated.signal();
} finally {
lock.unlock();
}
}
@Override
@@ -5,7 +5,7 @@
package com.actiontech.dble.backend.mysql.nio.handler;
import com.actiontech.dble.DbleServer;
import com.actiontech.dble.server.variables.SystemVariables;
import com.actiontech.dble.backend.BackendConnection;
import com.actiontech.dble.backend.mysql.nio.handler.query.DMLResponseHandler;
import com.actiontech.dble.backend.mysql.nio.handler.util.HandlerTool;
@@ -40,7 +40,7 @@ public class ShowTablesHandler extends SingleNodeHandler {
this.info = info;
ServerConnection source = session.getSource();
String showSchema = info.getSchema();
if (showSchema != null && DbleServer.getInstance().getConfig().getSystem().isLowerCaseTableNames()) {
if (showSchema != null && SystemVariables.getSysVars().isLowerCaseTableNames()) {
showSchema = showSchema.toLowerCase();
}
showTableSchema = showSchema == null ? source.getSchema() : showSchema;
@@ -11,16 +11,26 @@ import com.actiontech.dble.backend.mysql.nio.handler.query.DMLResponseHandler;
import com.actiontech.dble.backend.mysql.nio.handler.query.impl.*;
import com.actiontech.dble.backend.mysql.nio.handler.query.impl.groupby.DirectGroupByHandler;
import com.actiontech.dble.backend.mysql.nio.handler.query.impl.groupby.OrderedGroupByHandler;
import com.actiontech.dble.backend.mysql.nio.handler.query.impl.subquery.AllAnySubQueryHandler;
import com.actiontech.dble.backend.mysql.nio.handler.query.impl.subquery.InSubQueryHandler;
import com.actiontech.dble.backend.mysql.nio.handler.query.impl.subquery.SingleRowSubQueryHandler;
import com.actiontech.dble.backend.mysql.nio.handler.query.impl.subquery.SubQueryHandler;
import com.actiontech.dble.backend.mysql.nio.handler.util.CallBackHandler;
import com.actiontech.dble.config.ErrorCode;
import com.actiontech.dble.config.ServerConfig;
import com.actiontech.dble.config.model.SchemaConfig;
import com.actiontech.dble.config.model.TableConfig;
import com.actiontech.dble.net.mysql.ErrorPacket;
import com.actiontech.dble.plan.Order;
import com.actiontech.dble.plan.PlanNode;
import com.actiontech.dble.plan.PlanNode.PlanNodeType;
import com.actiontech.dble.plan.common.exception.MySQLOutPutException;
import com.actiontech.dble.plan.common.item.Item;
import com.actiontech.dble.plan.common.item.function.sumfunc.ItemSum;
import com.actiontech.dble.plan.common.item.subquery.ItemAllAnySubQuery;
import com.actiontech.dble.plan.common.item.subquery.ItemInSubQuery;
import com.actiontech.dble.plan.common.item.subquery.ItemSingleRowSubQuery;
import com.actiontech.dble.plan.common.item.subquery.ItemSubQuery;
import com.actiontech.dble.plan.node.JoinNode;
import com.actiontech.dble.plan.node.QueryNode;
import com.actiontech.dble.plan.node.TableNode;
@@ -29,13 +39,21 @@ import com.actiontech.dble.route.RouteResultsetNode;
import com.actiontech.dble.server.NonBlockingSession;
import com.actiontech.dble.server.parser.ServerParse;
import com.alibaba.druid.sql.ast.SQLOrderingSpecification;
import org.apache.log4j.Logger;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
abstract class BaseHandlerBuilder {
public abstract class BaseHandlerBuilder {
private static final Logger LOGGER = Logger.getLogger(BaseHandlerBuilder.class);
private static AtomicLong sequenceId = new AtomicLong(0);
protected NonBlockingSession session;
protected HandlerBuilder hBuilder;
@@ -53,11 +71,15 @@ abstract class BaseHandlerBuilder {
/* it's no need to send maker if sql is just the same as the client origin query */
protected boolean needSendMaker = true;
protected BaseHandlerBuilder(NonBlockingSession session, PlanNode node, HandlerBuilder hBuilder) {
protected boolean isExplain = false;
protected List<BaseHandlerBuilder> subQueryBuilderList = new ArrayList<>(1);
protected BaseHandlerBuilder(NonBlockingSession session, PlanNode node, HandlerBuilder hBuilder, boolean isExplain) {
this.session = session;
this.node = node;
this.hBuilder = hBuilder;
this.config = DbleServer.getInstance().getConfig();
this.isExplain = isExplain;
if (config.getSchemas().isEmpty())
throw new MySQLOutPutException(ErrorCode.ER_QUERYHANDLER, "", "current router config is empty!");
}
@@ -66,6 +88,10 @@ abstract class BaseHandlerBuilder {
return currentLast;
}
public List<BaseHandlerBuilder> getSubQueryBuilderList() {
return subQueryBuilderList;
}
/**
* generate a handler chain
*/
@@ -82,6 +108,7 @@ abstract class BaseHandlerBuilder {
// the query can be send to some certain nodes .eg: ER tables, GLOBAL*NORMAL GLOBAL*ER
mergeBuild();
} else {
handleSubQueries();
//need to split to simple query
preHandlers = buildPre();
buildOwn();
@@ -89,7 +116,7 @@ abstract class BaseHandlerBuilder {
if (needCommon)
buildCommon();
if (needSendMaker) {
// view subalias
// view sub alias
String tbAlias = node.getAlias();
if (node.getParent() != null && node.getParent().getSubAlias() != null)
tbAlias = node.getParent().getSubAlias();
@@ -116,6 +143,8 @@ abstract class BaseHandlerBuilder {
//
}
protected abstract void handleSubQueries();
protected abstract List<DMLResponseHandler> buildPre();
/**
@@ -396,4 +425,110 @@ abstract class BaseHandlerBuilder {
return schemaConfig.getTables().get(table);
}
protected void handleBlockingSubQuery() {
if (node.getSubQueries().size() == 0) {
return;
}
final ReentrantLock lock = new ReentrantLock();
final Condition finishSubQuery = lock.newCondition();
final AtomicBoolean finished = new AtomicBoolean(false);
final AtomicInteger subNodes = new AtomicInteger(node.getSubQueries().size());
final CopyOnWriteArrayList<ErrorPacket> errorPackets = new CopyOnWriteArrayList<>();
for (ItemSubQuery itemSubQuery : node.getSubQueries()) {
if (itemSubQuery instanceof ItemSingleRowSubQuery) {
final SubQueryHandler tempHandler = new SingleRowSubQueryHandler(getSequenceId(), session, (ItemSingleRowSubQuery) itemSubQuery);
if (isExplain) {
handleSubQueryForExplain(lock, finishSubQuery, finished, subNodes, itemSubQuery.getPlanNode(), tempHandler);
} else {
handleSubQuery(lock, finishSubQuery, finished, subNodes, errorPackets, itemSubQuery.getPlanNode(), tempHandler);
}
} else if (itemSubQuery instanceof ItemInSubQuery) {
final SubQueryHandler tempHandler = new InSubQueryHandler(getSequenceId(), session, (ItemInSubQuery) itemSubQuery);
if (isExplain) {
handleSubQueryForExplain(lock, finishSubQuery, finished, subNodes, itemSubQuery.getPlanNode(), tempHandler);
} else {
handleSubQuery(lock, finishSubQuery, finished, subNodes, errorPackets, itemSubQuery.getPlanNode(), tempHandler);
}
} else if (itemSubQuery instanceof ItemAllAnySubQuery) {
final SubQueryHandler tempHandler = new AllAnySubQueryHandler(getSequenceId(), session, (ItemAllAnySubQuery) itemSubQuery);
if (isExplain) {
handleSubQueryForExplain(lock, finishSubQuery, finished, subNodes, itemSubQuery.getPlanNode(), tempHandler);
} else {
handleSubQuery(lock, finishSubQuery, finished, subNodes, errorPackets, itemSubQuery.getPlanNode(), tempHandler);
}
}
}
lock.lock();
try {
while (!finished.get()) {
finishSubQuery.await();
}
} catch (InterruptedException e) {
LOGGER.warn("execute ScalarSubQuery " + e);
ErrorPacket errorPackage = new ErrorPacket();
errorPackage.setErrNo(ErrorCode.ER_UNKNOWN_ERROR);
String errorMsg = e.getMessage() == null ? e.toString() : e.getMessage();
errorPackage.setMessage(errorMsg.getBytes(StandardCharsets.UTF_8));
errorPackets.add(errorPackage);
} finally {
lock.unlock();
}
if (errorPackets.size() > 0) {
throw new MySQLOutPutException(errorPackets.get(0).getErrNo(), "", new String(errorPackets.get(0).getMessage(), StandardCharsets.UTF_8));
}
}
private void handleSubQueryForExplain(final ReentrantLock lock, final Condition finishSubQuery, final AtomicBoolean finished,
final AtomicInteger subNodes, final PlanNode planNode, final SubQueryHandler tempHandler) {
tempHandler.setForExplain();
BaseHandlerBuilder builder = hBuilder.getBuilder(session, planNode, true);
DMLResponseHandler endHandler = builder.getEndHandler();
endHandler.setNextHandler(tempHandler);
this.getSubQueryBuilderList().add(builder);
subQueryFinished(subNodes, lock, finished, finishSubQuery);
return;
}
private void handleSubQuery(final ReentrantLock lock, final Condition finishSubQuery, final AtomicBoolean finished,
final AtomicInteger subNodes, final CopyOnWriteArrayList<ErrorPacket> errorPackets, final PlanNode planNode, final SubQueryHandler tempHandler) {
DbleServer.getInstance().getComplexQueryExecutor().execute(new Runnable() {
@Override
public void run() {
try {
DMLResponseHandler endHandler = hBuilder.buildNode(session, planNode, false);
endHandler.setNextHandler(tempHandler);
CallBackHandler tempDone = new CallBackHandler() {
@Override
public void call() throws Exception {
if (tempHandler.getErrorPacket() != null) {
errorPackets.add(tempHandler.getErrorPacket());
}
subQueryFinished(subNodes, lock, finished, finishSubQuery);
}
};
tempHandler.setTempDoneCallBack(tempDone);
HandlerBuilder.startHandler(endHandler);
} catch (Exception e) {
LOGGER.warn("execute ItemScalarSubQuery error", e);
ErrorPacket errorPackage = new ErrorPacket();
errorPackage.setErrNo(ErrorCode.ER_UNKNOWN_ERROR);
String errorMsg = e.getMessage() == null ? e.toString() : e.getMessage();
errorPackage.setMessage(errorMsg.getBytes(StandardCharsets.UTF_8));
errorPackets.add(errorPackage);
}
}
});
}
private void subQueryFinished(AtomicInteger subNodes, ReentrantLock lock, AtomicBoolean finished, Condition finishSubQuery) {
if (subNodes.decrementAndGet() == 0) {
lock.lock();
try {
finished.set(true);
finishSubQuery.signal();
} finally {
lock.unlock();
}
}
}
}
@@ -54,15 +54,20 @@ public class HandlerBuilder {
* @param planNode
* @return
*/
public DMLResponseHandler buildNode(NonBlockingSession nonBlockingSession, PlanNode planNode) {
BaseHandlerBuilder builder = createBuilder(nonBlockingSession, planNode);
builder.build();
public DMLResponseHandler buildNode(NonBlockingSession nonBlockingSession, PlanNode planNode, boolean isExplain) {
BaseHandlerBuilder builder = getBuilder(nonBlockingSession, planNode, isExplain);
return builder.getEndHandler();
}
public BaseHandlerBuilder getBuilder(NonBlockingSession nonBlockingSession, PlanNode planNode, boolean isExplain) {
BaseHandlerBuilder builder = createBuilder(nonBlockingSession, planNode, isExplain);
builder.build();
return builder;
}
public void build(boolean hasNext) throws Exception {
final long startTime = System.nanoTime();
DMLResponseHandler endHandler = buildNode(session, node);
DMLResponseHandler endHandler = buildNode(session, node, false);
OutputHandler fh = new OutputHandler(BaseHandlerBuilder.getSequenceId(), session, hasNext);
endHandler.setNextHandler(fh);
HandlerBuilder.startHandler(fh);
@@ -70,18 +75,18 @@ public class HandlerBuilder {
logger.info("HandlerBuilder.build cost:" + (endTime - startTime));
}
private BaseHandlerBuilder createBuilder(final NonBlockingSession nonBlockingSession, PlanNode planNode) {
private BaseHandlerBuilder createBuilder(final NonBlockingSession nonBlockingSession, PlanNode planNode, boolean isExplain) {
PlanNode.PlanNodeType i = planNode.type();
if (i == PlanNode.PlanNodeType.TABLE) {
return new TableNodeHandlerBuilder(nonBlockingSession, (TableNode) planNode, this);
return new TableNodeHandlerBuilder(nonBlockingSession, (TableNode) planNode, this, isExplain);
} else if (i == PlanNode.PlanNodeType.JOIN) {
return new JoinNodeHandlerBuilder(nonBlockingSession, (JoinNode) planNode, this);
return new JoinNodeHandlerBuilder(nonBlockingSession, (JoinNode) planNode, this, isExplain);
} else if (i == PlanNode.PlanNodeType.MERGE) {
return new MergeNodeHandlerBuilder(nonBlockingSession, (MergeNode) planNode, this);
return new MergeNodeHandlerBuilder(nonBlockingSession, (MergeNode) planNode, this, isExplain);
} else if (i == PlanNode.PlanNodeType.QUERY) {
return new QueryNodeHandlerBuilder(nonBlockingSession, (QueryNode) planNode, this);
return new QueryNodeHandlerBuilder(nonBlockingSession, (QueryNode) planNode, this, isExplain);
} else if (i == PlanNode.PlanNodeType.NONAME) {
return new NoNameNodeHandlerBuilder(nonBlockingSession, (NoNameNode) planNode, this);
return new NoNameNodeHandlerBuilder(nonBlockingSession, (NoNameNode) planNode, this, isExplain);
}
throw new RuntimeException("not supported tree node type:" + planNode.type());
}
@@ -29,11 +29,13 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import static com.actiontech.dble.plan.optimizer.JoinStrategyProcessor.NEED_REPLACE;
class JoinNodeHandlerBuilder extends BaseHandlerBuilder {
private JoinNode node;
protected JoinNodeHandlerBuilder(NonBlockingSession session, JoinNode node, HandlerBuilder hBuilder) {
super(session, node, hBuilder);
protected JoinNodeHandlerBuilder(NonBlockingSession session, JoinNode node, HandlerBuilder hBuilder, boolean isExplain) {
super(session, node, hBuilder, isExplain);
this.node = node;
}
@@ -42,6 +44,11 @@ class JoinNodeHandlerBuilder extends BaseHandlerBuilder {
return PlanUtil.isGlobalOrER(node);
}
@Override
protected void handleSubQueries() {
handleBlockingSubQuery();
}
@Override
public void mergeBuild() {
try {
@@ -99,6 +106,11 @@ class JoinNodeHandlerBuilder extends BaseHandlerBuilder {
HandlerBuilder.startHandler(bigLh);
}
};
if (isExplain) {
buildNestFiltersForExplain(tnBig, keyToPass);
DMLResponseHandler bigLh = buildJoinChild(tnBig, !isLeftSmall);
tempHandler.setCreatedHandler(bigLh);
}
tempHandler.setTempDoneCallBack(tempDone);
} else if (node.getStrategy() == JoinNode.Strategy.SORTMERGE) {
@@ -114,7 +126,11 @@ class JoinNodeHandlerBuilder extends BaseHandlerBuilder {
}
private DMLResponseHandler buildJoinChild(PlanNode child, boolean isLeft) {
DMLResponseHandler endHandler = hBuilder.buildNode(session, child);
BaseHandlerBuilder builder = hBuilder.getBuilder(session, child, isExplain);
if (builder.getSubQueryBuilderList().size() > 0) {
this.getSubQueryBuilderList().addAll(builder.getSubQueryBuilderList());
}
DMLResponseHandler endHandler = builder.getEndHandler();
if (isLeft) {
if (!node.isLeftOrderMatch()) {
OrderByHandler oh = new OrderByHandler(getSequenceId(), session, node.getLeftJoinOnOrders());
@@ -145,6 +161,16 @@ class JoinNodeHandlerBuilder extends BaseHandlerBuilder {
}
}
private void buildNestFiltersForExplain(PlanNode tnBig, Item keyToPass) {
Item keyInBig = PlanUtil.pushDownItem(node, keyToPass);
List<Item> strategyFilters = tnBig.getNestLoopFilters();
List<Item> argList = new ArrayList<>();
argList.add(keyInBig);
argList.add(new ItemString(NEED_REPLACE));
ItemFuncIn filter = new ItemFuncIn(argList, false);
strategyFilters.add(filter);
}
/**
* generate filter for big table according to tmp(small) table's result
*
@@ -18,16 +18,24 @@ import java.util.List;
class MergeNodeHandlerBuilder extends BaseHandlerBuilder {
private MergeNode node;
protected MergeNodeHandlerBuilder(NonBlockingSession session, MergeNode node, HandlerBuilder hBuilder) {
super(session, node, hBuilder);
protected MergeNodeHandlerBuilder(NonBlockingSession session, MergeNode node, HandlerBuilder hBuilder, boolean isExplain) {
super(session, node, hBuilder, isExplain);
this.node = node;
}
@Override
protected void handleSubQueries() {
}
@Override
protected List<DMLResponseHandler> buildPre() {
List<DMLResponseHandler> pres = new ArrayList<>();
for (PlanNode child : node.getChildren()) {
DMLResponseHandler ch = hBuilder.buildNode(session, child);
BaseHandlerBuilder builder = hBuilder.getBuilder(session, child, isExplain);
if (builder.getSubQueryBuilderList().size() > 0) {
this.getSubQueryBuilderList().addAll(builder.getSubQueryBuilderList());
}
DMLResponseHandler ch = builder.getEndHandler();
pres.add(ch);
}
return pres;
@@ -25,13 +25,18 @@ import java.util.List;
class NoNameNodeHandlerBuilder extends BaseHandlerBuilder {
private NoNameNode node;
protected NoNameNodeHandlerBuilder(NonBlockingSession session, NoNameNode node, HandlerBuilder hBuilder) {
super(session, node, hBuilder);
protected NoNameNodeHandlerBuilder(NonBlockingSession session, NoNameNode node, HandlerBuilder hBuilder, boolean isExplain) {
super(session, node, hBuilder, isExplain);
this.node = node;
this.needWhereHandler = false;
this.needCommon = false;
}
@Override
protected void handleSubQueries() {
handleBlockingSubQuery();
}
@Override
public List<DMLResponseHandler> buildPre() {
return new ArrayList<>();
@@ -18,16 +18,24 @@ class QueryNodeHandlerBuilder extends BaseHandlerBuilder {
private QueryNode node;
protected QueryNodeHandlerBuilder(NonBlockingSession session,
QueryNode node, HandlerBuilder hBuilder) {
super(session, node, hBuilder);
QueryNode node, HandlerBuilder hBuilder, boolean isExplain) {
super(session, node, hBuilder, isExplain);
this.node = node;
}
@Override
protected void handleSubQueries() {
}
@Override
public List<DMLResponseHandler> buildPre() {
List<DMLResponseHandler> pres = new ArrayList<>();
PlanNode subNode = node.getChild();
DMLResponseHandler subHandler = hBuilder.buildNode(session, subNode);
BaseHandlerBuilder builder = hBuilder.getBuilder(session, subNode, isExplain);
if (builder.getSubQueryBuilderList().size() > 0) {
this.getSubQueryBuilderList().addAll(builder.getSubQueryBuilderList());
}
DMLResponseHandler subHandler = builder.getEndHandler();
pres.add(subHandler);
return pres;
}
@@ -24,14 +24,19 @@ class TableNodeHandlerBuilder extends BaseHandlerBuilder {
private TableNode node;
private TableConfig tableConfig = null;
protected TableNodeHandlerBuilder(NonBlockingSession session, TableNode node, HandlerBuilder hBuilder) {
super(session, node, hBuilder);
protected TableNodeHandlerBuilder(NonBlockingSession session, TableNode node, HandlerBuilder hBuilder, boolean isExplain) {
super(session, node, hBuilder, isExplain);
this.node = node;
this.canPushDown = !node.existUnPushDownGroup();
this.needWhereHandler = false;
this.tableConfig = getTableConfig(node.getSchema(), node.getTableName());
}
@Override
protected void handleSubQueries() {
handleBlockingSubQuery();
}
@Override
public List<DMLResponseHandler> buildPre() {
return new ArrayList<>();
@@ -47,7 +52,7 @@ class TableNodeHandlerBuilder extends BaseHandlerBuilder {
this.needSendMaker = mergeBuilder.getNeedSendMakerFlag();
buildMergeHandler(node, rrssArray);
} catch (Exception e) {
throw new MySQLOutPutException(ErrorCode.ER_QUERYHANDLER, "", "tablenode buildOwn exception!", e);
throw new MySQLOutPutException(ErrorCode.ER_QUERYHANDLER, "", "table node buildOwn exception!", e);
}
}
@@ -90,5 +95,4 @@ class TableNodeHandlerBuilder extends BaseHandlerBuilder {
throw new MySQLOutPutException(ErrorCode.ER_QUERYHANDLER, "", "", e);
}
}
}
@@ -74,6 +74,8 @@ public class GlobalVisitor extends MysqlVisitor {
buildHaving(query);
buildOrderBy(query);
buildLimit(query);
} else {
whereFilter = query.getWhereFilter();
}
if (query.isSubQuery() && !parentIsQuery && !isTopQuery) {
@@ -146,10 +148,9 @@ public class GlobalVisitor extends MysqlVisitor {
if (!isTopQuery) {
sqlBuilder.append(" ( ");
}
if (join.isSubQuery() || isTopQuery) {
buildSelect(join);
sqlBuilder.append(" from ");
}
buildSelect(join);
sqlBuilder.append(" from ");
PlanNode left = join.getLeftNode();
MysqlVisitor leftVisitor = new GlobalVisitor(left, false);
@@ -182,31 +183,27 @@ public class GlobalVisitor extends MysqlVisitor {
}
if (join.getOtherJoinOnFilter() != null) {
if (first) {
first = false;
} else {
if (!first) {
joinOnFilterStr.append(" and ");
}
joinOnFilterStr.append(join.getOtherJoinOnFilter());
}
sqlBuilder.append(joinOnFilterStr.toString());
if (join.isSubQuery() || isTopQuery) {
buildWhere(join);
buildGroupBy(join);
buildHaving(join);
buildOrderBy(join);
buildLimit(join);
}
buildWhere(join);
buildGroupBy(join);
buildHaving(join);
buildOrderBy(join);
buildLimit(join);
if (!isTopQuery) {
sqlBuilder.append(" ) ");
if (join.getAlias() != null)
sqlBuilder.append(" ").append(join.getAlias()).append(" ");
}
}
protected void buildSelect(PlanNode query) {
sqlBuilder.append("select ");
boolean hasDistinct = query.isDistinct();
@@ -9,11 +9,19 @@ import com.actiontech.dble.plan.PlanNode;
import com.actiontech.dble.plan.PlanNode.PlanNodeType;
import com.actiontech.dble.plan.common.item.Item;
import com.actiontech.dble.plan.common.item.Item.ItemType;
import com.actiontech.dble.plan.common.item.ItemInt;
import com.actiontech.dble.plan.common.item.function.operator.cmpfunc.ItemFuncEqual;
import com.actiontech.dble.plan.common.item.function.operator.cmpfunc.ItemFuncIn;
import com.actiontech.dble.plan.common.item.function.operator.logic.ItemCondAnd;
import com.actiontech.dble.plan.common.item.function.operator.logic.ItemCondOr;
import com.actiontech.dble.plan.common.item.subquery.*;
import com.actiontech.dble.plan.common.ptr.StringPtr;
import com.actiontech.dble.plan.node.TableNode;
import com.actiontech.dble.plan.util.PlanUtil;
import com.alibaba.druid.sql.ast.SQLHint;
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlOutputVisitor;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -40,8 +48,7 @@ public abstract class MysqlVisitor {
// tmp sql
protected StringBuilder sqlBuilder;
protected StringPtr replaceableWhere = new StringPtr("");
protected Item whereFilter = null;
public MysqlVisitor(PlanNode query, boolean isTopQuery) {
this.query = query;
this.isTopQuery = isTopQuery;
@@ -89,6 +96,7 @@ public abstract class MysqlVisitor {
String pdName = visitUnSelPushDownName(filter, false);
whereBuilder.append(" where ").append(pdName);
}
replaceableWhere.set(whereBuilder.toString());
// refresh sqlbuilder
sqlBuilder = replaceableSqlBuilder.getCurrentElement().getSb();
@@ -108,8 +116,86 @@ public abstract class MysqlVisitor {
*/
protected abstract String visitPushDownNameSel(Item o);
private Item genBoolItem(boolean isTrue) {
if (isTrue) {
return new ItemFuncEqual(new ItemInt(1), new ItemInt(1));
} else {
return new ItemFuncEqual(new ItemInt(1), new ItemInt(0));
}
}
private Item rebuildSubQueryItem(Item item) {
if (PlanUtil.isCmpFunc(item)) {
Item res1 = rebuildBoolSubQuery(item, 0);
if (res1 != null) {
return res1;
}
Item res2 = rebuildBoolSubQuery(item, 1);
if (res2 != null) {
return res2;
}
} else if (item instanceof ItemInSubQuery) {
ItemInSubQuery inSubItem = (ItemInSubQuery) item;
if (inSubItem.getValue().size() == 0) {
return genBoolItem(inSubItem.isNeg());
} else {
List<Item> args = new ArrayList<>(inSubItem.getValue().size() + 1);
args.add(inSubItem.getLeftOperand());
args.addAll(inSubItem.getValue());
return new ItemFuncIn(args, inSubItem.isNeg());
}
} else if (item instanceof ItemExistsSubQuery) {
ItemExistsSubQuery existsSubQuery = (ItemExistsSubQuery) item;
Item result = existsSubQuery.getValue();
if (result == null) {
return genBoolItem(existsSubQuery.isNot());
} else {
return genBoolItem(!existsSubQuery.isNot());
}
} else if (item instanceof ItemCondAnd || item instanceof ItemCondOr) {
for (int index = 0; index < item.getArgCount(); index++) {
Item rebuildItem = rebuildSubQueryItem(item.arguments().get(index));
item.arguments().set(index, rebuildItem);
item.setItemName(null);
}
}
return item;
}
private Item rebuildBoolSubQuery(Item item, int index) {
Item arg = item.arguments().get(index);
if (arg.type().equals(ItemType.SUBSELECT_ITEM)) {
if (arg instanceof ItemScalarSubQuery) {
Item result = ((ItemScalarSubQuery) arg).getValue();
if (result == null || result.getResultItem() == null) {
return new ItemFuncEqual(new ItemInt(1), new ItemInt(0));
}
item.arguments().set(index, result.getResultItem());
item.setItemName(null);
} else if (arg instanceof ItemAllAnySubQuery) {
ItemAllAnySubQuery allAnySubItem = (ItemAllAnySubQuery) arg;
if (allAnySubItem.getValue().size() == 0) {
return genBoolItem(allAnySubItem.isAll());
} else if (allAnySubItem.getValue().size() == 1) {
Item value = allAnySubItem.getValue().get(0);
if (value == null) {
return new ItemFuncEqual(new ItemInt(1), new ItemInt(0));
}
item.arguments().set(index, value.getResultItem());
item.setItemName(null);
} else {
return genBoolItem(!allAnySubItem.isAll());
}
}
}
return null;
}
// pushDown's name of not in select list
public final String visitUnSelPushDownName(Item item, boolean canUseAlias) {
if (item.isWithSubQuery()) {
item = rebuildSubQueryItem(item);
}
String selName = item.getItemName();
if (item.type().equals(ItemType.FIELD_ITEM)) {
selName = "`" + item.getTableName() + "`.`" + selName + "`";
@@ -125,4 +211,9 @@ public abstract class MysqlVisitor {
}
return selName;
}
public Item getWhereFilter() {
return whereFilter;
}
}
@@ -10,6 +10,7 @@ import com.actiontech.dble.plan.PlanNode;
import com.actiontech.dble.plan.common.item.Item;
import com.actiontech.dble.plan.common.item.function.sumfunc.ItemSum;
import com.actiontech.dble.plan.node.JoinNode;
import com.actiontech.dble.plan.node.NoNameNode;
import com.actiontech.dble.plan.node.TableNode;
import org.apache.commons.lang.StringUtils;
@@ -44,6 +45,9 @@ public class PushDownVisitor extends MysqlVisitor {
} else if (i == PlanNode.PlanNodeType.JOIN) {
visit((JoinNode) query);
} else if (i == PlanNode.PlanNodeType.NONAME) {
visit((NoNameNode) query);
} else {
throw new RuntimeException("not implement yet!");
}
@@ -54,6 +58,9 @@ public class PushDownVisitor extends MysqlVisitor {
}
}
protected void visit(NoNameNode query) {
buildSelect(query);
}
protected void visit(TableNode query) {
if (query.isSubQuery() && !isTopQuery) {
@@ -112,29 +119,10 @@ public class PushDownVisitor extends MysqlVisitor {
rightVisitor.visit();
replaceableSqlBuilder.append(rightVisitor.getSql());
sqlBuilder = replaceableSqlBuilder.getCurrentElement().getSb();
StringBuilder joinOnFilterStr = new StringBuilder();
boolean first = true;
for (int i = 0; i < join.getJoinFilter().size(); i++) {
Item filter = join.getJoinFilter().get(i);
if (first) {
sqlBuilder.append(" on ");
first = false;
} else
joinOnFilterStr.append(" and ");
joinOnFilterStr.append(filter);
}
if (join.getOtherJoinOnFilter() != null) {
if (first) {
first = false;
} else {
joinOnFilterStr.append(" and ");
}
joinOnFilterStr.append(join.getOtherJoinOnFilter());
}
StringBuilder joinOnFilterStr = getJoinOn(join, leftVisitor, rightVisitor);
sqlBuilder.append(joinOnFilterStr.toString());
if (join.isSubQuery() || isTopQuery) {
buildWhere(join);
buildWhere(join, leftVisitor.getWhereFilter(), rightVisitor.getWhereFilter());
buildGroupBy(join);
// having may contains aggregate function, so it need to calc by middle-ware
buildOrderBy(join);
@@ -149,12 +137,85 @@ public class PushDownVisitor extends MysqlVisitor {
}
private StringBuilder getJoinOn(JoinNode join, MysqlVisitor leftVisitor, MysqlVisitor rightVisitor) {
StringBuilder joinOnFilterStr = new StringBuilder();
boolean first = true;
for (int i = 0; i < join.getJoinFilter().size(); i++) {
Item filter = join.getJoinFilter().get(i);
if (first) {
sqlBuilder.append(" on ");
first = false;
} else
joinOnFilterStr.append(" and ");
joinOnFilterStr.append(filter);
}
if (join.getOtherJoinOnFilter() != null) {
if (!first) {
joinOnFilterStr.append(" and ");
}
joinOnFilterStr.append(join.getOtherJoinOnFilter());
}
// is not left join
if (leftVisitor.getWhereFilter() != null && !join.getLeftOuter()) {
if (!first) {
joinOnFilterStr.append(" and ");
}
joinOnFilterStr.append("(");
joinOnFilterStr.append(leftVisitor.getWhereFilter());
joinOnFilterStr.append(")");
}
// is not right join
if (rightVisitor.getWhereFilter() != null && !join.getRightOuter()) {
if (!first) {
joinOnFilterStr.append(" and ");
}
joinOnFilterStr.append("(");
joinOnFilterStr.append(rightVisitor.getWhereFilter());
joinOnFilterStr.append(")");
}
return joinOnFilterStr;
}
protected void buildWhere(JoinNode planNode, Item leftFilter, Item rightFilter) {
if (!visited)
replaceableSqlBuilder.getCurrentElement().setRepString(replaceableWhere);
StringBuilder whereBuilder = new StringBuilder();
Item filter = planNode.getWhereFilter();
if (filter != null) {
String pdName = visitUnSelPushDownName(filter, false);
whereBuilder.append(" where ").append(pdName);
} else {
whereBuilder.append(" where 1=1 ");
}
// left join
if (leftFilter != null && !planNode.getRightOuter() && planNode.getLeftOuter()) {
String pdName = visitUnSelPushDownName(leftFilter, false);
whereBuilder.append(" and (");
whereBuilder.append(pdName);
whereBuilder.append(")");
}
//right join
if (rightFilter != null && !planNode.getLeftOuter() && planNode.getRightOuter()) {
String pdName = visitUnSelPushDownName(rightFilter, false);
whereBuilder.append(" and (");
whereBuilder.append(pdName);
whereBuilder.append(")");
}
replaceableWhere.set(whereBuilder.toString());
// refresh sqlbuilder
sqlBuilder = replaceableSqlBuilder.getCurrentElement().getSb();
}
protected void buildSelect(PlanNode query) {
sqlBuilder.append("select ");
List<Item> columns = query.getColumnsRefered();
if (query.isDistinct()) {
sqlBuilder.append("DISTINCT ");
}
List<Item> columns = query.getColumnsRefered();
if (columns.size() == 0) {
sqlBuilder.append("1");
return;
}
for (Item col : columns) {
if (existUnPushDownGroup && col.type().equals(Item.ItemType.SUM_FUNC_ITEM))
continue;
@@ -11,7 +11,7 @@ import java.util.Set;
public interface DMLResponseHandler extends ResponseHandler {
enum HandlerType {
DIRECT, TEMPTABLE, BASESEL, REFRESHFP, MERGE, JOIN, WHERE, GROUPBY, HAVING, ORDERBY, LIMIT, UNION, DISTINCT, SENDMAKER, FINAL
DIRECT, TEMPTABLE, BASESEL, REFRESHFP, MERGE, JOIN, WHERE, GROUPBY, HAVING, ORDERBY, LIMIT, UNION, DISTINCT, SENDMAKER, FINAL, SCALAR_SUB_QUERY, IN_SUB_QUERY, ALL_ANY_SUB_QUERY
}
HandlerType type();
@@ -42,6 +42,10 @@ public abstract class OwnThreadDMLHandler extends BaseDMLHandler {
}
}
protected final void startEasyMerge() {
ownJobFlag.compareAndSet(false, true);
}
/**
* @param objects
*/
@@ -135,8 +135,7 @@ public class BaseSelectHandler extends BaseDMLHandler {
public void connectionError(Throwable e, BackendConnection conn) {
if (terminate.get())
return;
LOGGER.warn(
conn.toString() + "|connectionError()|" + e.getMessage());
LOGGER.warn(conn.toString() + "|connectionError()|" + e.getMessage());
session.onQueryError(e.getMessage().getBytes());
}
@@ -109,7 +109,9 @@ public class MultiNodeMergeHandler extends OwnThreadDMLHandler {
rowComparator = makeRowDataSorter((MySQLConnection) conn);
nextHandler.fieldEofResponse(null, null, fieldPackets, null, this.isLeft, conn);
}
if (!isEasyMerge) {
if (isEasyMerge) {
startEasyMerge();
} else {
if (++reachedConCount == route.length) {
startOwnThread();
}
@@ -172,6 +172,11 @@ public class TempTableHandler extends BaseDMLHandler {
return maxPartSize;
}
public DMLResponseHandler getCreatedHandler() {
return createdHandler;
}
@Override
public HandlerType type() {
return HandlerType.TEMPTABLE;
@@ -0,0 +1,171 @@
/*
* Copyright (C) 2016-2017 ActionTech.
* License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher.
*/
package com.actiontech.dble.backend.mysql.nio.handler.query.impl.subquery;
import com.actiontech.dble.backend.BackendConnection;
import com.actiontech.dble.backend.mysql.nio.handler.util.HandlerTool;
import com.actiontech.dble.backend.mysql.nio.handler.util.RowDataComparator;
import com.actiontech.dble.net.mysql.FieldPacket;
import com.actiontech.dble.net.mysql.RowDataPacket;
import com.actiontech.dble.plan.Order;
import com.actiontech.dble.plan.common.field.Field;
import com.actiontech.dble.plan.common.item.Item;
import com.actiontech.dble.plan.common.item.ItemString;
import com.actiontech.dble.plan.common.item.subquery.ItemAllAnySubQuery;
import com.actiontech.dble.server.NonBlockingSession;
import java.util.Collections;
import java.util.List;
public class AllAnySubQueryHandler extends SubQueryHandler {
private ItemAllAnySubQuery itemSubQuery;
private Field sourceField;
private RowDataPacket tmpRow;
private RowDataComparator rowComparator;
public AllAnySubQueryHandler(long id, NonBlockingSession session, ItemAllAnySubQuery itemSubQuery) {
super(id, session);
this.itemSubQuery = itemSubQuery;
}
@Override
public void fieldEofResponse(byte[] headerNull, List<byte[]> fieldsNull, List<FieldPacket> fieldPackets,
byte[] eofNull, boolean isLeft, BackendConnection conn) {
if (terminate.get()) {
return;
}
lock.lock();
try {
// create field for first time
if (this.fieldPackets.isEmpty()) {
this.fieldPackets = fieldPackets;
sourceField = HandlerTool.createField(this.fieldPackets.get(0));
Item select = itemSubQuery.getSelect();
select.setPushDownName(select.getAlias());
Item tmpItem = HandlerTool.createItem(select, Collections.singletonList(this.sourceField), 0, isAllPushDown(), type());
itemSubQuery.setFiled(tmpItem);
rowComparator = new RowDataComparator(this.fieldPackets, Collections.singletonList(new Order(select)), this.isAllPushDown(), this.type());
}
} finally {
lock.unlock();
}
}
@Override
public boolean rowResponse(byte[] rowNull, RowDataPacket rowPacket, boolean isLeft, BackendConnection conn) {
lock.lock();
try {
if (terminate.get()) {
return true;
}
RowDataPacket row = rowPacket;
if (row == null) {
row = new RowDataPacket(this.fieldPackets.size());
row.read(rowNull);
}
sourceField.setPtr(row.getValue(0));
Item value = itemSubQuery.getFiled().getResultItem();
if (itemSubQuery.getValue().size() == 0) {
itemSubQuery.getValue().add(value);
tmpRow = row;
} else if (itemSubQuery.getValue().size() == 1) {
handleNewRow(row, value);
} else {
// ignore row
}
} finally {
lock.unlock();
}
return false;
}
@Override
public HandlerType type() {
return HandlerType.ALL_ANY_SUB_QUERY;
}
private void handleNewRow(RowDataPacket row, Item value) {
int result = rowComparator.compare(tmpRow, row);
switch (itemSubQuery.getOperator()) {
case Equality:
if (itemSubQuery.isAll() && result != 0) {
itemSubQuery.getValue().add(value);
}
break;
case NotEqual:
case LessThanOrGreater:
if (!itemSubQuery.isAll() && result != 0) {
itemSubQuery.getValue().add(value);
}
break;
case LessThan:
case LessThanOrEqual:
if (itemSubQuery.isAll() && result > 0) {
//row < tmpRow
itemSubQuery.getValue().set(0, value);
tmpRow = row;
} else if (!itemSubQuery.isAll() && result < 0) {
//row > tmpRow
itemSubQuery.getValue().set(0, value);
tmpRow = row;
}
break;
case GreaterThan:
case GreaterThanOrEqual:
if (itemSubQuery.isAll() && result < 0) {
//row > tmpRow
itemSubQuery.getValue().set(0, value);
tmpRow = row;
} else if (!itemSubQuery.isAll() && result > 0) {
//row < tmpRow
itemSubQuery.getValue().set(0, value);
tmpRow = row;
}
break;
default:
break;
}
}
@Override
public void setForExplain() {
switch (itemSubQuery.getOperator()) {
case Equality:
if (itemSubQuery.isAll()) {
itemSubQuery.getValue().add(new ItemString("{ALL_SUB_QUERY_RESULTS}"));
}
break;
case NotEqual:
case LessThanOrGreater:
if (!itemSubQuery.isAll()) {
itemSubQuery.getValue().add(new ItemString("{ALL_SUB_QUERY_RESULTS}"));
}
break;
case LessThan:
case LessThanOrEqual:
if (itemSubQuery.isAll()) {
//row < tmpRow
itemSubQuery.getValue().add(new ItemString("{MIN_SUB_QUERY_RESULTS}"));
} else if (!itemSubQuery.isAll()) {
//row > tmpRow
itemSubQuery.getValue().add(new ItemString("{MAX_SUB_QUERY_RESULTS}"));
}
break;
case GreaterThan:
case GreaterThanOrEqual:
if (itemSubQuery.isAll()) {
//row > tmpRow
itemSubQuery.getValue().add(new ItemString("{MAX_SUB_QUERY_RESULTS}"));
} else if (!itemSubQuery.isAll()) {
//row < tmpRow
itemSubQuery.getValue().add(new ItemString("{MIN_SUB_QUERY_RESULTS}"));
}
break;
default:
break;
}
}
}
@@ -0,0 +1,105 @@
/*
* Copyright (C) 2016-2017 ActionTech.
* License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher.
*/
package com.actiontech.dble.backend.mysql.nio.handler.query.impl.subquery;
import com.actiontech.dble.DbleServer;
import com.actiontech.dble.backend.BackendConnection;
import com.actiontech.dble.backend.mysql.nio.handler.util.HandlerTool;
import com.actiontech.dble.config.ErrorCode;
import com.actiontech.dble.net.mysql.FieldPacket;
import com.actiontech.dble.net.mysql.RowDataPacket;
import com.actiontech.dble.plan.common.field.Field;
import com.actiontech.dble.plan.common.item.Item;
import com.actiontech.dble.plan.common.item.ItemString;
import com.actiontech.dble.plan.common.item.subquery.ItemInSubQuery;
import com.actiontech.dble.server.NonBlockingSession;
import java.util.Collections;
import java.util.List;
import static com.actiontech.dble.plan.optimizer.JoinStrategyProcessor.NEED_REPLACE;
public class InSubQueryHandler extends SubQueryHandler {
private int maxPartSize = 2000;
private int maxConnSize = 4;
private int rowCount = 0;
private Field sourceField;
private ItemInSubQuery itemSubQuery;
public InSubQueryHandler(long id, NonBlockingSession session, ItemInSubQuery itemSubQuery) {
super(id, session);
this.itemSubQuery = itemSubQuery;
this.maxPartSize = DbleServer.getInstance().getConfig().getSystem().getNestLoopRowsSize();
this.maxConnSize = DbleServer.getInstance().getConfig().getSystem().getNestLoopConnSize();
}
@Override
public void fieldEofResponse(byte[] headerNull, List<byte[]> fieldsNull, List<FieldPacket> fieldPackets,
byte[] eofNull, boolean isLeft, BackendConnection conn) {
if (terminate.get()) {
return;
}
lock.lock();
try {
// create field for first time
if (this.fieldPackets.isEmpty()) {
this.fieldPackets = fieldPackets;
sourceField = HandlerTool.createField(this.fieldPackets.get(0));
Item select = itemSubQuery.getSelect();
select.setPushDownName(select.getAlias());
Item tmpItem = HandlerTool.createItem(select, Collections.singletonList(this.sourceField), 0, isAllPushDown(), type());
itemSubQuery.setFiled(tmpItem);
}
} finally {
lock.unlock();
}
}
@Override
public boolean rowResponse(byte[] rowNull, RowDataPacket rowPacket, boolean isLeft, BackendConnection conn) {
lock.lock();
try {
if (terminate.get()) {
return true;
}
if (++rowCount > maxPartSize * maxConnSize) {
String errMessage = "sub query too much rows!";
LOGGER.warn(errMessage);
genErrorPackage(ErrorCode.ER_UNKNOWN_ERROR, errMessage);
conn.close(errMessage);
try {
tempDoneCallBack.call();
} catch (Exception callback) {
LOGGER.warn("callback exception!", callback);
}
return true;
}
RowDataPacket row = rowPacket;
if (row == null) {
row = new RowDataPacket(this.fieldPackets.size());
row.read(rowNull);
}
sourceField.setPtr(row.getValue(0));
Item value = itemSubQuery.getFiled().getResultItem();
if (value != null) {
itemSubQuery.getValue().add(value);
}
} finally {
lock.unlock();
}
return false;
}
@Override
public HandlerType type() {
return HandlerType.IN_SUB_QUERY;
}
@Override
public void setForExplain() {
itemSubQuery.getValue().add(new ItemString(NEED_REPLACE));
}
}
@@ -0,0 +1,99 @@
/*
* Copyright (C) 2016-2017 ActionTech.
* License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher.
*/
package com.actiontech.dble.backend.mysql.nio.handler.query.impl.subquery;
import com.actiontech.dble.backend.BackendConnection;
import com.actiontech.dble.backend.mysql.nio.handler.util.HandlerTool;
import com.actiontech.dble.config.ErrorCode;
import com.actiontech.dble.net.mysql.FieldPacket;
import com.actiontech.dble.net.mysql.RowDataPacket;
import com.actiontech.dble.plan.common.field.Field;
import com.actiontech.dble.plan.common.item.Item;
import com.actiontech.dble.plan.common.item.ItemString;
import com.actiontech.dble.plan.common.item.subquery.ItemSingleRowSubQuery;
import com.actiontech.dble.server.NonBlockingSession;
import java.util.Collections;
import java.util.List;
import static com.actiontech.dble.plan.optimizer.JoinStrategyProcessor.NEED_REPLACE;
public class SingleRowSubQueryHandler extends SubQueryHandler {
private int rowCount = 0;
private Field sourceField;
private ItemSingleRowSubQuery itemSubQuery;
public SingleRowSubQueryHandler(long id, NonBlockingSession session, ItemSingleRowSubQuery itemSubQuery) {
super(id, session);
this.itemSubQuery = itemSubQuery;
}
@Override
public void fieldEofResponse(byte[] headerNull, List<byte[]> fieldsNull, List<FieldPacket> fieldPackets,
byte[] eofNull, boolean isLeft, BackendConnection conn) {
if (terminate.get()) {
return;
}
lock.lock();
try {
// create field for first time
if (this.fieldPackets.isEmpty()) {
this.fieldPackets = fieldPackets;
sourceField = HandlerTool.createField(this.fieldPackets.get(0));
if (itemSubQuery.isField()) {
setSubQueryFiled();
}
}
} finally {
lock.unlock();
}
}
@Override
public boolean rowResponse(byte[] rowNull, RowDataPacket rowPacket, boolean isLeft, BackendConnection conn) {
lock.lock();
try {
if (terminate.get()) {
return true;
}
if (++rowCount > 1) {
String errMessage = "Subquery returns more than 1 row";
LOGGER.warn(errMessage);
genErrorPackage(ErrorCode.ER_SUBQUERY_NO_1_ROW, errMessage);
return true;
}
RowDataPacket row = rowPacket;
if (row == null) {
row = new RowDataPacket(this.fieldPackets.size());
row.read(rowNull);
}
if (!itemSubQuery.isField()) {
setSubQueryFiled();
}
sourceField.setPtr(row.getValue(0));
} finally {
lock.unlock();
}
return false;
}
@Override
public HandlerType type() {
return HandlerType.SCALAR_SUB_QUERY;
}
private void setSubQueryFiled() {
Item select = itemSubQuery.getSelect();
select.setPushDownName(select.getAlias());
Item tmpItem = HandlerTool.createItem(select, Collections.singletonList(this.sourceField), 0, isAllPushDown(), type());
itemSubQuery.setValue(tmpItem);
}
@Override
public void setForExplain() {
itemSubQuery.setValue(new ItemString(NEED_REPLACE));
}
}
@@ -0,0 +1,100 @@
/*
* Copyright (C) 2016-2017 ActionTech.
* License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher.
*/
package com.actiontech.dble.backend.mysql.nio.handler.query.impl.subquery;
import com.actiontech.dble.backend.BackendConnection;
import com.actiontech.dble.backend.mysql.nio.handler.query.BaseDMLHandler;
import com.actiontech.dble.backend.mysql.nio.handler.util.CallBackHandler;
import com.actiontech.dble.backend.mysql.nio.handler.util.HandlerTool;
import com.actiontech.dble.config.ErrorCode;
import com.actiontech.dble.net.mysql.ErrorPacket;
import com.actiontech.dble.server.NonBlockingSession;
import org.apache.log4j.Logger;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.locks.ReentrantLock;
public abstract class SubQueryHandler extends BaseDMLHandler {
protected static final Logger LOGGER = Logger.getLogger(SubQueryHandler.class);
protected final ReentrantLock lock;
protected CallBackHandler tempDoneCallBack;
protected ErrorPacket errorPacket;
public abstract void setForExplain();
public SubQueryHandler(long id, NonBlockingSession session) {
super(id, session);
this.lock = new ReentrantLock();
}
@Override
public void rowEofResponse(byte[] eof, boolean isLeft, BackendConnection conn) {
lock.lock();
try {
// callBack after terminated
if (terminate.get()) {
return;
}
HandlerTool.terminateHandlerTree(this);
// locked onTerminate, because terminated may sync with start
tempDoneCallBack.call();
} catch (Exception callback) {
LOGGER.warn("callback exception!", callback);
} finally {
lock.unlock();
}
}
@Override
public void connectionError(Throwable e, BackendConnection conn) {
lock.lock();
try {
String errorMsg = e.getMessage() == null ? e.toString() : e.getMessage();
LOGGER.warn(errorMsg);
genErrorPackage(ErrorCode.ER_UNKNOWN_ERROR, errorMsg);
HandlerTool.terminateHandlerTree(this);
tempDoneCallBack.call();
} catch (Exception callback) {
LOGGER.warn("callback exception!", callback);
} finally {
lock.unlock();
}
}
@Override
protected void onTerminate() {
//do nothing
}
@Override
public void errorResponse(byte[] err, BackendConnection conn) {
lock.lock();
try {
ErrorPacket errPacket = new ErrorPacket();
errPacket.read(err);
String errorMsg = new String(errPacket.getMessage(), StandardCharsets.UTF_8);
LOGGER.warn(errorMsg);
genErrorPackage(errPacket.getErrNo(), errorMsg);
HandlerTool.terminateHandlerTree(this);
tempDoneCallBack.call();
} catch (Exception callback) {
LOGGER.warn("callback exception!", callback);
} finally {
lock.unlock();
}
}
protected void genErrorPackage(int errorNum, String msg) {
if (errorPacket == null) {
errorPacket = new ErrorPacket();
errorPacket.setErrNo(errorNum);
errorPacket.setMessage(msg.getBytes(StandardCharsets.UTF_8));
}
}
public void setTempDoneCallBack(CallBackHandler tempDoneCallBack) {
this.tempDoneCallBack = tempDoneCallBack;
}
public ErrorPacket getErrorPacket() {
return errorPacket;
}
}
@@ -17,9 +17,15 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public abstract class AbstractCommitNodesHandler extends MultiNodeHandler implements CommitNodesHandler {
protected static final Logger LOGGER = LoggerFactory.getLogger(AbstractCommitNodesHandler.class);
protected Lock lockForErrorHandle = new ReentrantLock();
protected Condition sendFinished = lockForErrorHandle.newCondition();
protected volatile boolean sendFinishedFlag = true;
public AbstractCommitNodesHandler(NonBlockingSession session) {
super(session);
@@ -45,13 +51,25 @@ public abstract class AbstractCommitNodesHandler extends MultiNodeHandler implem
}
}
for (RouteResultsetNode rrn : session.getTargetKeys()) {
final BackendConnection conn = session.getTarget(rrn);
conn.setResponseHandler(this);
if (!executeCommit((MySQLConnection) conn, position++)) {
break;
try {
sendFinishedFlag = false;
for (RouteResultsetNode rrn : session.getTargetKeys()) {
final BackendConnection conn = session.getTarget(rrn);
conn.setResponseHandler(this);
if (!executeCommit((MySQLConnection) conn, position++)) {
break;
}
}
} finally {
lockForErrorHandle.lock();
try {
sendFinishedFlag = true;
sendFinished.signalAll();
} finally {
lockForErrorHandle.unlock();
}
}
}
@Override
@@ -87,6 +105,11 @@ public abstract class AbstractCommitNodesHandler extends MultiNodeHandler implem
}
@Override
public void reset(int initCount) {
nodeCount = initCount;
packetId = 0;
}
public void debugCommitDelay() {
@@ -19,6 +19,8 @@ import com.actiontech.dble.net.mysql.OkPacket;
import com.actiontech.dble.server.NonBlockingSession;
import com.actiontech.dble.util.StringUtil;
import static com.actiontech.dble.config.ErrorCode.ER_ERROR_DURING_COMMIT;
public class XACommitNodesHandler extends AbstractCommitNodesHandler {
private static final int COMMIT_TIMES = 5;
private int tryCommitTimes = 0;
@@ -39,6 +41,7 @@ public class XACommitNodesHandler extends AbstractCommitNodesHandler {
@Override
protected boolean executeCommit(MySQLConnection mysqlCon, int position) {
TxState state = session.getXaState();
if (state == TxState.TX_STARTED_STATE) {
if (participantLogEntry == null) {
participantLogEntry = new ParticipantLogEntry[nodeCount];
@@ -77,6 +80,20 @@ public class XACommitNodesHandler extends AbstractCommitNodesHandler {
XAStateLog.saveXARecoveryLog(session.getSessionXaID(), TxState.TX_COMMIT_FAILED_STATE);
}
commitPhase(mysqlCon);
} else if (state == TxState.TX_PREPARE_UNCONNECT_STATE) {
final String errorMsg = this.error;
if (decrementCountBy(1)) {
DbleServer.getInstance().getBusinessExecutor().execute(new Runnable() {
@Override
public void run() {
ErrorPacket error = new ErrorPacket();
error.setErrNo(ER_ERROR_DURING_COMMIT);
error.setMessage(errorMsg == null ? "unknow error".getBytes() : errorMsg.getBytes());
XAAutoRollbackNodesHandler nextHandler = new XAAutoRollbackNodesHandler(session, error.toBytes(), null, null);
nextHandler.rollback();
}
});
}
}
return true;
}
@@ -114,6 +131,7 @@ public class XACommitNodesHandler extends AbstractCommitNodesHandler {
@Override
public void okResponse(byte[] ok, BackendConnection conn) {
this.waitUntilSendFinish();
MySQLConnection mysqlCon = (MySQLConnection) conn;
TxState state = mysqlCon.getXaStatus();
if (state == TxState.TX_STARTED_STATE) {
@@ -151,6 +169,7 @@ public class XACommitNodesHandler extends AbstractCommitNodesHandler {
@Override
public void errorResponse(byte[] err, BackendConnection conn) {
this.waitUntilSendFinish();
ErrorPacket errPacket = new ErrorPacket();
errPacket.read(err);
String errMsg = new String(errPacket.getMessage());
@@ -193,6 +212,7 @@ public class XACommitNodesHandler extends AbstractCommitNodesHandler {
@Override
public void connectionError(Throwable e, BackendConnection conn) {
this.waitUntilSendFinish();
LOGGER.warn("backend connect", e);
String errMsg = new String(StringUtil.encode(e.getMessage(), session.getSource().getCharset().getResults()));
this.setFail(errMsg);
@@ -230,7 +250,19 @@ public class XACommitNodesHandler extends AbstractCommitNodesHandler {
}
@Override
public void connectionClose(BackendConnection conn, String reason) {
public void connectionClose(final BackendConnection conn, final String reason) {
final XACommitNodesHandler thisHandler = this;
DbleServer.getInstance().getBusinessExecutor().execute(new Runnable() {
@Override
public void run() {
thisHandler.connectionCloseLocal(conn, reason);
}
});
}
public void connectionCloseLocal(BackendConnection conn, String reason) {
this.waitUntilSendFinish();
this.setFail(reason);
sendData = makeErrorPacket(reason);
if (conn instanceof MySQLConnection) {
@@ -265,8 +297,9 @@ public class XACommitNodesHandler extends AbstractCommitNodesHandler {
}
}
protected void nextParse() {
if (this.isFail()) {
if (this.isFail() && session.getXaState() != TxState.TX_PREPARE_UNCONNECT_STATE) {
session.getSource().setTxInterrupt(error);
session.getSource().write(sendData);
LOGGER.warn("nextParse failed:" + error);
@@ -347,4 +380,18 @@ public class XACommitNodesHandler extends AbstractCommitNodesHandler {
}
}
public void waitUntilSendFinish() {
try {
this.lockForErrorHandle.lock();
if (!this.sendFinishedFlag) {
this.sendFinished.await();
}
} catch (Exception e) {
LOGGER.info("back Response is closed by thread interrupted");
} finally {
lockForErrorHandle.unlock();
}
return;
}
}
@@ -341,7 +341,8 @@ public class XARollbackNodesHandler extends AbstractRollbackNodesHandler {
session.getSource().write(send);
//partitionly commited,must commit again
} else if (session.getXaState() == TxState.TX_ROLLBACK_FAILED_STATE || session.getXaState() == TxState.TX_PREPARED_STATE) {
} else if (session.getXaState() == TxState.TX_ROLLBACK_FAILED_STATE || session.getXaState() == TxState.TX_PREPARED_STATE ||
session.getXaState() == TxState.TX_PREPARE_UNCONNECT_STATE) {
MySQLConnection errConn = session.releaseExcept(session.getXaState());
if (errConn != null) {
XAStateLog.saveXARecoveryLog(session.getSessionXaID(), session.getXaState());
@@ -20,6 +20,7 @@ import com.actiontech.dble.plan.common.item.ItemInt;
import com.actiontech.dble.plan.common.item.ItemRef;
import com.actiontech.dble.plan.common.item.function.ItemFunc;
import com.actiontech.dble.plan.common.item.function.sumfunc.ItemSum;
import com.actiontech.dble.plan.common.item.subquery.ItemScalarSubQuery;
import com.actiontech.dble.util.StringUtil;
import com.alibaba.druid.sql.ast.SQLOrderingSpecification;
import org.apache.log4j.Logger;
@@ -82,6 +83,9 @@ public final class HandlerTool {
Item ret;
if (sel.basicConstItem())
return sel;
if (sel instanceof ItemScalarSubQuery) {
return ((ItemScalarSubQuery) sel).getValue();
}
Item.ItemType i = sel.type();
if (i == Item.ItemType.FUNC_ITEM || i == Item.ItemType.COND_ITEM) {
ItemFunc func = (ItemFunc) sel;
@@ -84,7 +84,6 @@ public class FileSystemRepository implements Repository {
private synchronized void writeToFile(ByteBuffer buff, boolean force)
throws IOException {
rwChannel.write(buff);
rwChannel.force(force);
}
@Override
@@ -100,7 +99,7 @@ public class FileSystemRepository implements Repository {
} catch (FileNotFoundException firstStart) {
// the file could not be opened for reading;
// merely return the default empty vector
LOGGER.warn("FileSystemRepository.getAllCoordinatorLogEntries error", firstStart);
LOGGER.debug("Only For debug FileSystemRepository.getAllCoordinatorLogEntries error", firstStart);
}
if (fis != null) {
return readFromInputStream(fis);
@@ -6,12 +6,13 @@
package com.actiontech.dble.config;
import com.actiontech.dble.DbleServer;
import com.actiontech.dble.server.variables.SystemVariables;
import com.actiontech.dble.backend.datasource.PhysicalDBNode;
import com.actiontech.dble.backend.datasource.PhysicalDBPool;
import com.actiontech.dble.backend.datasource.PhysicalDatasource;
import com.actiontech.dble.backend.mysql.nio.MySQLDataSource;
import com.actiontech.dble.config.loader.SchemaLoader;
import com.actiontech.dble.config.loader.xml.XMLConfigLoader;
import com.actiontech.dble.config.loader.xml.XMLServerLoader;
import com.actiontech.dble.config.loader.xml.XMLSchemaLoader;
import com.actiontech.dble.config.model.*;
import com.actiontech.dble.config.util.ConfigException;
@@ -44,11 +45,12 @@ public class ConfigInitializer {
public ConfigInitializer(boolean loadDataHost) {
//load server.xml
XMLConfigLoader configLoader = new XMLConfigLoader();
XMLServerLoader serverloader = new XMLServerLoader();
//load rule.xml and schema.xml
SchemaLoader schemaLoader = new XMLSchemaLoader(configLoader.getSystemConfig().isLowerCaseTableNames());
this.system = configLoader.getSystemConfig();
this.users = configLoader.getUserConfigs();
SchemaLoader schemaLoader = new XMLSchemaLoader(SystemVariables.getSysVars().isLowerCaseTableNames());
this.system = serverloader.getSystem();
this.users = serverloader.getUsers();
this.schemas = schemaLoader.getSchemas();
this.erRelations = schemaLoader.getErRelations();
// need reload DataHost and DataNode?
@@ -62,11 +64,34 @@ public class ConfigInitializer {
this.dataHostWithoutWH = DbleServer.getInstance().getConfig().isDataHostWithoutWR();
}
this.firewall = configLoader.getFirewallConfig();
this.firewall = serverloader.getFirewall();
loadSequence();
/**
* check config
*/
this.selfChecking0();
}
public ConfigInitializer() {
XMLServerLoader serverloader = new XMLServerLoader();
this.system = serverloader.getSystem();
this.users = serverloader.getUsers();
this.firewall = serverloader.getFirewall();
SchemaLoader schemaLoader = new XMLSchemaLoader(SystemVariables.getSysVars().isLowerCaseTableNames());
this.schemas = schemaLoader.getSchemas();
this.erRelations = schemaLoader.getErRelations();
this.dataHosts = DbleServer.getInstance().getConfig().getDataHosts();
this.dataNodes = initDataNodes(schemaLoader);
loadSequence();
}
private void loadSequence() {
//load global sequence
if (system.getSequnceHandlerType() == SystemConfig.SEQUENCE_HANDLER_MYSQL) {
IncrSequenceMySQLHandler.getInstance().load(system.isLowerCaseTableNames());
IncrSequenceMySQLHandler.getInstance().load(SystemVariables.getSysVars().isLowerCaseTableNames());
}
if (system.getSequnceHandlerType() == SystemConfig.SEQUENCE_HANDLER_LOCAL_TIME) {
@@ -78,13 +103,8 @@ public class ConfigInitializer {
}
if (system.getSequnceHandlerType() == SystemConfig.SEQUENCE_HANDLER_ZK_GLOBAL_INCREMENT) {
IncrSequenceZKHandler.getInstance().load(system.isLowerCaseTableNames());
IncrSequenceZKHandler.getInstance().load(SystemVariables.getSysVars().isLowerCaseTableNames());
}
/**
* check config
*/
this.selfChecking0();
}
private void selfChecking0() throws ConfigException {
@@ -70,9 +70,7 @@ public class ServerConfig {
this.dataNodes = confInit.getDataNodes();
this.erRelations = confInit.getErRelations();
this.dataHostWithoutWR = confInit.isDataHostWithoutWH();
for (PhysicalDBPool dbPool : dataHosts.values()) {
dbPool.setSchemas(getDataNodeSchemasOfDataHost(dbPool.getHostName()));
}
setSchemasForPool();
this.firewall = confInit.getFirewall();
@@ -83,6 +81,23 @@ public class ServerConfig {
this.lock = new ReentrantLock();
}
private void setSchemasForPool() {
for (PhysicalDBPool dbPool : dataHosts.values()) {
dbPool.setSchemas(getDataNodeSchemasOfDataHost(dbPool.getHostName()));
}
}
public void reviseSchemas() {
ConfigInitializer confInit = new ConfigInitializer();
this.system = confInit.getSystem();
this.users = confInit.getUsers();
this.firewall = confInit.getFirewall();
this.schemas = confInit.getSchemas();
this.dataNodes = confInit.getDataNodes();
this.erRelations = confInit.getErRelations();
setSchemasForPool();
}
public SystemConfig getSystem() {
return system;
}
@@ -12,7 +12,7 @@ public abstract class Versions {
public static final byte PROTOCOL_VERSION = 10;
private static byte[] serverVersion = "5.6.29-dble-2.17.08.0-20170922131413".getBytes();
private static byte[] serverVersion = "5.6.29-dble-2.17.09.0-dev-20171017161450".getBytes();
public static final byte[] VERSION_COMMENT = "dble Server (ActionTech)".getBytes();
public static final String ANNOTATION_NAME = "dble:";
public static final String ROOT_PREFIX = "dble";
@@ -0,0 +1,73 @@
/*
* Copyright (C) 2016-2017 ActionTech.
* based on code by MyCATCopyrightHolder Copyright (c) 2013, OpenCloudDB/MyCAT.
* License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher.
*/
package com.actiontech.dble.config.loader.xml;
import com.actiontech.dble.config.model.FirewallConfig;
import com.actiontech.dble.config.model.UserConfig;
import com.actiontech.dble.config.util.ParameterMapping;
import com.actiontech.dble.config.util.ConfigException;
import com.actiontech.dble.config.util.ConfigUtil;
import com.alibaba.druid.wall.WallConfig;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import java.util.*;
import java.lang.reflect.InvocationTargetException;
public class FirewallConfigLoader implements Loader<FirewallConfig, XMLServerLoader> {
public void load(Element root, XMLServerLoader xsl) throws IllegalAccessException, InvocationTargetException {
FirewallConfig firewall = xsl.getFirewall();
Map<String, UserConfig> users = xsl.getUsers();
NodeList list = root.getElementsByTagName("host");
Map<String, List<UserConfig>> whitehost = new HashMap<>();
for (int i = 0, n = list.getLength(); i < n; i++) {
Node node = list.item(i);
if (node instanceof Element) {
Element e = (Element) node;
String host = e.getAttribute("host").trim();
String userStr = e.getAttribute("user").trim();
if (firewall.existsHost(host)) {
throw new ConfigException("host duplicated : " + host);
}
String[] arrayUsers = userStr.split(",");
List<UserConfig> userConfigs = new ArrayList<>();
for (String user : arrayUsers) {
UserConfig uc = users.get(user);
if (null == uc) {
throw new ConfigException("[user: " + user + "] doesn't exist in [host: " + host + "]");
}
if (!uc.isManager() && (uc.getSchemas() == null || uc.getSchemas().size() == 0)) {
throw new ConfigException("[host: " + host + "] contains one root privileges user: " + user);
}
userConfigs.add(uc);
}
whitehost.put(host, userConfigs);
}
}
firewall.setWhitehost(whitehost);
WallConfig wallConfig = new WallConfig();
NodeList blacklist = root.getElementsByTagName("blacklist");
for (int i = 0, n = blacklist.getLength(); i < n; i++) {
Node node = blacklist.item(i);
if (node instanceof Element) {
Element e = (Element) node;
String check = e.getAttribute("check");
if (null != check) {
firewall.setBlackListCheck(Boolean.parseBoolean(check));
}
Map<String, Object> props = ConfigUtil.loadElements((Element) node);
ParameterMapping.mapping(wallConfig, props);
}
}
firewall.setWallConfig(wallConfig);
firewall.init();
}
}
@@ -0,0 +1,13 @@
/*
* Copyright (C) 2016-2017 ActionTech.
* based on code by MyCATCopyrightHolder Copyright (c) 2013, OpenCloudDB/MyCAT.
* License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher.
*/
package com.actiontech.dble.config.loader.xml;
import java.lang.reflect.InvocationTargetException;
import org.w3c.dom.Element;
public interface Loader<P, T> {
void load(Element root, T t) throws IllegalAccessException, InvocationTargetException;
}
@@ -0,0 +1,51 @@
/*
* Copyright (C) 2016-2017 ActionTech.
* based on code by MyCATCopyrightHolder Copyright (c) 2013, OpenCloudDB/MyCAT.
* License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher.
*/
package com.actiontech.dble.config.loader.xml;
import com.actiontech.dble.config.Versions;
import com.actiontech.dble.config.model.SystemConfig;
import com.actiontech.dble.config.util.ConfigException;
import com.actiontech.dble.config.util.ConfigUtil;
import com.actiontech.dble.config.util.ParameterMapping;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import java.util.*;
import java.lang.reflect.InvocationTargetException;
public class SystemConfigLoader implements Loader<SystemConfig, XMLServerLoader> {
public void load(Element root, XMLServerLoader xsl) throws IllegalAccessException, InvocationTargetException {
SystemConfig system = xsl.getSystem();
NodeList list = root.getElementsByTagName("system");
for (int i = 0, n = list.getLength(); i < n; i++) {
Node node = list.item(i);
if (node instanceof Element) {
Map<String, Object> props = ConfigUtil.loadElements((Element) node);
ParameterMapping.mapping(system, props);
}
}
if (system.getFakeMySQLVersion() != null) {
boolean validVersion = false;
String majorMySQLVersion = system.getFakeMySQLVersion();
int pos = majorMySQLVersion.indexOf(".") + 1;
majorMySQLVersion = majorMySQLVersion.substring(0, majorMySQLVersion.indexOf(".", pos));
for (String ver : SystemConfig.MYSQL_VERSIONS) {
// version is x.y.z ,just compare the x.y
if (majorMySQLVersion.equals(ver)) {
validVersion = true;
}
}
if (validVersion) {
Versions.setServerVersion(system.getFakeMySQLVersion());
} else {
throw new ConfigException("The specified MySQL Version (" + system.getFakeMySQLVersion() + ") is not valid.");
}
}
}
}
@@ -0,0 +1,133 @@
/*
* Copyright (C) 2016-2017 ActionTech.
* based on code by MyCATCopyrightHolder Copyright (c) 2013, OpenCloudDB/MyCAT.
* License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher.
*/
package com.actiontech.dble.config.loader.xml;
import com.actiontech.dble.config.model.UserConfig;
import com.actiontech.dble.config.model.SystemConfig;
import com.actiontech.dble.config.model.UserPrivilegesConfig;
import com.actiontech.dble.config.util.ConfigException;
import com.actiontech.dble.config.util.ConfigUtil;
import com.actiontech.dble.util.DecryptUtil;
import com.actiontech.dble.util.SplitUtil;
import com.actiontech.dble.server.variables.SystemVariables;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import java.util.*;
import java.lang.reflect.InvocationTargetException;
public class UserConfigLoader implements Loader<UserConfig, XMLServerLoader> {
public void load(Element root, XMLServerLoader xsl) throws IllegalAccessException, InvocationTargetException {
SystemConfig system = xsl.getSystem();
Map<String, UserConfig> users = xsl.getUsers();
NodeList list = root.getElementsByTagName("user");
for (int i = 0, n = list.getLength(); i < n; i++) {
Node node = list.item(i);
if (node instanceof Element) {
Element e = (Element) node;
String name = e.getAttribute("name");
UserConfig user = new UserConfig();
Map<String, Object> props = ConfigUtil.loadElements(e);
String password = (String) props.get("password");
String usingDecrypt = (String) props.get("usingDecrypt");
String passwordDecrypt = DecryptUtil.decrypt(usingDecrypt, name, password);
user.setName(name);
user.setPassword(passwordDecrypt);
user.setEncryptPassword(password);
String benchmark = (String) props.get("benchmark");
if (null != benchmark) {
user.setBenchmark(Integer.parseInt(benchmark));
}
String readOnly = (String) props.get("readOnly");
if (null != readOnly) {
user.setReadOnly(Boolean.parseBoolean(readOnly));
}
String manager = (String) props.get("manager");
if (null != manager) {
user.setManager(Boolean.parseBoolean(manager));
}
String schemas = (String) props.get("schemas");
if (user.isManager() && schemas != null) {
throw new ConfigException("manager user can't set any schema!");
} else if (!user.isManager()) {
if (schemas != null) {
if (SystemVariables.getSysVars().isLowerCaseTableNames()) {
schemas = schemas.toLowerCase();
}
String[] strArray = SplitUtil.split(schemas, ',', true);
user.setSchemas(new HashSet<>(Arrays.asList(strArray)));
}
// load DML
loadPrivileges(user, system, e);
}
if (users.containsKey(name)) {
throw new ConfigException("user " + name + " duplicated!");
}
users.put(name, user);
}
}
}
private void loadPrivileges(UserConfig userConfig, SystemConfig system, Element node) {
UserPrivilegesConfig privilegesConfig = new UserPrivilegesConfig();
NodeList privilegesNodes = node.getElementsByTagName("privileges");
int privilegesNodesLength = privilegesNodes.getLength();
for (int i = 0; i < privilegesNodesLength; i++) {
Element privilegesNode = (Element) privilegesNodes.item(i);
String check = privilegesNode.getAttribute("check");
if (null != check) {
privilegesConfig.setCheck(Boolean.valueOf(check));
}
NodeList schemaNodes = privilegesNode.getElementsByTagName("schema");
int schemaNodeLength = schemaNodes.getLength();
for (int j = 0; j < schemaNodeLength; j++) {
Element schemaNode = (Element) schemaNodes.item(j);
String name1 = schemaNode.getAttribute("name");
if (SystemVariables.getSysVars().isLowerCaseTableNames()) {
name1 = name1.toLowerCase();
}
String dml1 = schemaNode.getAttribute("dml");
int[] dml1Array = new int[dml1.length()];
for (int offset1 = 0; offset1 < dml1.length(); offset1++) {
dml1Array[offset1] = Character.getNumericValue(dml1.charAt(offset1));
}
UserPrivilegesConfig.SchemaPrivilege schemaPrivilege = new UserPrivilegesConfig.SchemaPrivilege();
schemaPrivilege.setDml(dml1Array);
NodeList tableNodes = schemaNode.getElementsByTagName("table");
int tableNodeLength = tableNodes.getLength();
for (int z = 0; z < tableNodeLength; z++) {
UserPrivilegesConfig.TablePrivilege tablePrivilege = new UserPrivilegesConfig.TablePrivilege();
Element tableNode = (Element) tableNodes.item(z);
String name2 = tableNode.getAttribute("name");
if (SystemVariables.getSysVars().isLowerCaseTableNames()) {
name2 = name2.toLowerCase();
}
String dml2 = tableNode.getAttribute("dml");
int[] dml2Array = new int[dml2.length()];
for (int offset2 = 0; offset2 < dml2.length(); offset2++) {
dml2Array[offset2] = Character.getNumericValue(dml2.charAt(offset2));
}
tablePrivilege.setDml(dml2Array);
schemaPrivilege.addTablePrivilege(name2, tablePrivilege);
}
privilegesConfig.addSchemaPrivilege(name1, schemaPrivilege);
}
}
userConfig.setPrivilegesConfig(privilegesConfig);
}
}
@@ -5,25 +5,16 @@
*/
package com.actiontech.dble.config.loader.xml;
import com.actiontech.dble.config.Versions;
import com.actiontech.dble.config.model.FirewallConfig;
import com.actiontech.dble.config.model.SystemConfig;
import com.actiontech.dble.config.model.UserConfig;
import com.actiontech.dble.config.model.UserPrivilegesConfig;
import com.actiontech.dble.config.util.ConfigException;
import com.actiontech.dble.config.util.ConfigUtil;
import com.actiontech.dble.config.util.ParameterMapping;
import com.actiontech.dble.util.DecryptUtil;
import com.actiontech.dble.util.ResourceUtil;
import com.actiontech.dble.util.SplitUtil;
import com.alibaba.druid.wall.WallConfig;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
/**
@@ -39,7 +30,10 @@ public class XMLServerLoader {
this.system = new SystemConfig();
this.users = new HashMap<>();
this.firewall = new FirewallConfig();
this.load();
this.load(new SystemConfigLoader());
this.load(new UserConfigLoader());
this.load(new FirewallConfigLoader());
}
public SystemConfig getSystem() {
@@ -48,15 +42,15 @@ public class XMLServerLoader {
@SuppressWarnings("unchecked")
public Map<String, UserConfig> getUsers() {
return (Map<String, UserConfig>) (users.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(users));
//return (Map<String, UserConfig>) (users.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(users));
return users;
}
public FirewallConfig getFirewall() {
return firewall;
}
private void load() {
public void load(Loader loader) {
//read server.xml
InputStream dtd = null;
InputStream xml = null;
@@ -64,10 +58,7 @@ public class XMLServerLoader {
dtd = ResourceUtil.getResourceAsStream("/server.dtd");
xml = ResourceUtil.getResourceAsStream("/server.xml");
Element root = ConfigUtil.getDocument(dtd, xml).getDocumentElement();
loadSystem(root);
loadUsers(root);
loadFirewall(root);
loader.load(root, this);
} catch (ConfigException e) {
throw e;
} catch (Exception e) {
@@ -89,200 +80,4 @@ public class XMLServerLoader {
}
}
}
private void loadFirewall(Element root) throws IllegalAccessException, InvocationTargetException {
NodeList list = root.getElementsByTagName("host");
Map<String, List<UserConfig>> whitehost = new HashMap<>();
for (int i = 0, n = list.getLength(); i < n; i++) {
Node node = list.item(i);
if (node instanceof Element) {
Element e = (Element) node;
String host = e.getAttribute("host").trim();
String userStr = e.getAttribute("user").trim();
if (this.firewall.existsHost(host)) {
throw new ConfigException("host duplicated : " + host);
}
String[] arrayUsers = userStr.split(",");
List<UserConfig> userConfigs = new ArrayList<>();
for (String user : arrayUsers) {
UserConfig uc = this.users.get(user);
if (null == uc) {
throw new ConfigException("[user: " + user + "] doesn't exist in [host: " + host + "]");
}
if (!uc.isManager() && (uc.getSchemas() == null || uc.getSchemas().size() == 0)) {
throw new ConfigException("[host: " + host + "] contains one root privileges user: " + user);
}
userConfigs.add(uc);
}
whitehost.put(host, userConfigs);
}
}
firewall.setWhitehost(whitehost);
WallConfig wallConfig = new WallConfig();
NodeList blacklist = root.getElementsByTagName("blacklist");
for (int i = 0, n = blacklist.getLength(); i < n; i++) {
Node node = blacklist.item(i);
if (node instanceof Element) {
Element e = (Element) node;
String check = e.getAttribute("check");
if (null != check) {
firewall.setBlackListCheck(Boolean.parseBoolean(check));
}
Map<String, Object> props = ConfigUtil.loadElements((Element) node);
ParameterMapping.mapping(wallConfig, props);
}
}
firewall.setWallConfig(wallConfig);
firewall.init();
}
private void loadUsers(Element root) {
NodeList list = root.getElementsByTagName("user");
for (int i = 0, n = list.getLength(); i < n; i++) {
Node node = list.item(i);
if (node instanceof Element) {
Element e = (Element) node;
String name = e.getAttribute("name");
UserConfig user = new UserConfig();
Map<String, Object> props = ConfigUtil.loadElements(e);
String password = (String) props.get("password");
String usingDecrypt = (String) props.get("usingDecrypt");
String passwordDecrypt = DecryptUtil.decrypt(usingDecrypt, name, password);
user.setName(name);
user.setPassword(passwordDecrypt);
user.setEncryptPassword(password);
String benchmark = (String) props.get("benchmark");
if (null != benchmark) {
user.setBenchmark(Integer.parseInt(benchmark));
}
String readOnly = (String) props.get("readOnly");
if (null != readOnly) {
user.setReadOnly(Boolean.parseBoolean(readOnly));
}
String manager = (String) props.get("manager");
if (null != manager) {
user.setManager(Boolean.parseBoolean(manager));
}
String schemas = (String) props.get("schemas");
if (user.isManager() && schemas != null) {
throw new ConfigException("manager user can't set any schema!");
} else if (!user.isManager()) {
if (schemas != null) {
if (system.isLowerCaseTableNames()) {
schemas = schemas.toLowerCase();
}
String[] strArray = SplitUtil.split(schemas, ',', true);
user.setSchemas(new HashSet<>(Arrays.asList(strArray)));
}
// load DML
loadPrivileges(user, e);
}
if (users.containsKey(name)) {
throw new ConfigException("user " + name + " duplicated!");
}
users.put(name, user);
}
}
}
private void loadPrivileges(UserConfig userConfig, Element node) {
UserPrivilegesConfig privilegesConfig = new UserPrivilegesConfig();
NodeList privilegesNodes = node.getElementsByTagName("privileges");
int privilegesNodesLength = privilegesNodes.getLength();
for (int i = 0; i < privilegesNodesLength; i++) {
Element privilegesNode = (Element) privilegesNodes.item(i);
String check = privilegesNode.getAttribute("check");
if (null != check) {
privilegesConfig.setCheck(Boolean.valueOf(check));
}
NodeList schemaNodes = privilegesNode.getElementsByTagName("schema");
int schemaNodeLength = schemaNodes.getLength();
for (int j = 0; j < schemaNodeLength; j++) {
Element schemaNode = (Element) schemaNodes.item(j);
String name1 = schemaNode.getAttribute("name");
if (system.isLowerCaseTableNames()) {
name1 = name1.toLowerCase();
}
String dml1 = schemaNode.getAttribute("dml");
int[] dml1Array = new int[dml1.length()];
for (int offset1 = 0; offset1 < dml1.length(); offset1++) {
dml1Array[offset1] = Character.getNumericValue(dml1.charAt(offset1));
}
UserPrivilegesConfig.SchemaPrivilege schemaPrivilege = new UserPrivilegesConfig.SchemaPrivilege();
schemaPrivilege.setDml(dml1Array);
NodeList tableNodes = schemaNode.getElementsByTagName("table");
int tableNodeLength = tableNodes.getLength();
for (int z = 0; z < tableNodeLength; z++) {
UserPrivilegesConfig.TablePrivilege tablePrivilege = new UserPrivilegesConfig.TablePrivilege();
Element tableNode = (Element) tableNodes.item(z);
String name2 = tableNode.getAttribute("name");
if (system.isLowerCaseTableNames()) {
name2 = name2.toLowerCase();
}
String dml2 = tableNode.getAttribute("dml");
int[] dml2Array = new int[dml2.length()];
for (int offset2 = 0; offset2 < dml2.length(); offset2++) {
dml2Array[offset2] = Character.getNumericValue(dml2.charAt(offset2));
}
tablePrivilege.setDml(dml2Array);
schemaPrivilege.addTablePrivilege(name2, tablePrivilege);
}
privilegesConfig.addSchemaPrivilege(name1, schemaPrivilege);
}
}
userConfig.setPrivilegesConfig(privilegesConfig);
}
private void loadSystem(Element root) throws IllegalAccessException, InvocationTargetException {
NodeList list = root.getElementsByTagName("system");
for (int i = 0, n = list.getLength(); i < n; i++) {
Node node = list.item(i);
if (node instanceof Element) {
Map<String, Object> props = ConfigUtil.loadElements((Element) node);
ParameterMapping.mapping(system, props);
}
}
if (system.getFakeMySQLVersion() != null) {
boolean validVersion = false;
String majorMySQLVersion = system.getFakeMySQLVersion();
int pos = majorMySQLVersion.indexOf(".") + 1;
majorMySQLVersion = majorMySQLVersion.substring(0, majorMySQLVersion.indexOf(".", pos));
for (String ver : SystemConfig.MYSQL_VERSIONS) {
// version is x.y.z ,just compare the x.y
if (majorMySQLVersion.equals(ver)) {
validVersion = true;
}
}
if (validVersion) {
Versions.setServerVersion(system.getFakeMySQLVersion());
} else {
throw new ConfigException("The specified MySQL Version (" + system.getFakeMySQLVersion() + ") is not valid.");
}
}
}
}
@@ -48,7 +48,6 @@ public final class SystemConfig {
private static final String DEFAULT_CLUSTER_HEARTBEAT_PASS = "_HEARTBEAT_PASS_";
private static final int DEFAULT_SQL_RECORD_COUNT = 10;
private static final boolean DEFAULT_USE_ZK_SWITCH = true;
private static final boolean DEFAULT_LOWER_CASE = true;
private static final String DEFAULT_TRANSACTION_BASE_DIR = "txlogs";
private static final String DEFAULT_TRANSACTION_BASE_NAME = "server-tx";
private static final int DEFAULT_TRANSACTION_ROTATE_SIZE = 16;
@@ -146,8 +145,6 @@ public final class SystemConfig {
private int mappedFileSize;
private boolean useZKSwitch = DEFAULT_USE_ZK_SWITCH;
private boolean lowerCaseTableNames = DEFAULT_LOWER_CASE;
private boolean useJoinStrategy;
public SystemConfig() {
@@ -277,17 +274,6 @@ public final class SystemConfig {
this.useJoinStrategy = useJoinStrategy;
}
public boolean isLowerCaseTableNames() {
return lowerCaseTableNames;
}
@SuppressWarnings("unused")
public void setLowerCaseTableNames(boolean lowerCaseTableNames) {
this.lowerCaseTableNames = lowerCaseTableNames;
}
public String getXaRecoveryLogBaseDir() {
return xaRecoveryLogBaseDir;
}
@@ -6,6 +6,7 @@
package com.actiontech.dble.meta.table;
import com.actiontech.dble.DbleServer;
import com.actiontech.dble.server.variables.SystemVariables;
import com.actiontech.dble.backend.datasource.PhysicalDBNode;
import com.actiontech.dble.config.model.SchemaConfig;
import com.actiontech.dble.sqlengine.MultiRowSQLQueryResultHandler;
@@ -62,7 +63,7 @@ public class ShowTablesHandler {
List<Map<String, String>> rows = result.getResult();
for (Map<String, String> row : rows) {
String table = row.get(mysqlShowTableCol);
if (DbleServer.getInstance().getConfig().getSystem().isLowerCaseTableNames()) {
if (SystemVariables.getSysVars().isLowerCaseTableNames()) {
table = table.toLowerCase();
}
if (!config.getTables().containsKey(table)) {
@@ -7,7 +7,7 @@ package com.actiontech.dble.net;
import com.actiontech.dble.net.mysql.CharsetNames;
import com.actiontech.dble.net.mysql.MySQLPacket;
import com.actiontech.dble.server.SystemVariables;
import com.actiontech.dble.server.variables.SystemVariables;
import com.actiontech.dble.util.CompressUtil;
import com.actiontech.dble.util.TimeUtil;
import com.google.common.base.Strings;
@@ -109,7 +109,7 @@ public abstract class AbstractConnection implements NIOConnection {
public void setCharacterSet(String name) {
charsetName.setClient(name);
charsetName.setResults(name);
charsetName.setCollation(SystemVariables.getDefaultValue("collation_database"));
charsetName.setCollation(SystemVariables.getSysVars().getDefaultValue("collation_database"));
}
public boolean setNames(String name, String collationName) {
@@ -6,6 +6,7 @@
package com.actiontech.dble.net;
import com.actiontech.dble.DbleServer;
import com.actiontech.dble.server.variables.SystemVariables;
import com.actiontech.dble.backend.mysql.CharsetUtil;
import com.actiontech.dble.backend.mysql.MySQLMessage;
import com.actiontech.dble.config.Capabilities;
@@ -16,7 +17,6 @@ import com.actiontech.dble.net.mysql.ErrorPacket;
import com.actiontech.dble.net.mysql.HandshakeV10Packet;
import com.actiontech.dble.net.mysql.MySQLPacket;
import com.actiontech.dble.net.mysql.OkPacket;
import com.actiontech.dble.server.SystemVariables;
import com.actiontech.dble.util.CompressUtil;
import com.actiontech.dble.util.RandomUtil;
import com.actiontech.dble.util.StringUtil;
@@ -162,7 +162,7 @@ public abstract class FrontendConnection extends AbstractConnection {
}
public void setSchema(String schema) {
if (schema != null && DbleServer.getInstance().getConfig().getSystem().isLowerCaseTableNames()) {
if (schema != null && SystemVariables.getSysVars().isLowerCaseTableNames()) {
schema = schema.toLowerCase();
}
this.schema = schema;
@@ -184,7 +184,7 @@ public abstract class FrontendConnection extends AbstractConnection {
String name = CharsetUtil.getCharset(ci);
charsetName.setClient(name);
charsetName.setResults(name);
charsetName.setCollation(SystemVariables.getDefaultValue("collation_database"));
charsetName.setCollation(SystemVariables.getSysVars().getDefaultValue("collation_database"));
return true;
}
@@ -220,7 +220,7 @@ public abstract class FrontendConnection extends AbstractConnection {
writeErrMessage(ErrorCode.ER_UNKNOWN_CHARACTER_SET, "Unknown charset '" + charsetName.getClient() + "'");
return;
}
if (db != null && DbleServer.getInstance().getConfig().getSystem().isLowerCaseTableNames()) {
if (db != null && SystemVariables.getSysVars().isLowerCaseTableNames()) {
db = db.toLowerCase();
}
// check schema
@@ -425,7 +425,7 @@ public abstract class FrontendConnection extends AbstractConnection {
hs.setSeed(rand1);
hs.setServerCapabilities(getServerCapabilities());
//TODO:CHECK
int charsetIndex = CharsetUtil.getCharsetDefaultIndex(SystemVariables.getDefaultValue("character_set_server"));
int charsetIndex = CharsetUtil.getCharsetDefaultIndex(SystemVariables.getSysVars().getDefaultValue("character_set_server"));
hs.setServerCharsetIndex((byte) (charsetIndex & 0xff));
hs.setServerStatus(2);
hs.setRestOfScrambleBuff(rand2);
@@ -60,7 +60,7 @@ public class FrontendAuthenticator implements NIOHandler {
auth.read(data);
//check mysql_native_password
if (!"mysql_native_password".equals(auth.getAuthPlugin())) {
if (auth.getAuthPlugin() != null && !"mysql_native_password".equals(auth.getAuthPlugin())) {
failure(ErrorCode.ER_ACCESS_DENIED_ERROR, "only mysql_native_password auth check is supported");
return;
}
@@ -5,7 +5,7 @@
*/
package com.actiontech.dble.net.mysql;
import com.actiontech.dble.DbleServer;
import com.actiontech.dble.server.variables.SystemVariables;
import com.actiontech.dble.backend.mysql.BufferUtil;
import com.actiontech.dble.backend.mysql.MySQLMessage;
import com.actiontech.dble.backend.mysql.StreamUtil;
@@ -70,7 +70,7 @@ public class AuthPacket extends MySQLPacket {
password = mm.readBytesWithLength();
if (((clientFlags & Capabilities.CLIENT_CONNECT_WITH_DB) != 0) && mm.hasRemaining()) {
database = mm.readStringWithNull();
if (database != null && DbleServer.getInstance().getConfig().getSystem().isLowerCaseTableNames()) {
if (database != null && SystemVariables.getSysVars().isLowerCaseTableNames()) {
database = database.toLowerCase();
}
}
@@ -6,7 +6,7 @@
package com.actiontech.dble.net.mysql;
import com.actiontech.dble.backend.mysql.CharsetUtil;
import com.actiontech.dble.server.SystemVariables;
import com.actiontech.dble.server.variables.SystemVariables;
import org.apache.commons.lang.StringUtils;
public class CharsetNames {
@@ -15,9 +15,9 @@ public class CharsetNames {
private volatile String collation;
public CharsetNames() {
this.client = SystemVariables.getDefaultValue("character_set_client");
this.results = SystemVariables.getDefaultValue("character_set_results");
this.collation = SystemVariables.getDefaultValue("collation_connection");
this.client = SystemVariables.getSysVars().getDefaultValue("character_set_client");
this.results = SystemVariables.getSysVars().getDefaultValue("character_set_results");
this.collation = SystemVariables.getSysVars().getDefaultValue("collation_connection");
}
public void setNames(String name, String collationName) {
@@ -12,7 +12,7 @@ import com.actiontech.dble.plan.common.exception.MySQLOutPutException;
import com.actiontech.dble.plan.common.item.Item;
import com.actiontech.dble.plan.common.item.ItemField;
import com.actiontech.dble.plan.common.item.function.sumfunc.ItemSum;
import com.actiontech.dble.plan.common.item.subquery.ItemSubselect;
import com.actiontech.dble.plan.common.item.subquery.ItemSubQuery;
import com.actiontech.dble.plan.node.JoinNode;
import com.actiontech.dble.plan.node.TableNode;
import com.alibaba.druid.sql.ast.SQLOrderingSpecification;
@@ -39,14 +39,10 @@ public abstract class PlanNode {
}
/**
* subQuery list
* select subQuery list
*/
public List<ItemSubselect> getSubSelects() {
return subSelects;
}
public void setSubSelects(List<ItemSubselect> subSelects) {
this.subSelects = subSelects;
public List<ItemSubQuery> getSubQueries() {
return subQueries;
}
public enum PlanNodeType {
@@ -120,12 +116,13 @@ public abstract class PlanNode {
* is this node is subQuery
*/
protected boolean subQuery;
protected boolean correlatedSubQuery;
protected boolean exsitView = false;
private HashSet<ItemSum> sumFuncs = new HashSet<>();
private List<ItemSubselect> subSelects = new ArrayList<>();
private List<ItemSubQuery> subQueries = new ArrayList<>();
protected List<TableNode> referedTableNodes = new ArrayList<>();
@@ -295,6 +292,7 @@ public abstract class PlanNode {
to.setLimitTo(this.limitTo);
to.setSql(this.getSql());
to.setSubQuery(subQuery);
to.setCorrelatedSubQuery(correlatedSubQuery);
to.setUnGlobalTableCount(unGlobalTableCount);
to.setNoshardNode(noshardNode);
}
@@ -590,6 +588,15 @@ public abstract class PlanNode {
return this;
}
public boolean isCorrelatedSubQuery() {
return correlatedSubQuery;
}
public void setCorrelatedSubQuery(boolean correlatedSubQuery) {
this.correlatedSubQuery = correlatedSubQuery;
}
public PlanNode having(Item having) {
this.havingFilter = having;
return this;
@@ -5,6 +5,8 @@
package com.actiontech.dble.plan.common.exception;
import com.actiontech.dble.util.StringUtil;
/**
* MySQLOutPutException
*
@@ -23,7 +25,11 @@ public class MySQLOutPutException extends RuntimeException {
public MySQLOutPutException(int errorCode, String sqlState, String msg) {
super(msg);
this.errorCode = errorCode;
this.sqlState = sqlState;
if (StringUtil.isEmpty(sqlState)) {
this.sqlState = "HY000";
} else {
this.sqlState = sqlState;
}
}
public MySQLOutPutException(int errorCode, String sqlState, String msg, Throwable cause) {
@@ -90,6 +90,14 @@ public abstract class Item {
this.withSubQuery = withSubQuery;
}
public boolean isCorrelatedSubQuery() {
return correlatedSubQuery;
}
public void setCorrelatedSubQuery(boolean correlatedSubQuery) {
this.correlatedSubQuery = correlatedSubQuery;
}
public boolean isWithUnValAble() {
return withUnValAble;
}
@@ -141,6 +149,7 @@ public abstract class Item {
protected boolean withSumFunc;
protected boolean withIsNull;
protected boolean withSubQuery;
protected boolean correlatedSubQuery;
protected boolean withUnValAble;
protected boolean fixed;
protected ItemResult cmpContext;
@@ -325,6 +334,50 @@ public abstract class Item {
return result;
}
public Item getResultItem() {
FieldTypes fType;
FieldTypes i = fType = fieldType();
if (i == FieldTypes.MYSQL_TYPE_TINY || i == FieldTypes.MYSQL_TYPE_SHORT || i == FieldTypes.MYSQL_TYPE_YEAR || i == FieldTypes.MYSQL_TYPE_INT24 || i == FieldTypes.MYSQL_TYPE_LONG || i == FieldTypes.MYSQL_TYPE_LONGLONG) {
BigInteger bi = valInt();
if (!nullValue) {
return new ItemInt(bi.longValue());
}
} else if (i == FieldTypes.MYSQL_TYPE_FLOAT || i == FieldTypes.MYSQL_TYPE_DOUBLE) {
BigDecimal bd = valReal();
if (!nullValue) {
return new ItemFloat(bd);
}
} else if (i == FieldTypes.MYSQL_TYPE_DATETIME || i == FieldTypes.MYSQL_TYPE_DATE || i == FieldTypes.MYSQL_TYPE_TIMESTAMP) {
MySQLTime tm = new MySQLTime();
getDate(tm, MyTime.TIME_FUZZY_DATE);
if (!nullValue) {
if (fType == FieldTypes.MYSQL_TYPE_DATE) {
return new ItemString(MyTime.myDateToStr(tm));
} else {
return new ItemString(MyTime.myDatetimeToStr(tm, decimals));
}
}
} else if (i == FieldTypes.MYSQL_TYPE_TIME) {
MySQLTime tm = new MySQLTime();
getTime(tm);
if (!nullValue)
return new ItemString(MyTime.myTimeToStrL(tm, decimals));
} else {
String res;
if ((res = valStr()) != null) {
return new ItemString(res);
} else {
assert (nullValue);
BigInteger bi = valInt();
if (!nullValue) {
return new ItemInt(bi.longValue());
}
}
}
return null;
}
public boolean valBool() {
ItemResult i = resultType();
if (i == ItemResult.INT_RESULT) {
@@ -940,6 +993,7 @@ public abstract class Item {
clone.withSumFunc = withSumFunc;
clone.withIsNull = withIsNull;
clone.withSubQuery = withSubQuery;
clone.correlatedSubQuery = correlatedSubQuery;
clone.withUnValAble = withUnValAble;
clone.pushDownName = pushDownName;
clone.getReferTables().addAll(getReferTables());
@@ -0,0 +1,66 @@
/*
* Copyright (C) 2016-2017 ActionTech.
* License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher.
*/
/*
* ALL/ANY/SOME sub Query
*/
package com.actiontech.dble.plan.common.item.subquery;
import com.actiontech.dble.config.ErrorCode;
import com.actiontech.dble.plan.common.exception.MySQLOutPutException;
import com.actiontech.dble.plan.common.field.Field;
import com.actiontech.dble.plan.common.item.Item;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.expr.SQLAllExpr;
import com.alibaba.druid.sql.ast.expr.SQLAnyExpr;
import com.alibaba.druid.sql.ast.expr.SQLBinaryOperator;
import com.alibaba.druid.sql.ast.statement.SQLSelect;
import com.alibaba.druid.sql.ast.statement.SQLSelectQuery;
import java.util.List;
public class ItemAllAnySubQuery extends ItemMultiRowSubQuery {
private boolean isAll;
private SQLBinaryOperator operator;
public ItemAllAnySubQuery(String currentDb, SQLBinaryOperator operator, SQLSelectQuery query, boolean isAll) {
super(currentDb, query);
this.isAll = isAll;
this.operator = operator;
if (this.planNode.getColumnsSelected().size() > 1) {
throw new MySQLOutPutException(ErrorCode.ER_OPERAND_COLUMNS, "", "Operand should contain 1 column(s)");
}
this.select = this.planNode.getColumnsSelected().get(0);
}
@Override
public SubSelectType subType() {
return isAll ? SubSelectType.ALL_SUBS : SubSelectType.ANY_SUBS;
}
@Override
public SQLExpr toExpression() {
SQLSelect sqlSelect = new SQLSelect(query);
if (isAll) {
return new SQLAllExpr(sqlSelect);
} else {
return new SQLAnyExpr(sqlSelect);
}
}
@Override
protected Item cloneStruct(boolean forCalculate, List<Item> calArgs, boolean isPushDown, List<Field> fields) {
return new ItemAllAnySubQuery(this.currentDb, this.operator, this.query, this.isAll);
}
public boolean isAll() {
return isAll;
}
public SQLBinaryOperator getOperator() {
return operator;
}
}
@@ -1,95 +0,0 @@
/*
* Copyright (C) 2016-2017 ActionTech.
* License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher.
*/
/**
* ALL/ANY/SOME subselect
*/
package com.actiontech.dble.plan.common.item.subquery;
import com.actiontech.dble.config.ErrorCode;
import com.actiontech.dble.plan.common.exception.MySQLOutPutException;
import com.actiontech.dble.plan.common.field.Field;
import com.actiontech.dble.plan.common.item.Item;
import com.actiontech.dble.plan.common.time.MySQLTime;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.statement.SQLSelectQuery;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.List;
public class ItemAllanySubselect extends ItemSubselect {
private boolean isAll;
/**
* @param currentDb
* @param query
*/
public ItemAllanySubselect(String currentDb, Item left, SQLSelectQuery query, boolean all) {
super(currentDb, query);
Item leftOprand = left;
this.isAll = all;
throw new MySQLOutPutException(ErrorCode.ER_OPTIMIZER, "", "not support!");
}
@Override
public SubSelectType substype() {
return isAll ? SubSelectType.ALL_SUBS : SubSelectType.ANY_SUBS;
}
@Override
public void fixLengthAndDec() {
}
@Override
public BigDecimal valReal() {
// TODO Auto-generated method stub
return null;
}
@Override
public BigInteger valInt() {
// TODO Auto-generated method stub
return null;
}
@Override
public String valStr() {
// TODO Auto-generated method stub
return null;
}
@Override
public BigDecimal valDecimal() {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean getDate(MySQLTime ltime, long fuzzydate) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean getTime(MySQLTime ltime) {
// TODO Auto-generated method stub
return false;
}
@Override
public SQLExpr toExpression() {
// TODO Auto-generated method stub
return null;
}
@Override
protected Item cloneStruct(boolean forCalculate, List<Item> calArgs, boolean isPushDown, List<Field> fields) {
// TODO Auto-generated method stub
return null;
}
}
@@ -2,21 +2,16 @@
* Copyright (C) 2016-2017 ActionTech.
* License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher.
*/
/**
*
*/
package com.actiontech.dble.plan.common.item.subquery;
import com.actiontech.dble.config.ErrorCode;
import com.actiontech.dble.plan.common.context.NameResolutionContext;
import com.actiontech.dble.plan.common.context.ReferContext;
import com.actiontech.dble.plan.common.exception.MySQLOutPutException;
import com.actiontech.dble.plan.common.field.Field;
import com.actiontech.dble.plan.common.item.Item;
import com.actiontech.dble.plan.common.item.ItemInt;
import com.actiontech.dble.plan.common.time.MySQLTime;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.expr.SQLInSubQueryExpr;
import com.alibaba.druid.sql.ast.expr.SQLExistsExpr;
import com.alibaba.druid.sql.ast.statement.SQLSelect;
import com.alibaba.druid.sql.ast.statement.SQLSelectQuery;
@@ -24,39 +19,24 @@ import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.List;
public class ItemInSubselect extends ItemSubselect {
private boolean isNeg;
private Item leftOprand;
/**
* @param currentDb
* @param query
*/
public ItemInSubselect(String currentDb, Item leftOprand, SQLSelectQuery query, boolean isNeg) {
super(currentDb, query);
this.leftOprand = leftOprand;
this.isNeg = isNeg;
public class ItemExistsSubQuery extends ItemSingleRowSubQuery {
private boolean isNot;
public ItemExistsSubQuery(String currentDb, SQLSelectQuery query, boolean isNot) {
super(currentDb, query, false);
this.isNot = isNot;
if (!this.correlatedSubQuery) {
if ((this.planNode.getLimitFrom() == -1)) {
this.planNode.setLimitFrom(0);
this.planNode.setLimitTo(1);
} else if (this.planNode.getLimitTo() > 1) {
this.planNode.setLimitTo(1);
}
this.select = new ItemInt(1L);
this.planNode.getColumnsSelected().add(select);
}
}
@Override
public void fixLengthAndDec() {
}
public Item fixFields(NameResolutionContext context) {
super.fixFields(context);
leftOprand = leftOprand.fixFields(context);
return this;
}
/**
* added to construct all refers in an item
*
* @param context
*/
public void fixRefer(ReferContext context) {
super.fixRefer(context);
leftOprand.fixRefer(context);
}
@Override
@@ -89,27 +69,22 @@ public class ItemInSubselect extends ItemSubselect {
throw new MySQLOutPutException(ErrorCode.ER_OPTIMIZER, "", "not support yet!");
}
public Item getLeftOprand() {
return leftOprand;
}
public boolean isNeg() {
return isNeg;
}
@Override
public SQLExpr toExpression() {
SQLExpr expr = leftOprand.toExpression();
SQLSelect select = new SQLSelect(query);
SQLInSubQueryExpr insub = new SQLInSubQueryExpr(select);
insub.setExpr(expr);
insub.setNot(isNeg);
return insub;
return new SQLExistsExpr(new SQLSelect(query), isNot);
}
@Override
protected Item cloneStruct(boolean forCalculate, List<Item> calArgs, boolean isPushDown, List<Field> fields) {
throw new MySQLOutPutException(ErrorCode.ER_OPTIMIZER, "", "unexpected!");
return new ItemExistsSubQuery(this.currentDb, this.query, this.isNot);
}
@Override
public SubSelectType subType() {
return SubSelectType.EXISTS_SUBS;
}
public boolean isNot() {
return isNot;
}
}
@@ -0,0 +1,78 @@
/*
* Copyright (C) 2016-2017 ActionTech.
* License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher.
*/
package com.actiontech.dble.plan.common.item.subquery;
import com.actiontech.dble.config.ErrorCode;
import com.actiontech.dble.plan.common.context.NameResolutionContext;
import com.actiontech.dble.plan.common.context.ReferContext;
import com.actiontech.dble.plan.common.exception.MySQLOutPutException;
import com.actiontech.dble.plan.common.field.Field;
import com.actiontech.dble.plan.common.item.Item;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.expr.SQLInSubQueryExpr;
import com.alibaba.druid.sql.ast.statement.SQLSelect;
import com.alibaba.druid.sql.ast.statement.SQLSelectQuery;
import java.util.List;
public class ItemInSubQuery extends ItemMultiRowSubQuery {
private boolean isNeg;
protected Item leftOperand;
public ItemInSubQuery(String currentDb, Item leftOperand, SQLSelectQuery query, boolean isNeg) {
super(currentDb, query);
this.leftOperand = leftOperand;
this.isNeg = isNeg;
if (this.planNode.getColumnsSelected().size() > 1) {
throw new MySQLOutPutException(ErrorCode.ER_OPERAND_COLUMNS, "", "Operand should contain 1 column(s)");
}
this.select = this.planNode.getColumnsSelected().get(0);
}
public Item fixFields(NameResolutionContext context) {
super.fixFields(context);
leftOperand = leftOperand.fixFields(context);
return this;
}
/**
* added to construct all refers in an item
*
* @param context
*/
public void fixRefer(ReferContext context) {
super.fixRefer(context);
leftOperand.fixRefer(context);
}
@Override
public SubSelectType subType() {
return SubSelectType.IN_SUBS;
}
@Override
public SQLExpr toExpression() {
SQLExpr expr = leftOperand.toExpression();
SQLSelect sqlSelect = new SQLSelect(query);
SQLInSubQueryExpr inSub = new SQLInSubQueryExpr(sqlSelect);
inSub.setExpr(expr);
inSub.setNot(isNeg);
return inSub;
}
@Override
protected Item cloneStruct(boolean forCalculate, List<Item> calArgs, boolean isPushDown, List<Field> fields) {
return new ItemInSubQuery(this.currentDb, this.leftOperand.cloneItem(), this.query, this.isNeg);
}
public Item getLeftOperand() {
return leftOperand;
}
public boolean isNeg() {
return isNeg;
}
}
@@ -1,24 +0,0 @@
/*
* Copyright (C) 2016-2017 ActionTech.
* License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher.
*/
/**
*
*/
package com.actiontech.dble.plan.common.item.subquery;
import com.alibaba.druid.sql.ast.statement.SQLSelectQuery;
public class ItemMaxminSubselect extends ItemSinglerowSubselect {
/**
* @param currentDb
* @param query
*/
public ItemMaxminSubselect(String currentDb, SQLSelectQuery query, boolean max) {
super(currentDb, query);
boolean max1 = max;
}
}
@@ -10,80 +10,80 @@ package com.actiontech.dble.plan.common.item.subquery;
import com.actiontech.dble.config.ErrorCode;
import com.actiontech.dble.plan.common.exception.MySQLOutPutException;
import com.actiontech.dble.plan.common.field.Field;
import com.actiontech.dble.plan.common.item.Item;
import com.actiontech.dble.plan.common.time.MySQLTime;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.statement.SQLSelectQuery;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
public class ItemExistsSubselect extends ItemSubselect {
public abstract class ItemMultiRowSubQuery extends ItemSubQuery {
protected List<Item> value = new ArrayList<>();
protected Item filed;
protected Item select;
/**
* @param currentDb
* @param query
*/
public ItemExistsSubselect(String currentDb, SQLSelectQuery query, boolean isNot) {
public ItemMultiRowSubQuery(String currentDb, SQLSelectQuery query) {
super(currentDb, query);
boolean isNot1 = isNot;
throw new MySQLOutPutException(ErrorCode.ER_OPTIMIZER, "", "not support!");
}
@Override
public void fixLengthAndDec() {
// TODO Auto-generated method stub
}
@Override
public BigDecimal valReal() {
// TODO Auto-generated method stub
return null;
throw new MySQLOutPutException(ErrorCode.ER_OPTIMIZER, "", "not support yet!");
}
@Override
public BigInteger valInt() {
// TODO Auto-generated method stub
return null;
throw new MySQLOutPutException(ErrorCode.ER_OPTIMIZER, "", "not support yet!");
}
@Override
public String valStr() {
// TODO Auto-generated method stub
return null;
throw new MySQLOutPutException(ErrorCode.ER_OPTIMIZER, "", "not support yet!");
}
@Override
public BigDecimal valDecimal() {
// TODO Auto-generated method stub
return null;
throw new MySQLOutPutException(ErrorCode.ER_OPTIMIZER, "", "not support yet!");
}
@Override
public boolean getDate(MySQLTime ltime, long fuzzydate) {
// TODO Auto-generated method stub
return false;
throw new MySQLOutPutException(ErrorCode.ER_OPTIMIZER, "", "not support yet!");
}
@Override
public boolean getTime(MySQLTime ltime) {
// TODO Auto-generated method stub
return false;
throw new MySQLOutPutException(ErrorCode.ER_OPTIMIZER, "", "not support yet!");
}
@Override
public SQLExpr toExpression() {
// TODO Auto-generated method stub
return null;
public Item getSelect() {
return select;
}
@Override
protected Item cloneStruct(boolean forCalculate, List<Item> calArgs, boolean isPushDown, List<Field> fields) {
// TODO Auto-generated method stub
return null;
public void setSelect(Item select) {
this.select = select;
}
public Item getFiled() {
return filed;
}
public void setFiled(Item filed) {
this.filed = filed;
}
public List<Item> getValue() {
return value;
}
}
@@ -0,0 +1,59 @@
/*
* Copyright (C) 2016-2017 ActionTech.
* License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher.
*/
package com.actiontech.dble.plan.common.item.subquery;
import com.actiontech.dble.config.ErrorCode;
import com.actiontech.dble.plan.common.exception.MySQLOutPutException;
import com.actiontech.dble.plan.common.field.Field;
import com.actiontech.dble.plan.common.item.Item;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.expr.SQLQueryExpr;
import com.alibaba.druid.sql.ast.statement.SQLSelect;
import com.alibaba.druid.sql.ast.statement.SQLSelectQuery;
import java.util.List;
public class ItemScalarSubQuery extends ItemSingleRowSubQuery {
public ItemScalarSubQuery(String currentDb, SQLSelectQuery query) {
super(currentDb, query, false);
if (this.planNode.getColumnsSelected().size() > 1) {
throw new MySQLOutPutException(ErrorCode.ER_OPERAND_COLUMNS, "", "Operand should contain 1 column(s)");
}
if (!this.correlatedSubQuery) {
if ((this.planNode.getLimitFrom() == -1)) {
this.planNode.setLimitFrom(0);
this.planNode.setLimitTo(2);
} else if (this.planNode.getLimitTo() > 2) {
this.planNode.setLimitTo(2);
}
}
}
@Override
public SubSelectType subType() {
return SubSelectType.SINGLEROW_SUBS;
}
@Override
public void fixLengthAndDec() {
}
@Override
public SQLExpr toExpression() {
SQLSelect sqlSelect = new SQLSelect(query);
SQLQueryExpr expr = new SQLQueryExpr(sqlSelect);
return expr;
}
@Override
protected Item cloneStruct(boolean forCalculate, List<Item> calArgs, boolean isPushDown, List<Field> fieldList) {
return new ItemScalarSubQuery(this.currentDb, this.query);
}
}
@@ -3,36 +3,26 @@
* License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher.
*/
/**
*
*/
package com.actiontech.dble.plan.common.item.subquery;
import com.actiontech.dble.plan.common.field.Field;
import com.actiontech.dble.plan.common.item.Item;
import com.actiontech.dble.plan.common.time.MySQLTime;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.statement.SQLSelectQuery;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.List;
public class ItemSinglerowSubselect extends ItemSubselect {
private List<Item> row;
/* row item fields*/
private List<Field> fields;
private Item value;
private boolean noRows;
public abstract class ItemSingleRowSubQuery extends ItemSubQuery {
protected Item value;
protected Item select;
protected boolean isField;
public ItemSinglerowSubselect(String currentDb, SQLSelectQuery query) {
public ItemSingleRowSubQuery(String currentDb, SQLSelectQuery query, boolean isField) {
super(currentDb, query);
this.select = this.planNode.getColumnsSelected().get(0);
this.isField = isField;
}
@Override
public SubSelectType substype() {
return SubSelectType.SINGLEROW_SUBS;
}
@Override
public void reset() {
@@ -43,7 +33,7 @@ public class ItemSinglerowSubselect extends ItemSubselect {
@Override
public BigDecimal valReal() {
if (!noRows && !execute() && !value.isNullValue()) {
if (!execute() && !value.isNullValue()) {
nullValue = false;
return value.valReal();
} else {
@@ -54,7 +44,7 @@ public class ItemSinglerowSubselect extends ItemSubselect {
@Override
public BigInteger valInt() {
if (!noRows && !execute() && !value.isNullValue()) {
if (!execute() && !value.isNullValue()) {
nullValue = false;
return value.valInt();
} else {
@@ -65,7 +55,7 @@ public class ItemSinglerowSubselect extends ItemSubselect {
@Override
public String valStr() {
if (!noRows && !execute() && !value.isNullValue()) {
if (!execute() && !value.isNullValue()) {
nullValue = false;
return value.valStr();
} else {
@@ -76,7 +66,7 @@ public class ItemSinglerowSubselect extends ItemSubselect {
@Override
public BigDecimal valDecimal() {
if (!noRows && !execute() && !value.isNullValue()) {
if (!execute() && !value.isNullValue()) {
nullValue = false;
return value.valDecimal();
} else {
@@ -87,7 +77,7 @@ public class ItemSinglerowSubselect extends ItemSubselect {
@Override
public boolean getDate(MySQLTime ltime, long fuzzydate) {
if (!noRows && !execute() && !value.isNullValue()) {
if (!execute() && !value.isNullValue()) {
nullValue = false;
return value.getDate(ltime, fuzzydate);
} else {
@@ -98,7 +88,7 @@ public class ItemSinglerowSubselect extends ItemSubselect {
@Override
public boolean getTime(MySQLTime ltime) {
if (!noRows && !execute() && !value.isNullValue()) {
if (!execute() && !value.isNullValue()) {
nullValue = false;
return value.getTime(ltime);
} else {
@@ -109,7 +99,7 @@ public class ItemSinglerowSubselect extends ItemSubselect {
@Override
public boolean valBool() {
if (!noRows && !execute() && !value.isNullValue()) {
if (!execute() && !value.isNullValue()) {
nullValue = false;
return value.valBool();
} else {
@@ -123,25 +113,30 @@ public class ItemSinglerowSubselect extends ItemSubselect {
}
@Override
public SQLExpr toExpression() {
// TODO
return null;
}
@Override
protected Item cloneStruct(boolean forCalculate, List<Item> calArgs, boolean isPushDown, List<Field> fieldList) {
// TODO Auto-generated method stub
return null;
}
/*--------------------------------------getter/setter-----------------------------------*/
public List<Field> getFields() {
return fields;
public Item getValue() {
return value;
}
public void setFields(List<Field> fields) {
this.fields = fields;
public void setValue(Item value) {
this.value = value;
}
public Item getSelect() {
return select;
}
public void setSelect(Item select) {
this.select = select;
}
public boolean isField() {
return isField;
}
public void setField(boolean field) {
isField = field;
}
}
@@ -8,31 +8,29 @@
*/
package com.actiontech.dble.plan.common.item.subquery;
import com.actiontech.dble.config.ErrorCode;
import com.actiontech.dble.plan.PlanNode;
import com.actiontech.dble.plan.PlanNode.PlanNodeType;
import com.actiontech.dble.plan.common.context.NameResolutionContext;
import com.actiontech.dble.plan.common.context.ReferContext;
import com.actiontech.dble.plan.common.exception.MySQLOutPutException;
import com.actiontech.dble.plan.common.item.Item;
import com.actiontech.dble.plan.common.item.ItemResultField;
import com.actiontech.dble.plan.visitor.MySQLPlanNodeVisitor;
import com.alibaba.druid.sql.ast.statement.SQLSelectQuery;
public abstract class ItemSubselect extends ItemResultField {
public abstract class ItemSubQuery extends ItemResultField {
protected SQLSelectQuery query;
private String currentDb;
private PlanNode planNode;
protected String currentDb;
protected PlanNode planNode;
public enum SubSelectType {
UNKNOWN_SUBS, SINGLEROW_SUBS, EXISTS_SUBS, IN_SUBS, ALL_SUBS, ANY_SUBS
}
public SubSelectType substype() {
public SubSelectType subType() {
return SubSelectType.UNKNOWN_SUBS;
}
public ItemSubselect(String currentDb, SQLSelectQuery query) {
public ItemSubQuery(String currentDb, SQLSelectQuery query) {
this.query = query;
this.currentDb = currentDb;
init();
@@ -49,6 +47,12 @@ public abstract class ItemSubselect extends ItemResultField {
this.planNode = pv.getTableNode();
if (planNode.type() != PlanNodeType.NONAME) {
this.withSubQuery = true;
PlanNode test = this.planNode.copy();
try {
test.setUpFields();
} catch (Exception e) {
this.correlatedSubQuery = true;
}
}
}
@@ -64,7 +68,7 @@ public abstract class ItemSubselect extends ItemResultField {
@Override
public boolean fixFields() {
throw new MySQLOutPutException(ErrorCode.ER_QUERYHANDLER, "", "not supported!");
return false;
}
public Item fixFields(NameResolutionContext context) {
@@ -80,8 +84,6 @@ public abstract class ItemSubselect extends ItemResultField {
public void fixRefer(ReferContext context) {
if (context.isPushDownNode())
return;
else
context.getPlanNode().getSubSelects().add(this);
}
@Override
@@ -102,8 +104,4 @@ public abstract class ItemSubselect extends ItemResultField {
this.planNode = planNode;
}
@Override
public String toString() {
throw new MySQLOutPutException(ErrorCode.ER_OPTIMIZER, "", "not supported!");
}
}
@@ -10,10 +10,8 @@ import com.actiontech.dble.config.model.SchemaConfig;
import com.actiontech.dble.plan.PlanNode;
import com.actiontech.dble.plan.util.ToStringUtil;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
/**
* NoNameNode eg:select 1,only exists selecteditems
@@ -48,10 +46,6 @@ public class NoNameNode extends PlanNode {
return "";
}
@Override
public List<TableNode> getReferedTableNodes() {
return new ArrayList<>();
}
public String getCatalog() {
return this.catalog;
@@ -10,7 +10,7 @@ import com.actiontech.dble.plan.common.item.Item;
import com.actiontech.dble.plan.util.ToStringUtil;
/*
* query a logic table
* query a logic table ,in fact, it is derived sub query
*/
public class QueryNode extends PlanNode {
@@ -6,6 +6,7 @@
package com.actiontech.dble.plan.node;
import com.actiontech.dble.DbleServer;
import com.actiontech.dble.server.variables.SystemVariables;
import com.actiontech.dble.config.ServerConfig;
import com.actiontech.dble.config.model.SchemaConfig;
import com.actiontech.dble.config.model.TableConfig;
@@ -40,7 +41,7 @@ public class TableNode extends PlanNode {
this.schema = catalog;
this.tableName = tableName;
ServerConfig config = DbleServer.getInstance().getConfig();
if (config.getSystem().isLowerCaseTableNames()) {
if (SystemVariables.getSysVars().isLowerCaseTableNames()) {
this.schema = this.schema.toLowerCase();
this.tableName = this.tableName.toLowerCase();
}
@@ -31,6 +31,6 @@ public final class ViewUtil {
boolean selectsAllowMerge = viewSelNode.type() != PlanNode.PlanNodeType.MERGE;
// TODO as the same as LEX::can_be_merged();
boolean existAggr = PlanUtil.existAggr(viewSelNode);
return selectsAllowMerge && viewSelNode.getReferedTableNodes().size() >= 1 && !existAggr;
return selectsAllowMerge && viewSelNode.getReferedTableNodes().size() == 1 && !existAggr;
}
}
@@ -524,10 +524,10 @@ public class ERJoinChooser {
//TODO:performance
private boolean isGlobalTree(PlanNode tn) {
if (tn instanceof TableNode) {
if (tn instanceof TableNode && tn.getSubQueries().size() == 0) {
return tn.getUnGlobalTableCount() == 0;
} else if (tn.type() == PlanNode.PlanNodeType.NONAME) {
return true;
return tn.getSubQueries().size() == 0;
} else {
for (TableNode leaf : tn.getReferedTableNodes()) {
if (leaf.getUnGlobalTableCount() != 0)
@@ -185,6 +185,8 @@ public final class FilterPreProcessor {
if (!inMap.containsKey(a))
inMap.put(a, new HashSet<Item>());
inMap.get(a).add(b);
} else { // stop convert
return filter;
}
} else {
Item subNew = convertOrToIn(subFilter);
@@ -7,6 +7,7 @@ package com.actiontech.dble.plan.optimizer;
import com.actiontech.dble.plan.PlanNode;
import com.actiontech.dble.plan.PlanNode.PlanNodeType;
import com.actiontech.dble.plan.common.item.subquery.ItemSubQuery;
import com.actiontech.dble.plan.node.JoinNode;
import com.actiontech.dble.plan.util.PlanUtil;
@@ -27,18 +28,24 @@ public final class GlobalTableProcessor {
* @return true:parent node maybe is global;false parent node must not be global
*/
private static boolean initGlobalStatus(PlanNode tn) {
if (tn == null || tn.type() == PlanNodeType.TABLE)
if (tn == null || ((tn.type() == PlanNodeType.TABLE || tn.type() == PlanNodeType.NONAME) && tn.getSubQueries().size() == 0)) {
return true;
}
boolean status = true;
for (PlanNode child : tn.getChildren()) {
boolean ret = initGlobalStatus(child);
if (status) {
status = ret;
}
}
for (ItemSubQuery subQuery : tn.getSubQueries()) {
boolean ret = initGlobalStatus(subQuery.getPlanNode());
if (status) {
status = ret;
}
}
if (PlanUtil.isERNode(tn)) {
// treat erjoin as an unglobaltable
// treat er join as an un global table
tn.setUnGlobalTableCount(1);
Set<String> newSet = new HashSet<>();
newSet.addAll(tn.getReferedTableNodes().get(0).getNoshardNode());
@@ -90,38 +97,51 @@ public final class GlobalTableProcessor {
private static int calcUnGlobalCount(PlanNode tn) {
int unGlobalCount = 0;
for (ItemSubQuery subQuery : tn.getSubQueries()) {
PlanNode subNode = subQuery.getPlanNode();
resetNoShardNode(tn, subNode);
unGlobalCount += subNode.getUnGlobalTableCount();
}
for (PlanNode tnChild : tn.getChildren()) {
if (tnChild != null) {
if (tn.getNoshardNode() == null) {
if (tnChild.getNoshardNode() != null) {
Set<String> parentSet = new HashSet<>();
parentSet.addAll(tnChild.getNoshardNode());
tn.setNoshardNode(parentSet);
}
}
if (tn.getNoshardNode() != null) {
tn.getNoshardNode().retainAll(tnChild.getNoshardNode());
}
resetNoShardNode(tn, tnChild);
unGlobalCount += tnChild.getUnGlobalTableCount();
}
}
return unGlobalCount;
}
private static void resetNoShardNode(PlanNode tn, PlanNode tnChild) {
if (tn.getNoshardNode() == null) {
if (tnChild.getNoshardNode() != null) {
Set<String> parentSet = new HashSet<>();
parentSet.addAll(tnChild.getNoshardNode());
tn.setNoshardNode(parentSet);
}
}
if (tn.getNoshardNode() != null) {
if (tnChild.getNoshardNode() != null) {
tn.getNoshardNode().retainAll(tnChild.getNoshardNode());
} else {
tn.setNoshardNode(null);
}
}
}
private static boolean isGlobalTableBigEnough(JoinNode jn) {
PlanNode left = jn.getLeftNode();
PlanNode right = jn.getRightNode();
PlanNode global, noraml;
PlanNode global, normal;
if (left.getUnGlobalTableCount() == 0) {
global = left;
noraml = right;
normal = right;
} else {
global = right;
noraml = left;
normal = left;
}
Set<String> result = new HashSet<>();
result.addAll(global.getNoshardNode());
Set<String> normalSet = noraml.getNoshardNode();
Set<String> normalSet = normal.getNoshardNode();
result.retainAll(normalSet);
return result.size() == normalSet.size();
}
@@ -10,6 +10,7 @@ import com.actiontech.dble.plan.node.JoinNode;
import com.actiontech.dble.plan.util.PlanUtil;
public final class JoinStrategyProcessor {
public static final String NEED_REPLACE = "{NEED_TO_REPLACE}";
private JoinStrategyProcessor() {
}
@@ -9,12 +9,15 @@ import com.actiontech.dble.DbleServer;
import com.actiontech.dble.config.model.SchemaConfig;
import com.actiontech.dble.plan.PlanNode;
import com.actiontech.dble.plan.common.exception.MySQLOutPutException;
import com.actiontech.dble.plan.common.item.subquery.ItemSubQuery;
import com.actiontech.dble.plan.node.TableNode;
import com.actiontech.dble.route.util.RouterUtil;
import com.actiontech.dble.server.util.SchemaUtil;
import org.apache.log4j.Logger;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public final class MyOptimizer {
@@ -26,7 +29,8 @@ public final class MyOptimizer {
try {
// PreProcessor SubQuery
node = SubQueryPreProcessor.optimize(node);
int existGlobal = checkGlobalTable(node);
updateReferedTableNodes(node);
int existGlobal = checkGlobalTable(node, new HashSet<String>());
if (node.isExsitView() || existGlobal != 1) {
// optimizer subquery
node = SubQueryProcessor.optimize(node);
@@ -64,6 +68,20 @@ public final class MyOptimizer {
}
}
private static List<TableNode> updateReferedTableNodes(PlanNode node) {
List<TableNode> subTables = new ArrayList<>();
for (PlanNode childNode : node.getChildren()) {
List<TableNode> childSubTables = updateReferedTableNodes(childNode);
node.getReferedTableNodes().addAll(childSubTables);
subTables.addAll(childSubTables);
}
for (ItemSubQuery subQuery : node.getSubQueries()) {
List<TableNode> childSubTables = subQuery.getPlanNode().getReferedTableNodes();
node.getReferedTableNodes().addAll(childSubTables);
subTables.addAll(childSubTables);
}
return subTables;
}
/**
* existShardTable
*
@@ -72,7 +90,10 @@ public final class MyOptimizer {
* return -1 if all the table is not global table,need not global optimizer;
* return 0 for other ,may need to global optimizer ;
*/
public static int checkGlobalTable(PlanNode node) {
public static int checkGlobalTable(PlanNode node, Set<String> resultDataNodes) {
if (node.isSubQuery()) {
return 0;
}
Set<String> dataNodes = null;
boolean isAllGlobal = true;
boolean isContainGlobal = false;
@@ -102,9 +123,11 @@ public final class MyOptimizer {
String db = SchemaUtil.getRandomDb();
SchemaConfig schemaConfig = DbleServer.getInstance().getConfig().getSchemas().get(db);
node.setNoshardNode(schemaConfig.getAllDataNodes());
resultDataNodes.addAll(schemaConfig.getAllDataNodes());
return 1;
} else if (dataNodes.size() > 0) { //all global table
node.setNoshardNode(dataNodes);
resultDataNodes.addAll(dataNodes);
String sql = node.getSql();
for (TableNode tn : node.getReferedTableNodes()) {
sql = RouterUtil.removeSchema(sql, tn.getSchema());
@@ -115,10 +138,7 @@ public final class MyOptimizer {
return 0;
}
}
if (!isContainGlobal) {
return -1;
}
return 0;
return -1;
}
@@ -12,6 +12,7 @@ import com.actiontech.dble.plan.common.item.ItemField;
import com.actiontech.dble.plan.common.item.ItemInt;
import com.actiontech.dble.plan.common.item.function.ItemFunc;
import com.actiontech.dble.plan.common.item.function.sumfunc.ItemSum;
import com.actiontech.dble.plan.common.item.subquery.ItemSubQuery;
import com.actiontech.dble.plan.node.MergeNode;
import com.actiontech.dble.plan.util.PlanUtil;
@@ -58,6 +59,11 @@ public final class SelectedProcessor {
if (qtn.type() == PlanNode.PlanNodeType.MERGE) {
return mergePushSelected((MergeNode) qtn, toPushColumns);
} else {
if (qtn.getSubQueries().size() > 0) {
for (ItemSubQuery itemSubQuery : qtn.getSubQueries()) {
pushSelected(itemSubQuery.getPlanNode(), new HashSet<Item>());
}
}
if (toPushColumns.isEmpty()) {
qtn.setUpRefers(isPushDownNode);
} else if (qtn.isDistinct()) {
@@ -14,13 +14,14 @@ import com.actiontech.dble.plan.common.item.Item.ItemType;
import com.actiontech.dble.plan.common.item.ItemField;
import com.actiontech.dble.plan.common.item.ItemInt;
import com.actiontech.dble.plan.common.item.function.operator.ItemBoolFunc2;
import com.actiontech.dble.plan.common.item.function.operator.cmpfunc.*;
import com.actiontech.dble.plan.common.item.function.operator.cmpfunc.ItemFuncEqual;
import com.actiontech.dble.plan.common.item.function.operator.logic.ItemCondAnd;
import com.actiontech.dble.plan.common.item.function.operator.logic.ItemCondOr;
import com.actiontech.dble.plan.common.item.subquery.ItemInSubselect;
import com.actiontech.dble.plan.common.item.subquery.ItemSubselect;
import com.actiontech.dble.plan.common.item.subquery.*;
import com.actiontech.dble.plan.common.ptr.BoolPtr;
import com.actiontech.dble.plan.node.JoinNode;
import com.actiontech.dble.plan.util.FilterUtils;
import com.actiontech.dble.plan.util.PlanUtil;
import org.apache.commons.lang.StringUtils;
import java.util.ArrayList;
@@ -35,78 +36,109 @@ public final class SubQueryPreProcessor {
public static PlanNode optimize(PlanNode qtn) {
MergeHavingFilter.optimize(qtn);
qtn = findComparisonsSubQueryToJoinNode(qtn);
qtn = findComparisonsSubQueryToJoinNode(qtn, new BoolPtr(false));
return qtn;
}
/**
* http://dev.mysql.com/doc/refman/5.0/en/comparisons-using-subqueries.html
*/
private static PlanNode findComparisonsSubQueryToJoinNode(PlanNode qtn) {
private static PlanNode findComparisonsSubQueryToJoinNode(PlanNode qtn, BoolPtr childTransform) {
for (int i = 0; i < qtn.getChildren().size(); i++) {
PlanNode child = qtn.getChildren().get(i);
qtn.getChildren().set(i, findComparisonsSubQueryToJoinNode(child));
qtn.getChildren().set(i, findComparisonsSubQueryToJoinNode(child, childTransform));
}
SubQueryAndFilter find = new SubQueryAndFilter();
SubQueryFilter find = new SubQueryFilter();
find.query = qtn;
find.filter = null;
Item where = qtn.getWhereFilter();
SubQueryAndFilter result = buildSubQuery(find, where);
SubQueryFilter result = buildSubQuery(qtn, find, where, false, childTransform);
if (result != find) {
// that means where filter only contains subquery,just replace it
// that means where filter only contains sub query,just replace it
result.query.query(result.filter);
qtn.query(null);
// change result.filter and rebuild
result.query.setUpFields();
childTransform.set(true);
return result.query;
} else {
if (childTransform.get()) {
qtn.setUpFields();
}
return qtn;
}
}
private static SubQueryAndFilter buildSubQuery(SubQueryAndFilter qtn, Item filter) {
private static SubQueryFilter buildSubQuery(PlanNode node, SubQueryFilter qtn, Item filter, boolean isOrChild, BoolPtr childTransform) {
if (filter == null)
return qtn;
if (!filter.isWithSubQuery()) {
qtn.filter = filter;
} else if (filter instanceof ItemCondOr) {
throw new MySQLOutPutException(ErrorCode.ER_OPTIMIZER, "", "not support 'or' when condition subquery");
return buildSubQueryWithOrFilter(node, qtn, (ItemCondOr) filter, childTransform);
} else if (filter instanceof ItemCondAnd) {
return buildSubQueryWithAndFilter(qtn, (ItemCondAnd) filter);
return buildSubQueryWithAndFilter(node, qtn, (ItemCondAnd) filter, isOrChild, childTransform);
} else {
return buildSubQueryByFilter(qtn, filter);
return buildSubQueryByFilter(node, qtn, filter, isOrChild, childTransform);
}
return qtn;
}
private static SubQueryAndFilter buildSubQueryByFilter(SubQueryAndFilter qtn, Item filter) {
Item leftColumn;
PlanNode query;
boolean isNotIn = false;
boolean needExchange = false;
if (isCmpFunc(filter)) {
private static SubQueryFilter buildSubQueryByFilter(PlanNode node, SubQueryFilter qtn, Item filter, boolean isOrChild, BoolPtr childTransform) {
if (filter instanceof ItemInSubQuery && !isOrChild) {
return transformInSubQuery(qtn, (ItemInSubQuery) filter, childTransform);
} else if (filter instanceof ItemInSubQuery) {
addSubQuey(node, (ItemInSubQuery) filter, childTransform);
return qtn;
} else if (PlanUtil.isCmpFunc(filter)) {
ItemBoolFunc2 eqFilter = (ItemBoolFunc2) filter;
Item arg0 = eqFilter.arguments().get(0);
Item arg1 = eqFilter.arguments().get(1);
boolean arg0IsSubQuery = arg0.type().equals(ItemType.SUBSELECT_ITEM);
boolean arg1IsSubQuery = arg1.type().equals(ItemType.SUBSELECT_ITEM);
if (arg0IsSubQuery && arg1IsSubQuery) {
throw new MySQLOutPutException(ErrorCode.ER_OPTIMIZER, "",
"left and right both condition subquery,not supported...");
if (arg0.type().equals(ItemType.SUBSELECT_ITEM)) {
if (arg0 instanceof ItemScalarSubQuery) {
addSubQuey(node, (ItemScalarSubQuery) arg0, childTransform);
} else {
//todo: when happened?
throw new MySQLOutPutException(ErrorCode.ER_OPTIMIZER, "", "not support subquery of:" + filter.type());
}
}
needExchange = arg0IsSubQuery;
leftColumn = arg0IsSubQuery ? arg1 : arg0;
query = arg0IsSubQuery ? ((ItemSubselect) arg0).getPlanNode() : ((ItemSubselect) arg1).getPlanNode();
} else if (filter instanceof ItemInSubselect) {
ItemInSubselect inSub = (ItemInSubselect) filter;
leftColumn = inSub.getLeftOprand();
query = inSub.getPlanNode();
isNotIn = inSub.isNeg();
Item arg1 = eqFilter.arguments().get(1);
if (arg1.type().equals(ItemType.SUBSELECT_ITEM)) {
if (arg1 instanceof ItemScalarSubQuery) {
addSubQuey(node, (ItemScalarSubQuery) arg1, childTransform);
} else if (arg1 instanceof ItemAllAnySubQuery) {
addSubQuey(node, (ItemAllAnySubQuery) arg1, childTransform);
} else {
//todo: when happened?
throw new MySQLOutPutException(ErrorCode.ER_OPTIMIZER, "", "not support subquery of:" + filter.type());
}
}
return qtn;
} else if (filter.type().equals(ItemType.SUBSELECT_ITEM)) {
if (filter instanceof ItemExistsSubQuery) {
addSubQuey(node, (ItemExistsSubQuery) filter, childTransform);
} else {
//todo: when happened?
throw new MySQLOutPutException(ErrorCode.ER_OPTIMIZER, "", "not support subquery of:" + filter.type());
}
return qtn;
} else {
//todo: when happened?
throw new MySQLOutPutException(ErrorCode.ER_OPTIMIZER, "", "not support subquery of:" + filter.type());
}
query = findComparisonsSubQueryToJoinNode(query);
}
private static void addSubQuey(PlanNode node, ItemSubQuery subQuery, BoolPtr childTransform) {
node.getSubQueries().add(subQuery);
PlanNode subNode = findComparisonsSubQueryToJoinNode(subQuery.getPlanNode(), childTransform);
subQuery.setPlanNode(subNode);
}
private static SubQueryFilter transformInSubQuery(SubQueryFilter qtn, ItemInSubQuery filter, BoolPtr childTransform) {
Item leftColumn = filter.getLeftOperand();
PlanNode query = filter.getPlanNode();
query = findComparisonsSubQueryToJoinNode(query, childTransform);
if (StringUtils.isEmpty(query.getAlias()))
query.alias(AUTOALIAS + query.getPureName());
if (query.getColumnsSelected().size() != 1)
@@ -114,7 +146,7 @@ public final class SubQueryPreProcessor {
query.setSubQuery(true).setDistinct(true);
final List<Item> newSelects = qtn.query.getColumnsSelected();
SubQueryAndFilter result = new SubQueryAndFilter();
SubQueryFilter result = new SubQueryFilter();
Item rightColumn = query.getColumnsSelected().get(0);
qtn.query.setColumnsSelected(new ArrayList<Item>());
String rightJoinName = rightColumn.getAlias();
@@ -130,7 +162,7 @@ public final class SubQueryPreProcessor {
ItemField rightJoinColumn = new ItemField(null, query.getAlias(), rightJoinName);
// rename the left column's table name
result.query = new JoinNode(qtn.query, query);
// leave origin sqlto new join node
// leave origin sql to new join node
result.query.setSql(qtn.query.getSql());
qtn.query.setSql(null);
result.query.select(newSelects);
@@ -154,13 +186,13 @@ public final class SubQueryPreProcessor {
result.query.setLimitTo(qtn.query.getLimitTo());
qtn.query.setLimitTo(-1);
}
if (isNotIn) {
if (filter.isNeg()) {
((JoinNode) result.query).setLeftOuterJoin().setNotIn(true);
ItemFuncEqual joinFilter = FilterUtils.equal(leftColumn, rightJoinColumn);
((JoinNode) result.query).addJoinFilter(joinFilter);
result.filter = null;
} else {
Item joinFilter = calcJoinFilter(filter, leftColumn, needExchange, rightJoinColumn);
Item joinFilter = FilterUtils.equal(leftColumn, rightJoinColumn);
result.query.query(joinFilter);
result.filter = joinFilter;
}
@@ -178,54 +210,31 @@ public final class SubQueryPreProcessor {
return result;
}
private static boolean isCmpFunc(Item filter) {
return filter instanceof ItemFuncEqual || filter instanceof ItemFuncGt || filter instanceof ItemFuncGe ||
filter instanceof ItemFuncLt || filter instanceof ItemFuncLe || filter instanceof ItemFuncNe ||
filter instanceof ItemFuncStrictEqual;
}
private static Item calcJoinFilter(Item filter, Item leftColumn, boolean needExchange, ItemField rightJoinColumn) {
Item joinFilter;
if (((filter instanceof ItemFuncGt) && !needExchange) ||
((filter instanceof ItemFuncLt) && needExchange)) {
joinFilter = FilterUtils.greaterThan(leftColumn, rightJoinColumn);
} else if (((filter instanceof ItemFuncLt) && !needExchange) ||
((filter instanceof ItemFuncGt) && needExchange)) {
joinFilter = FilterUtils.lessThan(leftColumn, rightJoinColumn);
} else if (((filter instanceof ItemFuncGe) && !needExchange) ||
((filter instanceof ItemFuncLe) && needExchange)) {
joinFilter = FilterUtils.greaterEqual(leftColumn, rightJoinColumn);
} else if (((filter instanceof ItemFuncLe) && !needExchange) ||
((filter instanceof ItemFuncGe) && needExchange)) {
joinFilter = FilterUtils.lessEqual(leftColumn, rightJoinColumn);
} else if (filter instanceof ItemFuncNe) {
joinFilter = FilterUtils.notEqual(leftColumn, rightJoinColumn);
} else {
//equal or in
joinFilter = FilterUtils.equal(leftColumn, rightJoinColumn);
private static SubQueryFilter buildSubQueryWithOrFilter(PlanNode node, SubQueryFilter qtn, ItemCondOr filter, BoolPtr childTransform) {
for (int index = 0; index < filter.getArgCount(); index++) {
buildSubQuery(node, qtn, filter.arguments().get(index), true, childTransform);
}
return joinFilter;
return qtn;
}
private static SubQueryAndFilter buildSubQueryWithAndFilter(SubQueryAndFilter qtn, ItemCondAnd filter) {
ItemCondAnd andFilter = filter;
for (int index = 0; index < andFilter.getArgCount(); index++) {
SubQueryAndFilter result = buildSubQuery(qtn, andFilter.arguments().get(index));
private static SubQueryFilter buildSubQueryWithAndFilter(PlanNode node, SubQueryFilter qtn, ItemCondAnd filter, boolean isOrChild, BoolPtr childTransform) {
for (int index = 0; index < filter.getArgCount(); index++) {
SubQueryFilter result = buildSubQuery(node, qtn, filter.arguments().get(index), isOrChild, childTransform);
if (result != qtn) {
if (result.filter == null) {
result.filter = new ItemInt(1);
}
andFilter.arguments().set(index, result.filter);
filter.arguments().set(index, result.filter);
qtn = result;
}
}
qtn.filter = andFilter;
qtn.filter = filter;
return qtn;
}
private static class SubQueryAndFilter {
private static class SubQueryFilter {
PlanNode query; // subQuery may change querynode to join node
PlanNode query; // subQuery may change query node to join node
Item filter; // sub query's filter
}
@@ -127,7 +127,8 @@ public final class SubQueryProcessor {
private static void mergeWhere(PlanNode parent, PlanNode child) {
Item pWhere = parent.getWhereFilter();
Item pWhere0 = PlanUtil.pushDownItem(parent, pWhere, true);
Item mWhere = FilterUtils.and(pWhere0, child.getWhereFilter());
Item childWhere = PlanUtil.pushDownItem(child, child.getWhereFilter(), true);
Item mWhere = FilterUtils.and(pWhere0, childWhere);
child.setWhereFilter(mWhere);
}
@@ -17,7 +17,7 @@ import com.actiontech.dble.plan.common.item.ItemBasicConstant;
import com.actiontech.dble.plan.common.item.ItemField;
import com.actiontech.dble.plan.common.item.function.ItemFunc;
import com.actiontech.dble.plan.common.item.function.ItemFunc.Functype;
import com.actiontech.dble.plan.common.item.function.operator.cmpfunc.ItemFuncEqual;
import com.actiontech.dble.plan.common.item.function.operator.cmpfunc.*;
import com.actiontech.dble.plan.common.item.function.sumfunc.ItemSum;
import com.actiontech.dble.plan.common.item.function.sumfunc.ItemSum.SumFuncType;
import com.actiontech.dble.plan.node.JoinNode;
@@ -356,4 +356,10 @@ public final class PlanUtil {
return true;
}
}
public static boolean isCmpFunc(Item filter) {
return filter instanceof ItemFuncEqual || filter instanceof ItemFuncGt || filter instanceof ItemFuncGe ||
filter instanceof ItemFuncLt || filter instanceof ItemFuncLe || filter instanceof ItemFuncNe ||
filter instanceof ItemFuncStrictEqual;
}
}
@@ -36,13 +36,12 @@ import com.actiontech.dble.plan.common.item.function.timefunc.ItemDateAddInterva
import com.actiontech.dble.plan.common.item.function.timefunc.ItemExtract;
import com.actiontech.dble.plan.common.item.function.timefunc.ItemFuncTimestampDiff;
import com.actiontech.dble.plan.common.item.function.unknown.ItemFuncUnknown;
import com.actiontech.dble.plan.common.item.subquery.ItemInSubselect;
import com.actiontech.dble.plan.common.item.subquery.ItemSinglerowSubselect;
import com.actiontech.dble.plan.common.item.subquery.ItemAllAnySubQuery;
import com.actiontech.dble.plan.common.item.subquery.ItemExistsSubQuery;
import com.actiontech.dble.plan.common.item.subquery.ItemInSubQuery;
import com.actiontech.dble.plan.common.item.subquery.ItemScalarSubQuery;
import com.actiontech.dble.util.StringUtil;
import com.alibaba.druid.sql.ast.SQLDataType;
import com.alibaba.druid.sql.ast.SQLDataTypeImpl;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLOrderBy;
import com.alibaba.druid.sql.ast.*;
import com.alibaba.druid.sql.ast.expr.*;
import com.alibaba.druid.sql.ast.statement.SQLCharacterDataType;
import com.alibaba.druid.sql.ast.statement.SQLSelectOrderByItem;
@@ -92,7 +91,9 @@ public class MySQLItemVisitor extends MySqlASTVisitorAdapter {
@Override
public void endVisit(SQLQueryExpr x) {
SQLSelectQuery sqlSelect = x.getSubQuery().getQuery();
item = new ItemSinglerowSubselect(currentDb, sqlSelect);
item = new ItemScalarSubQuery(currentDb, sqlSelect);
initName(x);
item.setItemName(item.getItemName().replaceAll("\n\\t", " "));
}
@Override
@@ -105,7 +106,7 @@ public class MySQLItemVisitor extends MySqlASTVisitorAdapter {
public void endVisit(SQLInSubQueryExpr x) {
boolean isNeg = x.isNot();
Item left = getItem(x.getExpr());
item = new ItemInSubselect(currentDb, left, x.getSubQuery().getQuery(), isNeg);
item = new ItemInSubQuery(currentDb, left, x.getSubQuery().getQuery(), isNeg);
initName(x);
}
@@ -123,6 +124,10 @@ public class MySQLItemVisitor extends MySqlASTVisitorAdapter {
public void endVisit(SQLBinaryOpExpr x) {
Item itemLeft = getItem(x.getLeft());
Item itemRight = getItem(x.getRight());
if (itemRight instanceof ItemInSubQuery) {
item = itemRight;
return;
}
switch (x.getOperator()) {
case Is:
// is null, or is unknown
@@ -258,6 +263,8 @@ public class MySQLItemVisitor extends MySqlASTVisitorAdapter {
default:
throw new MySQLOutPutException(ErrorCode.ER_OPTIMIZER, "", "not supported kind expression:" + x.getOperator());
}
item.setWithSubQuery(itemLeft.isWithSubQuery() || itemRight.isWithSubQuery());
item.setCorrelatedSubQuery(itemLeft.isCorrelatedSubQuery() || itemRight.isCorrelatedSubQuery());
initName(x);
}
@@ -285,6 +292,8 @@ public class MySQLItemVisitor extends MySqlASTVisitorAdapter {
throw new MySQLOutPutException(ErrorCode.ER_OPTIMIZER, "",
"not supported kind expression:" + x.getOperator());
}
item.setWithSubQuery(a.isWithSubQuery());
item.setCorrelatedSubQuery(a.isCorrelatedSubQuery());
initName(x);
}
@@ -616,25 +625,42 @@ public class MySQLItemVisitor extends MySqlASTVisitorAdapter {
@Override
public void endVisit(SQLAllExpr x) {
throw new MySQLOutPutException(ErrorCode.ER_OPTIMIZER, "", "Subqueries with All is not supported");
SQLObject parent = x.getParent();
if (parent instanceof SQLBinaryOpExpr) {
handleAnySubQuery((SQLBinaryOpExpr) parent, x.getSubQuery().getQuery(), true);
} else {
throw new MySQLOutPutException(ErrorCode.ER_OPTIMIZER, "",
"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 all");
}
}
@Override
public void endVisit(SQLSomeExpr x) {
throw new MySQLOutPutException(ErrorCode.ER_OPTIMIZER, "", "Subqueries with Some is not supported");
SQLObject parent = x.getParent();
if (parent instanceof SQLBinaryOpExpr) {
handleAnySubQuery((SQLBinaryOpExpr) parent, x.getSubQuery().getQuery(), false);
} else {
throw new MySQLOutPutException(ErrorCode.ER_OPTIMIZER, "",
"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 all");
}
}
@Override
public void endVisit(SQLAnyExpr x) {
throw new MySQLOutPutException(ErrorCode.ER_OPTIMIZER, "", "Subqueries with Any is not supported");
SQLObject parent = x.getParent();
if (parent instanceof SQLBinaryOpExpr) {
handleAnySubQuery((SQLBinaryOpExpr) parent, x.getSubQuery().getQuery(), false);
} else {
throw new MySQLOutPutException(ErrorCode.ER_OPTIMIZER, "",
"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 all");
}
}
@Override
public void endVisit(SQLExistsExpr x) {
// TODO
throw new MySQLOutPutException(ErrorCode.ER_OPTIMIZER, "", "not supported exists!");
SQLSelectQuery sqlSelect = x.getSubQuery().getQuery();
item = new ItemExistsSubQuery(currentDb, sqlSelect, x.isNot());
}
@Override
@@ -669,7 +695,43 @@ public class MySQLItemVisitor extends MySqlASTVisitorAdapter {
@Override
public void endVisit(SQLSelectStatement node) {
SQLSelectQuery sqlSelect = node.getSelect().getQuery();
item = new ItemSinglerowSubselect(currentDb, sqlSelect);
item = new ItemScalarSubQuery(currentDb, sqlSelect);
}
private void handleAnySubQuery(SQLBinaryOpExpr parent, SQLSelectQuery sqlSelect, boolean isAll) {
SQLBinaryOperator operator = parent.getOperator();
switch (operator) {
case Equality:
if (isAll) {
item = new ItemAllAnySubQuery(currentDb, operator, sqlSelect, true);
} else {
Item left = getItem(parent.getLeft());
item = new ItemInSubQuery(currentDb, left, sqlSelect, false);
}
break;
case NotEqual:
case LessThanOrGreater:
if (isAll) {
Item left = getItem(parent.getLeft());
item = new ItemInSubQuery(currentDb, left, sqlSelect, true);
} else {
item = new ItemAllAnySubQuery(currentDb, operator, sqlSelect, false);
}
break;
case LessThan:
case LessThanOrEqual:
case GreaterThan:
case GreaterThanOrEqual:
item = new ItemAllAnySubQuery(currentDb, operator, sqlSelect, isAll);
break;
default:
throw new MySQLOutPutException(ErrorCode.ER_OPTIMIZER, "",
"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 all");
}
}
private CastType getCastType(SQLDataTypeImpl dataTypeImpl) {
@@ -13,6 +13,7 @@ import com.actiontech.dble.plan.common.item.Item;
import com.actiontech.dble.plan.common.item.ItemField;
import com.actiontech.dble.plan.common.item.function.operator.cmpfunc.ItemFuncEqual;
import com.actiontech.dble.plan.common.item.function.operator.logic.ItemCondAnd;
import com.actiontech.dble.plan.common.item.subquery.ItemScalarSubQuery;
import com.actiontech.dble.plan.node.*;
import com.actiontech.dble.plan.util.FilterUtils;
import com.actiontech.dble.util.StringUtil;
@@ -21,7 +22,6 @@ import com.alibaba.druid.sql.ast.*;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr;
import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr;
import com.alibaba.druid.sql.ast.expr.SQLQueryExpr;
import com.alibaba.druid.sql.ast.statement.*;
import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlOrderingExpr;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock;
@@ -139,7 +139,7 @@ public class MySQLPlanNodeVisitor {
}
public boolean visit(SQLExprTableSource tableSource) {
PlanNode table = null;
PlanNode table;
SQLExpr expr = tableSource.getExpr();
if (expr instanceof SQLPropertyExpr) {
SQLPropertyExpr propertyExpr = (SQLPropertyExpr) expr;
@@ -248,19 +248,13 @@ public class MySQLPlanNodeVisitor {
this.tableNode.setSubQuery(true);
if (subQueryTables.getAlias() != null) {
tableNode.alias(subQueryTables.getAlias());
if (tableNode.getSubAlias() == null) {
if (tableNode.getSubAlias() == null && tableNode.type() == PlanNode.PlanNodeType.TABLE && !tableNode.isSubQuery()) {
tableNode.setSubAlias(tableNode.getAlias());
}
}
return true;
}
public boolean visit(SQLSelect node) {
MySQLPlanNodeVisitor mtv = new MySQLPlanNodeVisitor(this.currentDb, this.charsetIndex);
mtv.visit(node);
this.tableNode = mtv.getTableNode();
return true;
}
public void visit(SQLTableSource tables) {
if (tables instanceof SQLExprTableSource) {
@@ -290,12 +284,14 @@ public class MySQLPlanNodeVisitor {
List<Item> selectItems = new ArrayList<>();
for (SQLSelectItem item : items) {
SQLExpr expr = item.getExpr();
if (expr instanceof SQLQueryExpr)
throw new RuntimeException("query statement as column is not supported!");
MySQLItemVisitor ev = new MySQLItemVisitor(currentDb, this.charsetIndex);
expr.accept(ev);
Item selItem = ev.getItem();
if (selItem instanceof ItemScalarSubQuery) {
((ItemScalarSubQuery) selItem).setField(true);
tableNode.getSubQueries().add((ItemScalarSubQuery) selItem);
tableNode.setSubQuery(true);
}
selItem.setAlias(item.getAlias());
selectItems.add(selItem);
}
@@ -306,9 +302,12 @@ public class MySQLPlanNodeVisitor {
MySQLItemVisitor mev = new MySQLItemVisitor(this.currentDb, this.charsetIndex);
whereExpr.accept(mev);
if (this.tableNode != null) {
Item whereFiler = mev.getItem();
tableNode.query(whereFiler);
// this.tableNode.setWhereFilter(tableNode.getWhereFilter());
Item whereFilter = mev.getItem();
tableNode.query(whereFilter);
if (whereFilter.isWithSubQuery()) {
tableNode.setSubQuery(true);
tableNode.setCorrelatedSubQuery(whereFilter.isCorrelatedSubQuery());
}
} else {
throw new MySQLOutPutException(ErrorCode.ER_OPTIMIZER, "", "from expression is null,check the sql!");
}
@@ -359,9 +358,9 @@ public class MySQLPlanNodeVisitor {
private void handleLimit(SQLLimit limit) {
long from = 0;
SQLExpr offest = limit.getOffset();
if (offest != null) {
SQLIntegerExpr offsetExpr = (SQLIntegerExpr) offest;
SQLExpr offset = limit.getOffset();
if (offset != null) {
SQLIntegerExpr offsetExpr = (SQLIntegerExpr) offset;
from = offsetExpr.getNumber().longValue();
}
SQLExpr rowCount = limit.getRowCount();
@@ -81,28 +81,28 @@ public class ServerSchemaStatVisitor extends MySqlSchemaStatVisitor {
@Override
public boolean visit(SQLExistsExpr x) {
super.visit(x);
notSupportMsg = "Subqueries with EXISTS or NOT EXISTS is not supported";
hasSubQuery = true;
return true;
}
@Override
public boolean visit(SQLAllExpr x) {
super.visit(x);
notSupportMsg = "Subqueries with All is not supported";
hasSubQuery = true;
return true;
}
@Override
public boolean visit(SQLSomeExpr x) {
super.visit(x);
notSupportMsg = "Subqueries with Some is not supported";
hasSubQuery = true;
return true;
}
@Override
public boolean visit(SQLAnyExpr x) {
super.visit(x);
notSupportMsg = "Subqueries with Any is not supported";
hasSubQuery = true;
return true;
}
@@ -5,7 +5,7 @@
package com.actiontech.dble.route.parser.druid.impl;
import com.actiontech.dble.DbleServer;
import com.actiontech.dble.server.variables.SystemVariables;
import com.actiontech.dble.cache.LayerCachePool;
import com.actiontech.dble.config.model.SchemaConfig;
import com.actiontech.dble.route.RouteResultset;
@@ -83,7 +83,7 @@ public class DefaultDruidParser implements DruidParser {
for (Map.Entry<String, String> entry : originTableAliasMap.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
if (DbleServer.getInstance().getConfig().getSystem().isLowerCaseTableNames()) {
if (SystemVariables.getSysVars().isLowerCaseTableNames()) {
if (key != null) {
key = key.toLowerCase();
}
@@ -130,7 +130,7 @@ public class DefaultDruidParser implements DruidParser {
if (checkConditionValues(values)) {
String columnName = StringUtil.removeBackQuote(condition.getColumn().getName().toUpperCase());
String tableName = StringUtil.removeBackQuote(condition.getColumn().getTable());
if (DbleServer.getInstance().getConfig().getSystem().isLowerCaseTableNames()) {
if (SystemVariables.getSysVars().isLowerCaseTableNames()) {
tableName = tableName.toLowerCase();
}
if (tableAliasMap != null && tableAliasMap.get(tableName) == null) {
@@ -152,7 +152,7 @@ public class DruidInsertParser extends DefaultDruidParser {
// try to route by ER parent partion key
RouteResultset theRrs = ReplaceInsertUtil.routeByERParentKey(rrs, tc, realVal);
if (theRrs != null) {
rrs.setFinishedRoute(true);
theRrs.setFinishedRoute(true);
return theRrs;
}
// route by sql query root parent's datanode
@@ -5,7 +5,7 @@
package com.actiontech.dble.route.parser.druid.impl;
import com.actiontech.dble.DbleServer;
import com.actiontech.dble.server.variables.SystemVariables;
import com.actiontech.dble.config.model.SchemaConfig;
import com.actiontech.dble.config.model.TableConfig;
import com.actiontech.dble.route.RouteResultset;
@@ -58,7 +58,7 @@ public class DruidLockTableParser extends DefaultDruidParser {
}
MySqlLockTableStatement lockTableStat = (MySqlLockTableStatement) stmt;
String table = lockTableStat.getTableSource().toString();
if (DbleServer.getInstance().getConfig().getSystem().isLowerCaseTableNames()) {
if (SystemVariables.getSysVars().isLowerCaseTableNames()) {
table = table.toLowerCase();
}
TableConfig tableConfig = schema.getTables().get(table);
@@ -30,7 +30,6 @@ import com.actiontech.dble.server.util.SchemaUtil.SchemaInfo;
import com.actiontech.dble.sqlengine.mpp.ColumnRoutePair;
import com.actiontech.dble.sqlengine.mpp.HavingCols;
import com.actiontech.dble.util.StringUtil;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.*;
import com.alibaba.druid.sql.ast.expr.*;
import com.alibaba.druid.sql.ast.statement.*;
@@ -66,9 +65,17 @@ public class DruidSelectParser extends DefaultDruidParser {
if (mysqlSelectQuery.getInto() != null) {
throw new SQLNonTransientException("select ... into is not supported!");
}
checkSelectList(mysqlSelectQuery);
SQLTableSource mysqlFrom = mysqlSelectQuery.getFrom();
if (mysqlFrom == null) {
List<SQLSelectItem> selectList = mysqlSelectQuery.getSelectList();
for (SQLSelectItem item : selectList) {
SQLExpr itemExpr = item.getExpr();
if (itemExpr instanceof SQLQueryExpr) {
rrs.setSqlStatement(selectStmt);
rrs.setNeedOptimizer(true);
return schema;
}
}
RouterUtil.routeNoNameTableToSingleNode(rrs, schema);
return schema;
}
@@ -138,14 +145,6 @@ public class DruidSelectParser extends DefaultDruidParser {
return schema;
}
private void checkSelectList(MySqlSelectQueryBlock mysqlSelectQuery) throws SQLNonTransientException {
for (SQLSelectItem item : mysqlSelectQuery.getSelectList()) {
if (item.getExpr() instanceof SQLQueryExpr) {
throw new SQLNonTransientException("query statement as column is not supported!");
}
}
}
private boolean matchSysTable(RouteResultset rrs, ServerConnection sc, SchemaInfo schemaInfo) {
// support PhpAdmin
//TODO:refactor INFORMATION_SCHEMA,MYSQL
@@ -192,7 +191,10 @@ public class DruidSelectParser extends DefaultDruidParser {
List<SQLSelectItem> selectList = mysqlSelectQuery.getSelectList();
for (SQLSelectItem item : selectList) {
SQLExpr itemExpr = item.getExpr();
if (itemExpr instanceof SQLAggregateExpr) {
if (itemExpr instanceof SQLQueryExpr) {
rrs.setNeedOptimizer(true);
return;
} else if (itemExpr instanceof SQLAggregateExpr) {
/*
* MAX,MIN; SUM,COUNT without distinct is not need optimize, but
* there is bugs in default Aggregate IN FACT ,ONLY:
@@ -477,10 +479,9 @@ public class DruidSelectParser extends DefaultDruidParser {
if (isNeedAddLimit) {
SQLLimit limit = new SQLLimit();
limit.setRowCount(new SQLIntegerExpr(limitSize));
String strLimit = SQLUtils.toMySqlString(limit);
mysqlSelectQuery.setLimit(limit);
rrs.setLimitSize(limitSize);
String sql = rrs.getStatement() + " " + strLimit;
String sql = getSql(rrs, stmt, isNeedAddLimit, schema.getName());
rrs.changeNodeSqlAfterAddLimit(sql, 0, limitSize);
}
@@ -512,10 +513,9 @@ public class DruidSelectParser extends DefaultDruidParser {
}
}
String strLimit = SQLUtils.toMySqlString(changedLimit);
mysqlSelectQuery.setLimit(changedLimit);
int iLimit = rrs.getStatement().toLowerCase().lastIndexOf("limit");
String sql = rrs.getStatement().substring(0, iLimit) + strLimit;
String sql = getSql(rrs, stmt, isNeedAddLimit, schema.getName());
rrs.changeNodeSqlAfterAddLimit(sql, 0, limitStart + limitSize);
} else {
rrs.changeNodeSqlAfterAddLimit(rrs.getStatement(), rrs.getLimitStart(), rrs.getLimitSize());
@@ -577,6 +577,15 @@ public class DruidSelectParser extends DefaultDruidParser {
return map;
}
protected String getSql(RouteResultset rrs, SQLStatement stmt, boolean isNeedAddLimit, String schema) {
if ((isNeedChangeLimit(rrs) || isNeedAddLimit)) {
return RouterUtil.removeSchema(stmt.toString(), schema);
}
return rrs.getStatement();
}
private boolean isNeedChangeLimit(RouteResultset rrs) {
if (rrs.getNodes() == null) {
return false;
@@ -22,6 +22,7 @@ import com.actiontech.dble.server.ServerConnection;
import com.actiontech.dble.server.parser.ServerParse;
import com.actiontech.dble.server.util.SchemaUtil;
import com.actiontech.dble.server.util.SchemaUtil.SchemaInfo;
import com.actiontech.dble.server.variables.SystemVariables;
import com.actiontech.dble.sqlengine.mpp.ColumnRoutePair;
import com.actiontech.dble.sqlengine.mpp.LoadData;
import com.actiontech.dble.util.StringUtil;
@@ -36,6 +37,8 @@ import java.sql.SQLException;
import java.sql.SQLNonTransientException;
import java.util.*;
import static com.actiontech.dble.plan.optimizer.JoinStrategyProcessor.NEED_REPLACE;
/**
* ServerRouterUtil
*
@@ -48,7 +51,7 @@ public final class RouterUtil {
private static final Logger LOGGER = LoggerFactory.getLogger(RouterUtil.class);
public static String removeSchema(String stmt, String schema) {
return removeSchema(stmt, schema, DbleServer.getInstance().getConfig().getSystem().isLowerCaseTableNames());
return removeSchema(stmt, schema, SystemVariables.getSysVars().isLowerCaseTableNames());
}
/**
@@ -143,11 +146,15 @@ public final class RouterUtil {
SortedSet<RouteResultsetNode> nodeSet = new TreeSet<>();
for (RouteCalculateUnit unit : druidParser.getCtx().getRouteCalculateUnits()) {
RouteResultset rrsTmp = RouterUtil.tryRouteForTables(schema, druidParser.getCtx(), unit, rrs, isSelect(statement), cachePool);
if (rrsTmp != null) {
if (rrsTmp != null && rrsTmp.getNodes() != null) {
Collections.addAll(nodeSet, rrsTmp.getNodes());
if (rrsTmp.isGlobalTable()) {
break;
}
}
}
RouteResultsetNode[] nodes = new RouteResultsetNode[nodeSet.size()];
int i = 0;
for (RouteResultsetNode aNodeSet : nodeSet) {
@@ -289,7 +296,7 @@ public final class RouterUtil {
public static String lowerCaseTable(String tableName) {
if (DbleServer.getInstance().getConfig().getSystem().isLowerCaseTableNames()) {
if (SystemVariables.getSysVars().isLowerCaseTableNames()) {
return tableName.toLowerCase();
}
return tableName;
@@ -575,7 +582,7 @@ public final class RouterUtil {
//router for shard-ing tables
for (Map.Entry<String, Map<String, Set<ColumnRoutePair>>> entry : tablesAndConditions.entrySet()) {
String tableName = entry.getKey();
if (DbleServer.getInstance().getConfig().getSystem().isLowerCaseTableNames()) {
if (SystemVariables.getSysVars().isLowerCaseTableNames()) {
tableName = tableName.toLowerCase();
}
if (tableName.startsWith(schema.getName() + ".")) {
@@ -634,9 +641,12 @@ public final class RouterUtil {
for (ColumnRoutePair pair : partitionValue) {
AbstractPartitionAlgorithm algorithm = tableConfig.getRule().getRuleAlgorithm();
if (pair.colValue != null) {
if (NEED_REPLACE.equals(pair.colValue)) {
return;
}
Integer nodeIndex = algorithm.calculate(pair.colValue);
if (nodeIndex == null) {
String msg = "can't find any valid datanode :" + tableConfig.getName() +
String msg = "can't find any valid data node :" + tableConfig.getName() +
" -> " + tableConfig.getPartitionColumn() + " -> " + pair.colValue;
LOGGER.warn(msg);
throw new SQLNonTransientException(msg);
@@ -220,6 +220,12 @@ public class NonBlockingSession implements Session {
LOGGER.warn(String.valueOf(source) + " execute plan is : " + node, e);
this.terminate();
source.writeErrMessage(ErrorCode.ER_NO_VALID_CONNECTION, "no valid connection");
} catch (MySQLOutPutException e) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info(String.valueOf(source) + " execute plan is : " + node, e);
}
this.terminate();
source.writeErrMessage(e.getSqlState(), e.getMessage(), e.getErrorCode());
} catch (Exception e) {
LOGGER.warn(String.valueOf(source) + " execute plan is : " + node, e);
this.terminate();
@@ -232,6 +238,9 @@ public class NonBlockingSession implements Session {
MySQLPlanNodeVisitor visitor = new MySQLPlanNodeVisitor(this.getSource().getSchema(), this.getSource().getCharset().getResultsIndex());
visitor.visit(ast);
PlanNode node = visitor.getTableNode();
if (node.isCorrelatedSubQuery()) {
throw new MySQLOutPutException(ErrorCode.ER_UNKNOWN_ERROR, "", "Correlated Subqueries is not supported ");
}
node.setSql(rrs.getStatement());
node.setUpFields();
checkTablesPrivilege(node, ast);
@@ -253,8 +262,13 @@ public class NonBlockingSession implements Session {
}
public void onQueryError(byte[] message) {
if (outputHandler != null)
if (outputHandler != null) {
outputHandler.backendConnError(message);
} else {
if (LOGGER.isDebugEnabled()) {
source.close(new String(message));
}
}
}
private CommitNodesHandler createCommitNodesHandler() {
@@ -1,202 +0,0 @@
/*
* Copyright (C) 2016-2017 ActionTech.
* License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher.
*/
package com.actiontech.dble.server;
import com.actiontech.dble.util.StringUtil;
import java.util.HashMap;
import java.util.Map;
public final class SystemVariables {
private SystemVariables() {
}
private static Map<String, String> sessionVariables = new HashMap<>();
static {
//some may not useful for middle-ware
sessionVariables.put("audit_log_current_session", "0");
sessionVariables.put("audit_log_filter_id", "0");
sessionVariables.put("auto_increment_increment", "1");
sessionVariables.put("auto_increment_offset", "1");
sessionVariables.put("autocommit", "1");
sessionVariables.put("big_tables", "0");
sessionVariables.put("binlog_direct_non_transactional_updates", "0");
sessionVariables.put("binlog_error_action", "IGNORE_ERROR");
sessionVariables.put("binlog_format", "ROW");
sessionVariables.put("binlog_row_image", "FULL");
sessionVariables.put("binlog_rows_query_log_events", "0");
sessionVariables.put("binlogging_impossible_mode", "IGNORE_ERROR");
sessionVariables.put("block_encryption_mode", "aes-128-ecb");
sessionVariables.put("bulk_insert_buffer_size", "8388608");
sessionVariables.put("character_set_client", "utf8");
sessionVariables.put("character_set_connection", "utf8");
sessionVariables.put("character_set_database", "utf8");
sessionVariables.put("character_set_filesystem", "binary");
sessionVariables.put("character_set_results", "utf8");
sessionVariables.put("character_set_server", "utf8");
sessionVariables.put("collation_connection", "utf8_general_ci");
sessionVariables.put("collation_database", "utf8_general_ci");
sessionVariables.put("collation_server", "utf8_general_ci");
sessionVariables.put("completion_type", "NO_CHAIN");
sessionVariables.put("debug", "d:t:i:o,/tmp/mysqld.trace");
sessionVariables.put("debug_sync", "0");
sessionVariables.put("default_storage_engine", "InnoDB");
sessionVariables.put("default_tmp_storage_engine", "InnoDB");
sessionVariables.put("default_week_format", "0");
sessionVariables.put("disconnect_on_expired_password", "1");
sessionVariables.put("div_precision_increment", "4");
sessionVariables.put("end_markers_in_json", "0");
sessionVariables.put("eq_range_index_dive_limit", "10");
sessionVariables.put("error_count", "0");
sessionVariables.put("explicit_defaults_for_timestamp", "0");
sessionVariables.put("external_user", "NULL");
sessionVariables.put("foreign_key_checks", "1");
sessionVariables.put("group_concat_max_len", "1024");
sessionVariables.put("gtid_next", "AUTOMATIC");
sessionVariables.put("gtid_owned", "NULL");
sessionVariables.put("identity", "0");
sessionVariables.put("innodb_create_intrinsic", "0");
sessionVariables.put("innodb_ft_user_stopword_table", "NULL");
sessionVariables.put("innodb_lock_wait_timeout", "50");
sessionVariables.put("innodb_optimize_point_storage", "0");
sessionVariables.put("innodb_strict_mode", "0");
sessionVariables.put("innodb_support_xa", "1");
sessionVariables.put("innodb_table_locks", "1");
sessionVariables.put("innodb_tmpdir", "NULL");
sessionVariables.put("insert_id", "0");
sessionVariables.put("interactive_timeout", "28800");
sessionVariables.put("join_buffer_size", "262144");
sessionVariables.put("keep_files_on_create", "0");
sessionVariables.put("last_insert_id", "0");
sessionVariables.put("lc_messages", "en_US");
sessionVariables.put("lc_time_names", "en_US");
sessionVariables.put("lock_wait_timeout", "31536000");
sessionVariables.put("long_query_time", "10");
sessionVariables.put("low_priority_updates", "0");
sessionVariables.put("max_allowed_packet", "4194304");
sessionVariables.put("max_delayed_threads", "20");
sessionVariables.put("max_error_count", "64");
sessionVariables.put("max_execution_time", "0");
sessionVariables.put("max_heap_table_size", "16777216");
sessionVariables.put("max_insert_delayed_threads", "20");
sessionVariables.put("max_join_size", String.valueOf(Long.MAX_VALUE));
sessionVariables.put("max_length_for_sort_data", "1024");
sessionVariables.put("max_seeks_for_key", String.valueOf(Long.MAX_VALUE));
sessionVariables.put("max_sort_length", "1024");
sessionVariables.put("max_sp_recursion_depth", "0");
sessionVariables.put("max_statement_time", "0");
//max_tmp_tables This variable is unused. It is deprecated and is removed in MySQL 8.0
sessionVariables.put("max_user_connections", "0");
sessionVariables.put("min_examined_row_limit", "0");
//multi_range_count This variable has no effect. It is deprecated and is removed in MySQL 8.0.
sessionVariables.put("myisam_repair_threads", "1");
sessionVariables.put("myisam_sort_buffer_size", "8388608");
sessionVariables.put("myisam_stats_method", "nulls_unequal");
sessionVariables.put("ndb-allow-copying-alter-table", "0");
sessionVariables.put("ndb_autoincrement_prefetch_sz", "32");
sessionVariables.put("ndb-blob-read-batch-bytes", "65536");
sessionVariables.put("ndb-blob-write-batch-bytes", "65536");
sessionVariables.put("ndb_deferred_constraints", "0");
sessionVariables.put("ndb_force_send", "1");
sessionVariables.put("ndb_fully_replicated", "0");
sessionVariables.put("ndb_index_stat_enable", "1");
sessionVariables.put("ndb_index_stat_option", "NULL");
sessionVariables.put("ndb_join_pushdown", "1");
sessionVariables.put("ndb_log_bin", "1");
sessionVariables.put("ndb_log_bin", "0");
sessionVariables.put("ndb_table_no_logging", "0");
sessionVariables.put("ndb_table_temporary", "0");
sessionVariables.put("ndb_use_copying_alter_table", "0");
sessionVariables.put("ndb_use_exact_count", "0");
sessionVariables.put("ndb_use_transactions", "1");
sessionVariables.put("ndbinfo_max_bytes", "0");
sessionVariables.put("ndbinfo_max_rows", "10");
sessionVariables.put("ndbinfo_show_hidden", "0");
sessionVariables.put("ndbinfo_table_prefix", "ndb$");
sessionVariables.put("net_buffer_length", "16384");
sessionVariables.put("net_read_timeout", "30");
sessionVariables.put("net_retry_count", "10");
sessionVariables.put("net_write_timeout", "60");
sessionVariables.put("new", "0");
sessionVariables.put("old_alter_table", "0");
sessionVariables.put("old_passwords", "0");
sessionVariables.put("optimizer_prune_level", "1");
sessionVariables.put("optimizer_search_depth", "62");
sessionVariables.put("optimizer_switch", "index_merge=on,index_merge_union=on," +
"index_merge_sort_union=on,index_merge_intersection=on," +
"engine_condition_pushdown=on,index_condition_pushdown=on," +
"mrr=on,mrr_cost_based=on,block_nested_loop=on,batched_key_access=off," +
"materialization=on,semijoin=on,loosescan=on,firstmatch=on," +
"subquery_materialization_cost_based=on,use_index_extensions=on");
sessionVariables.put("optimizer_trace", "enabled=off,one_line=off");
sessionVariables.put("optimizer_trace_features", "greedy_search=on,range_optimizer=on,dynamic_range=on,repeated_subselect=on");
sessionVariables.put("optimizer_trace_limit", "1");
sessionVariables.put("optimizer_trace_max_mem_size", "16384");
sessionVariables.put("optimizer_trace_offset", "-1");
sessionVariables.put("parser_max_mem_size", String.valueOf(Long.MAX_VALUE));
sessionVariables.put("preload_buffer_size", "32768");
sessionVariables.put("profiling", "0");
sessionVariables.put("profiling_history_size", "15");
sessionVariables.put("proxy_user", "NULL");
sessionVariables.put("pseudo_slave_mode", "0");
sessionVariables.put("pseudo_thread_id", "11");
sessionVariables.put("query_alloc_block_size", "8192");
sessionVariables.put("query_cache_type", "0");
sessionVariables.put("query_cache_wlock_invalidate", "0");
sessionVariables.put("query_prealloc_size", "8192");
sessionVariables.put("rand_seed1", "0");
sessionVariables.put("rand_seed2", "0");
sessionVariables.put("range_alloc_block_size", "4096");
sessionVariables.put("range_optimizer_max_mem_size", "8388608");
sessionVariables.put("rbr_exec_mode", "AUTOMATIC");
sessionVariables.put("read_buffer_size", "131072");
sessionVariables.put("read_rnd_buffer_size", "262144");
sessionVariables.put("session_track_gtids", "0");
sessionVariables.put("session_track_schema", "1");
sessionVariables.put("session_track_state_change", "0");
sessionVariables.put("session_track_system_variables", "time_zone, autocommit, character_set_client, character_set_results, character_set_connection");
sessionVariables.put("show_old_temporals", "0");
sessionVariables.put("sort_buffer_size", "262144");
sessionVariables.put("sql_auto_is_null", "0");
sessionVariables.put("sql_big_selects", "1");
sessionVariables.put("sql_buffer_result", "0");
sessionVariables.put("sql_log_bin", "1");
sessionVariables.put("sql_log_off", "0");
sessionVariables.put("sql_mode", "IGNORE_SPACE");
sessionVariables.put("sql_notes", "1");
sessionVariables.put("sql_quote_show_create", "1");
sessionVariables.put("sql_safe_updates", "0");
sessionVariables.put("sql_select_limit", String.valueOf(Long.MAX_VALUE));
sessionVariables.put("sql_warnings", "0");
sessionVariables.put("storage_engine", "InnoDB");
sessionVariables.put("thread_pool_high_priority_connection", "0");
sessionVariables.put("thread_pool_prio_kickup_timer", "1000");
sessionVariables.put("time_zone", "SYSTEM");
sessionVariables.put("timestamp", String.valueOf(System.currentTimeMillis()));
sessionVariables.put("tmp_table_size", "16777216");
sessionVariables.put("transaction_alloc_block_size", "8192");
sessionVariables.put("transaction_allow_batching", "0");
sessionVariables.put("transaction_prealloc_size", "4096");
sessionVariables.put("transaction_write_set_extraction", "0");
sessionVariables.put("tx_isolation", "REPEATABLE-READ"); //transaction-isolation
sessionVariables.put("tx_read_only", "0"); // OFF|0|false //transaction-read-only
sessionVariables.put("unique_checks", "1"); // ON|1|TRUE
sessionVariables.put("updatable_views_with_limit", "1"); // ON|1|TRUE
sessionVariables.put("version_tokens_session", "NULL");
sessionVariables.put("version_tokens_session_number", "0");
sessionVariables.put("wait_timeout", "28800");
sessionVariables.put("warning_count", "0");
}
public static String getDefaultValue(String variable) {
if (StringUtil.isEmpty(variable))
return null;
return sessionVariables.get(variable.toLowerCase());
}
}
@@ -7,6 +7,7 @@ package com.actiontech.dble.server.handler;
import com.actiontech.dble.DbleServer;
import com.actiontech.dble.backend.mysql.PacketUtil;
import com.actiontech.dble.backend.mysql.nio.handler.builder.BaseHandlerBuilder;
import com.actiontech.dble.backend.mysql.nio.handler.builder.HandlerBuilder;
import com.actiontech.dble.backend.mysql.nio.handler.query.DMLResponseHandler;
import com.actiontech.dble.backend.mysql.nio.handler.query.impl.*;
@@ -14,6 +15,9 @@ import com.actiontech.dble.backend.mysql.nio.handler.query.impl.groupby.DirectGr
import com.actiontech.dble.backend.mysql.nio.handler.query.impl.groupby.OrderedGroupByHandler;
import com.actiontech.dble.backend.mysql.nio.handler.query.impl.join.JoinHandler;
import com.actiontech.dble.backend.mysql.nio.handler.query.impl.join.NotInHandler;
import com.actiontech.dble.backend.mysql.nio.handler.query.impl.subquery.AllAnySubQueryHandler;
import com.actiontech.dble.backend.mysql.nio.handler.query.impl.subquery.InSubQueryHandler;
import com.actiontech.dble.backend.mysql.nio.handler.query.impl.subquery.SingleRowSubQueryHandler;
import com.actiontech.dble.config.ErrorCode;
import com.actiontech.dble.config.Fields;
import com.actiontech.dble.config.model.SchemaConfig;
@@ -114,30 +118,76 @@ public final class ExplainHandler {
}
private static List<String[]> getComplexQueryResult(RouteResultset rrs, ServerConnection c) {
List<String[]> result = new ArrayList<>();
DMLResponseHandler endHandler = buildNode(rrs, c);
Map<DMLResponseHandler, RefHandlerInfo> handlerMap = new HashMap<>();
Map<String, RefHandlerInfo> refMap = new HashMap<>();
int mergeCnt = 0;
List<BaseHandlerBuilder> builderList = getBaseHandlerBuilders(rrs, c);
Map<String, Integer> nameMap = new HashMap<>();
List<String[]> result = new ArrayList<>();
Map<BaseHandlerBuilder, String> builderNameMap = new HashMap<>();
for (int i = builderList.size() - 1; i >= 0; i--) {
BaseHandlerBuilder tmpBuilder = builderList.get(i);
Set<String> subQueries = new LinkedHashSet<>();
for (BaseHandlerBuilder childBuilder : tmpBuilder.getSubQueryBuilderList()) {
subQueries.add(builderNameMap.get(childBuilder));
}
String subQueryRootName = buildResultByEndHandler(subQueries, result, tmpBuilder.getEndHandler(), nameMap);
builderNameMap.put(tmpBuilder, subQueryRootName);
}
return result;
}
private static List<BaseHandlerBuilder> getBaseHandlerBuilders(RouteResultset rrs, ServerConnection c) {
BaseHandlerBuilder builder = buildNodes(rrs, c);
Queue<BaseHandlerBuilder> queue = new LinkedList<>();
queue.add(builder);
List<BaseHandlerBuilder> builderList = new ArrayList<>();
while (queue.size() > 0) {
BaseHandlerBuilder rootBuilder = queue.poll();
builderList.add(rootBuilder);
if (rootBuilder.getSubQueryBuilderList().size() > 0) {
queue.addAll(rootBuilder.getSubQueryBuilderList());
}
}
return builderList;
}
private static String buildResultByEndHandler(Set<String> subQueries, List<String[]> result, DMLResponseHandler endHandler, Map<String, Integer> nameMap) {
Map<String, RefHandlerInfo> refMap = new HashMap<>();
String rootName = buildHandlerTree(endHandler, refMap, new HashMap<DMLResponseHandler, RefHandlerInfo>(), nameMap, subQueries);
List<RefHandlerInfo> resultList = new ArrayList<>(refMap.size());
getDFSHandlers(refMap, rootName, resultList);
for (int i = resultList.size() - 1; i >= 0; i--) {
RefHandlerInfo handlerInfo = resultList.get(i);
result.add(new String[]{handlerInfo.name, handlerInfo.type, handlerInfo.getRefOrSQL()});
}
return rootName;
}
private static String buildHandlerTree(DMLResponseHandler endHandler, Map<String, RefHandlerInfo> refMap, Map<DMLResponseHandler, RefHandlerInfo> handlerMap, Map<String, Integer> nameMap, Set<String> dependencies) {
String rootName = null;
for (DMLResponseHandler startHandler : endHandler.getMerges()) {
MultiNodeMergeHandler mergeHandler = (MultiNodeMergeHandler) startHandler;
List<BaseSelectHandler> mergeList = new ArrayList<>();
mergeList.addAll(((MultiNodeMergeHandler) startHandler).getExeHandlers());
mergeCnt++;
String mergeNode = "merge." + mergeCnt;
String mergeNode = genHandlerName("MERGE", nameMap);
RefHandlerInfo refInfo = new RefHandlerInfo(mergeNode, "MERGE");
handlerMap.put(mergeHandler, refInfo);
refMap.put(mergeNode, refInfo);
for (BaseSelectHandler exeHandler : mergeList) {
RouteResultsetNode rrss = exeHandler.getRrss();
String dateNode = rrss.getName() + "." + rrss.getMultiplexNum();
result.add(new String[]{dateNode, "BASE SQL", rrss.getStatement()});
refInfo.addChild(dateNode);
String type = "BASE SQL";
if (dependencies != null && dependencies.size() > 0) {
type += "(May No Need)";
}
RefHandlerInfo baseSQLInfo = new RefHandlerInfo(dateNode, type, rrss.getStatement());
refMap.put(dateNode, baseSQLInfo);
if (dependencies != null && dependencies.size() > 0) {
baseSQLInfo.addAllStepChildren(dependencies);
}
}
String mergeRootName = dfsHandler(mergeHandler, handlerMap, refMap, nameMap);
if (mergeCnt == 1) {
String mergeRootName = getAllNodesFromLeaf(mergeHandler, refMap, handlerMap, nameMap);
if (rootName == null) {
if (mergeRootName == null) {
rootName = mergeNode;
} else {
@@ -145,10 +195,11 @@ public final class ExplainHandler {
}
}
}
nameMap.clear();
handlerMap.clear();
return rootName;
}
private static void getDFSHandlers(Map<String, RefHandlerInfo> refMap, String rootName, List<RefHandlerInfo> resultList) {
Stack<RefHandlerInfo> stackSearch = new Stack<>();
List<RefHandlerInfo> resultList = new ArrayList<>(refMap.size());
stackSearch.push(refMap.get(rootName));
while (stackSearch.size() > 0) {
RefHandlerInfo root = stackSearch.pop();
@@ -161,14 +212,9 @@ public final class ExplainHandler {
}
}
refMap.clear();
for (int i = resultList.size() - 1; i >= 0; i--) {
RefHandlerInfo handlerInfo = resultList.get(i);
result.add(new String[]{handlerInfo.name, handlerInfo.type, handlerInfo.getChildrenNames()});
}
return result;
}
private static String dfsHandler(DMLResponseHandler handler, Map<DMLResponseHandler, RefHandlerInfo> handlerMap, Map<String, RefHandlerInfo> refMap, Map<String, Integer> nameMap) {
private static String getAllNodesFromLeaf(DMLResponseHandler handler, Map<String, RefHandlerInfo> refMap, Map<DMLResponseHandler, RefHandlerInfo> handlerMap, Map<String, Integer> nameMap) {
DMLResponseHandler nextHandler = skipSendMake(handler.getNextHandler());
String rootName = null;
while (nextHandler != null) {
@@ -185,6 +231,12 @@ public final class ExplainHandler {
} else {
handlerMap.get(nextHandler).addChild(childName);
}
if (handler instanceof TempTableHandler) {
TempTableHandler tmp = (TempTableHandler) handler;
DMLResponseHandler endHandler = tmp.getCreatedHandler();
endHandler.setNextHandler(nextHandler);
buildHandlerTree(endHandler, refMap, handlerMap, nameMap, Collections.singleton(childName + "'s RESULTS"));
}
handler = nextHandler;
nextHandler = skipSendMake(nextHandler.getNextHandler());
}
@@ -236,11 +288,17 @@ public final class ExplainHandler {
return "DIRECT_GROUP";
} else if (handler instanceof TempTableHandler) {
return "NEST_LOOP";
} else if (handler instanceof InSubQueryHandler) {
return "IN_SUB_QUERY";
} else if (handler instanceof AllAnySubQueryHandler) {
return "ALL_ANY_SUB_QUERY";
} else if (handler instanceof SingleRowSubQueryHandler) {
return "SCALAR_SUB_QUERY";
}
return "OTHER";
}
private static DMLResponseHandler buildNode(RouteResultset rrs, ServerConnection c) {
private static BaseHandlerBuilder buildNodes(RouteResultset rrs, ServerConnection c) {
SQLSelectStatement ast = (SQLSelectStatement) rrs.getSqlStatement();
MySQLPlanNodeVisitor visitor = new MySQLPlanNodeVisitor(c.getSchema(), c.getCharset().getResultsIndex());
visitor.visit(ast);
@@ -249,7 +307,7 @@ public final class ExplainHandler {
node.setUpFields();
node = MyOptimizer.optimize(node);
HandlerBuilder builder = new HandlerBuilder(node, c.getSession2());
return builder.buildNode(c.getSession2(), node);
return builder.getBuilder(c.getSession2(), node, true);
}
private static RowDataPacket getRow(RouteResultsetNode node, String charset) {
@@ -318,22 +376,39 @@ public final class ExplainHandler {
private static class RefHandlerInfo {
private String name;
private String type;
private Set<String> children = new TreeSet<>();
private String baseSQL;
private Set<String> children = new LinkedHashSet<>();
private Set<String> stepChildren = new LinkedHashSet<>();
RefHandlerInfo(String name, String type, String baseSQL) {
this(name, type);
this.baseSQL = baseSQL;
}
RefHandlerInfo(String name, String type) {
this.name = name;
this.type = type;
}
String getChildrenNames() {
String getRefOrSQL() {
StringBuilder names = new StringBuilder("");
int i = 0;
for (String child : children) {
if (i > 0) {
names.append(", ");
for (String child : stepChildren) {
if (names.length() > 0) {
names.append("; ");
}
names.append(child);
i++;
}
for (String child : children) {
if (names.length() > 0) {
names.append("; ");
}
names.append(child);
}
if (baseSQL != null) {
if (names.length() > 0) {
names.append("; ");
}
names.append(baseSQL);
}
return names.toString();
}
@@ -342,6 +417,9 @@ public final class ExplainHandler {
return children;
}
void addAllStepChildren(Set<String> dependencies) {
this.stepChildren.addAll(dependencies);
}
void addChild(String child) {
this.children.add(child);
}
@@ -6,6 +6,7 @@
package com.actiontech.dble.server.handler;
import com.actiontech.dble.DbleServer;
import com.actiontech.dble.server.variables.SystemVariables;
import com.actiontech.dble.cache.LayerCachePool;
import com.actiontech.dble.config.ErrorCode;
import com.actiontech.dble.config.model.SchemaConfig;
@@ -20,7 +21,6 @@ import com.actiontech.dble.route.parser.druid.DruidShardingParseInfo;
import com.actiontech.dble.route.parser.druid.RouteCalculateUnit;
import com.actiontech.dble.route.util.RouterUtil;
import com.actiontech.dble.server.ServerConnection;
import com.actiontech.dble.server.SystemVariables;
import com.actiontech.dble.server.parser.ServerParse;
import com.actiontech.dble.sqlengine.mpp.LoadData;
import com.actiontech.dble.util.ObjectUtil;
@@ -116,7 +116,7 @@ public final class ServerLoadDataInfileHandler implements LoadDataInfileHandler
SQLTextLiteralExpr escapedExpr = (SQLTextLiteralExpr) statement.getColumnsEscaped();
String escaped = escapedExpr == null ? "\\" : escapedExpr.getText();
loadData.setEscape(escaped);
String charset = statement.getCharset() != null ? statement.getCharset() : SystemVariables.getDefaultValue("character_set_filesystem");
String charset = statement.getCharset() != null ? statement.getCharset() : SystemVariables.getSysVars().getDefaultValue("character_set_filesystem");
loadData.setCharset(charset);
loadData.setFileName(fileName);
}
@@ -144,7 +144,7 @@ public final class ServerLoadDataInfileHandler implements LoadDataInfileHandler
schema = DbleServer.getInstance().getConfig().getSchemas().get(serverConnection.getSchema());
tableId2DataNodeCache = (LayerCachePool) DbleServer.getInstance().getCacheService().getCachePool("TableID2DataNodeCache");
tableName = statement.getTableName().getSimpleName();
if (DbleServer.getInstance().getConfig().getSystem().isLowerCaseTableNames()) {
if (SystemVariables.getSysVars().isLowerCaseTableNames()) {
tableName = tableName.toLowerCase();
}
@@ -14,7 +14,7 @@ import com.actiontech.dble.net.mysql.OkPacket;
import com.actiontech.dble.route.parser.util.Pair;
import com.actiontech.dble.route.parser.util.ParseUtil;
import com.actiontech.dble.server.ServerConnection;
import com.actiontech.dble.server.SystemVariables;
import com.actiontech.dble.server.variables.SystemVariables;
import com.actiontech.dble.sqlengine.OneRawSQLQueryResultHandler;
import com.actiontech.dble.sqlengine.SetTestJob;
import com.actiontech.dble.util.StringUtil;
@@ -231,7 +231,10 @@ public final class SetHandler {
if (!handleTxIsolationInMultiStmt(c, contextTask, valueExpr)) return false;
break;
case SYSTEM_VARIABLES:
if (SystemVariables.getDefaultValue(key) == null) {
if (key.startsWith("@@")) {
key = key.substring(2);
}
if (SystemVariables.getSysVars().getDefaultValue(key) == null) {
c.writeErrMessage(ErrorCode.ERR_NOT_SUPPORTED, "system variable " + key + " is not supported");
}
contextTask.add(new Pair<>(KeyType.SYSTEM_VARIABLES, new Pair<>(key, parseVariablesValue(valueExpr))));
@@ -361,7 +364,10 @@ public final class SetHandler {
case TX_ISOLATION:
return handleTxIsolation(c, valueExpr);
case SYSTEM_VARIABLES:
if (SystemVariables.getDefaultValue(key) == null) {
if (key.startsWith("@@")) {
key = key.substring(2);
}
if (SystemVariables.getSysVars().getDefaultValue(key) == null) {
c.writeErrMessage(ErrorCode.ERR_NOT_SUPPORTED, "system variable " + key + " is not supported");
return false;
}
@@ -575,7 +581,7 @@ public final class SetHandler {
private static boolean checkValue(SQLExpr valueExpr) {
return (valueExpr instanceof SQLCharExpr) || (valueExpr instanceof SQLIdentifierExpr) ||
(valueExpr instanceof SQLIntegerExpr);
(valueExpr instanceof SQLIntegerExpr) || (valueExpr instanceof SQLNumberExpr) || (valueExpr instanceof SQLBooleanExpr);
}
private static KeyType parseKeyType(String key, boolean origin, KeyType defaultVariables) {
@@ -623,6 +629,9 @@ public final class SetHandler {
return null;
}
return (iValue == 1);
} else if (valueExpr instanceof SQLBooleanExpr) {
SQLBooleanExpr value = (SQLBooleanExpr) valueExpr;
return value.getValue();
}
String strValue = parseStringValue(valueExpr);
switch (strValue) {
@@ -646,6 +655,12 @@ public final class SetHandler {
} else if (valueExpr instanceof SQLIntegerExpr) {
SQLIntegerExpr value = (SQLIntegerExpr) valueExpr;
strValue = value.getNumber().toString();
} else if (valueExpr instanceof SQLNumberExpr) {
SQLNumberExpr value = (SQLNumberExpr) valueExpr;
strValue = value.getNumber().toString();
} else if (valueExpr instanceof SQLBooleanExpr) {
SQLBooleanExpr value = (SQLBooleanExpr) valueExpr;
strValue = String.valueOf(value.getValue());
}
return strValue;
}
@@ -5,7 +5,7 @@
*/
package com.actiontech.dble.server.handler;
import com.actiontech.dble.DbleServer;
import com.actiontech.dble.server.variables.SystemVariables;
import com.actiontech.dble.config.ErrorCode;
import com.actiontech.dble.net.handler.FrontendPrivileges;
import com.actiontech.dble.net.mysql.OkPacket;
@@ -34,7 +34,7 @@ public final class UseHandler {
if (schema.charAt(0) == '\'' && schema.charAt(length - 1) == '\'') {
schema = schema.substring(1, length - 1);
}
if (DbleServer.getInstance().getConfig().getSystem().isLowerCaseTableNames()) {
if (SystemVariables.getSysVars().isLowerCaseTableNames()) {
schema = schema.toLowerCase();
}
}
@@ -5,7 +5,7 @@
package com.actiontech.dble.server.response;
import com.actiontech.dble.DbleServer;
import com.actiontech.dble.server.variables.SystemVariables;
import com.actiontech.dble.config.ErrorCode;
import com.actiontech.dble.route.factory.RouteStrategyFactory;
import com.actiontech.dble.server.ServerConnection;
@@ -48,7 +48,7 @@ public final class ShowColumns {
showColumnsStatement.setDatabase(null);
sql = showColumnsStatement.toString();
}
if (DbleServer.getInstance().getConfig().getSystem().isLowerCaseTableNames()) {
if (SystemVariables.getSysVars().isLowerCaseTableNames()) {
schema = StringUtil.removeBackQuote(schema).toLowerCase();
table = table.toLowerCase();
}
@@ -5,7 +5,7 @@
package com.actiontech.dble.server.response;
import com.actiontech.dble.DbleServer;
import com.actiontech.dble.server.variables.SystemVariables;
import com.actiontech.dble.config.ErrorCode;
import com.actiontech.dble.route.factory.RouteStrategyFactory;
import com.actiontech.dble.server.ServerConnection;
@@ -83,7 +83,7 @@ public final class ShowIndex {
sql.append(" ");
sql.append(strWhere);
}
if (DbleServer.getInstance().getConfig().getSystem().isLowerCaseTableNames()) {
if (SystemVariables.getSysVars().isLowerCaseTableNames()) {
schema = StringUtil.removeBackQuote(schema).toLowerCase();
table = table.toLowerCase();
}
@@ -6,6 +6,7 @@
package com.actiontech.dble.server.response;
import com.actiontech.dble.DbleServer;
import com.actiontech.dble.server.variables.SystemVariables;
import com.actiontech.dble.backend.mysql.PacketUtil;
import com.actiontech.dble.backend.mysql.nio.handler.ShowTablesHandler;
import com.actiontech.dble.backend.mysql.nio.handler.query.DMLResponseHandler;
@@ -54,7 +55,7 @@ public final class ShowTables {
return;
}
String showSchema = info.getSchema();
if (showSchema != null && DbleServer.getInstance().getConfig().getSystem().isLowerCaseTableNames()) {
if (showSchema != null && SystemVariables.getSysVars().isLowerCaseTableNames()) {
showSchema = showSchema.toLowerCase();
}
String cSchema = showSchema == null ? c.getSchema() : showSchema;
@@ -6,6 +6,7 @@
package com.actiontech.dble.server.util;
import com.actiontech.dble.DbleServer;
import com.actiontech.dble.server.variables.SystemVariables;
import com.actiontech.dble.backend.datasource.PhysicalDBNode;
import com.actiontech.dble.backend.datasource.PhysicalDBPool;
import com.actiontech.dble.backend.datasource.PhysicalDatasource;
@@ -88,7 +89,7 @@ public final class GlobalTableUtil {
for (TableConfig table : entry.getValue().getTables().values()) {
if (table.isGlobalTable()) {
String tableName = table.getName();
if (config.getSystem().isLowerCaseTableNames()) {
if (SystemVariables.getSysVars().isLowerCaseTableNames()) {
tableName = tableName.toLowerCase();
}
globalTableMap.put(entry.getKey() + "." + tableName, table);
@@ -6,6 +6,7 @@
package com.actiontech.dble.server.util;
import com.actiontech.dble.DbleServer;
import com.actiontech.dble.server.variables.SystemVariables;
import com.actiontech.dble.config.ErrorCode;
import com.actiontech.dble.config.ServerPrivileges;
import com.actiontech.dble.config.model.SchemaConfig;
@@ -69,7 +70,7 @@ public final class SchemaUtil {
String msg = "No database selected";
throw new SQLException(msg, "3D000", ErrorCode.ER_NO_DB_ERROR);
}
if (DbleServer.getInstance().getConfig().getSystem().isLowerCaseTableNames()) {
if (SystemVariables.getSysVars().isLowerCaseTableNames()) {
schemaInfo.table = schemaInfo.table.toLowerCase();
schemaInfo.schema = schemaInfo.schema.toLowerCase();
}
@@ -0,0 +1,39 @@
/*
* Copyright (C) 2016-2017 ActionTech.
* License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher.
*/
package com.actiontech.dble.server.variables;
import com.actiontech.dble.sqlengine.SQLQueryResult;
import com.actiontech.dble.sqlengine.SQLQueryResultListener;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MysqlVarsListener implements SQLQueryResultListener<SQLQueryResult<Map<String, String>>> {
private static final Logger LOGGER = LoggerFactory.getLogger(MysqlVarsListener.class);
private final VarsExtractorHandler handler;
public MysqlVarsListener(VarsExtractorHandler handler) {
this.handler = handler;
}
@Override
public void onResult(SQLQueryResult<Map<String, String>> result) {
if (!result.isSuccess()) {
//not thread safe
LOGGER.warn("Can't get variables from DataNode: " + result.getDataNode() + "!");
return;
}
/* the logic is twist */
if (!handler.isExtracting()) {
return;
}
Map<String, String> kvs = result.getResult();
handler.handleVars(kvs);
return;
}
}
@@ -0,0 +1,26 @@
/*
* Copyright (C) 2016-2017 ActionTech.
* License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher.
*/
package com.actiontech.dble.server.variables;
import com.actiontech.dble.config.ServerConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SysVarsExtractor {
private static final Logger LOGGER = LoggerFactory.getLogger(SysVarsExtractor.class);
private final ServerConfig config;
public SysVarsExtractor(ServerConfig config) {
this.config = config;
}
public void extract() {
VarsExtractorHandler handler = new VarsExtractorHandler();
handler.execute();
return;
}
}
@@ -0,0 +1,11 @@
/*
* Copyright (C) 2016-2017 ActionTech.
* License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher.
*/
package com.actiontech.dble.server.variables;
public interface SystemGlobalVariable {
void setVariable(String value, SystemVariables sys) throws RuntimeException;
String getVariable();
}
@@ -0,0 +1,271 @@
/*
* Copyright (C) 2016-2017 ActionTech.
* License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher.
*/
package com.actiontech.dble.server.variables;
import com.actiontech.dble.util.StringUtil;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public final class SystemVariables {
private static final Logger LOGGER = LoggerFactory.getLogger(SystemVariables.class);
private Map<String, SystemGlobalVariable> globalVariables;
private Map<String, String> sessionVariables;
private boolean isInited;
private static final SystemVariables INSTANCE = new SystemVariables();
public static SystemVariables getSysVars() {
return INSTANCE;
}
private SystemVariables() {
isInited = false;
globalVariables = new HashMap<>();
pickGlobalVariables();
sessionVariables = new HashMap<>();
pickSessionVariables();
}
public boolean isInited() {
return isInited;
}
public void setInited() {
if (isInited) {
LOGGER.error("System variables have been inited!");
}
isInited = true;
}
private void pickGlobalVariables() {
globalVariables.put("lower_case_table_names", new SystemGlobalVariable() {
String value = "0";
public void setVariable(String value, SystemVariables sys) throws RuntimeException {
if (sys.isInited()) {
throw new RuntimeException("lower_case_table_names is global static variable, don't been change at run time");
}
this.value = value;
}
public String getVariable() {
return value;
}
});
}
public boolean isLowerCaseTableNames() {
Integer value = Integer.valueOf(globalVariables.get("lower_case_table_names").getVariable());
return value != 0 ? true : false;
}
private void pickSessionVariables() {
//some may not useful for middle-ware
sessionVariables.put("audit_log_current_session", null);
sessionVariables.put("audit_log_filter_id", null);
sessionVariables.put("auto_increment_increment", null);
sessionVariables.put("auto_increment_offset", null);
sessionVariables.put("autocommit", null);
sessionVariables.put("big_tables", null);
sessionVariables.put("binlog_direct_non_transactional_updates", null);
sessionVariables.put("binlog_error_action", null);
sessionVariables.put("binlog_format", null);
sessionVariables.put("binlog_row_image", null);
sessionVariables.put("binlog_rows_query_log_events", null);
sessionVariables.put("binlogging_impossible_mode", null);
sessionVariables.put("block_encryption_mode", null);
sessionVariables.put("bulk_insert_buffer_size", null);
sessionVariables.put("character_set_client", null);
sessionVariables.put("character_set_connection", null);
sessionVariables.put("character_set_database", null);
sessionVariables.put("character_set_filesystem", null);
sessionVariables.put("character_set_results", null);
sessionVariables.put("character_set_server", null);
sessionVariables.put("collation_connection", null);
sessionVariables.put("collation_database", null);
sessionVariables.put("collation_server", null);
sessionVariables.put("completion_type", null);
sessionVariables.put("debug", null);
sessionVariables.put("debug_sync", null);
sessionVariables.put("default_storage_engine", null);
sessionVariables.put("default_tmp_storage_engine", null);
sessionVariables.put("default_week_format", null);
sessionVariables.put("disconnect_on_expired_password", null);
sessionVariables.put("div_precision_increment", null);
sessionVariables.put("end_markers_in_json", null);
sessionVariables.put("eq_range_index_dive_limit", null);
sessionVariables.put("error_count", null);
sessionVariables.put("explicit_defaults_for_timestamp", null);
sessionVariables.put("external_user", null);
sessionVariables.put("foreign_key_checks", null);
sessionVariables.put("group_concat_max_len", null);
sessionVariables.put("gtid_next", null);
sessionVariables.put("gtid_owned", null);
sessionVariables.put("identity", null);
sessionVariables.put("innodb_create_intrinsic", null);
sessionVariables.put("innodb_ft_user_stopword_table", null);
sessionVariables.put("innodb_lock_wait_timeout", null);
sessionVariables.put("innodb_optimize_point_storage", null);
sessionVariables.put("innodb_strict_mode", null);
sessionVariables.put("innodb_support_xa", null);
sessionVariables.put("innodb_table_locks", null);
sessionVariables.put("innodb_tmpdir", null);
sessionVariables.put("insert_id", null);
sessionVariables.put("interactive_timeout", null);
sessionVariables.put("join_buffer_size", null);
sessionVariables.put("keep_files_on_create", null);
sessionVariables.put("last_insert_id", null);
sessionVariables.put("lc_messages", null);
sessionVariables.put("lc_time_names", null);
sessionVariables.put("lock_wait_timeout", null);
sessionVariables.put("long_query_time", null);
sessionVariables.put("low_priority_updates", null);
sessionVariables.put("max_allowed_packet", null);
sessionVariables.put("max_delayed_threads", null);
sessionVariables.put("max_error_count", null);
sessionVariables.put("max_execution_time", null);
sessionVariables.put("max_heap_table_size", null);
sessionVariables.put("max_insert_delayed_threads", null);
sessionVariables.put("max_join_size", null);
sessionVariables.put("max_length_for_sort_data", null);
sessionVariables.put("max_seeks_for_key", null);
sessionVariables.put("max_sort_length", null);
sessionVariables.put("max_sp_recursion_depth", null);
sessionVariables.put("max_statement_time", null);
//max_tmp_tables This variable is unused. It is deprecated and is removed in MySQL 8.0
sessionVariables.put("max_user_connections", null);
sessionVariables.put("min_examined_row_limit", null);
//multi_range_count This variable has no effect. It is deprecated and is removed in MySQL 8.0.
sessionVariables.put("myisam_repair_threads", null);
sessionVariables.put("myisam_sort_buffer_size", null);
sessionVariables.put("myisam_stats_method", null);
sessionVariables.put("ndb-allow-copying-alter-table", null);
sessionVariables.put("ndb_autoincrement_prefetch_sz", null);
sessionVariables.put("ndb-blob-read-batch-bytes", null);
sessionVariables.put("ndb-blob-write-batch-bytes", null);
sessionVariables.put("ndb_deferred_constraints", null);
sessionVariables.put("ndb_force_send", null);
sessionVariables.put("ndb_fully_replicated", null);
sessionVariables.put("ndb_index_stat_enable", null);
sessionVariables.put("ndb_index_stat_option", null);
sessionVariables.put("ndb_join_pushdown", null);
sessionVariables.put("ndb_log_bin", null);
sessionVariables.put("ndb_log_bin", null);
sessionVariables.put("ndb_table_no_logging", null);
sessionVariables.put("ndb_table_temporary", null);
sessionVariables.put("ndb_use_copying_alter_table", null);
sessionVariables.put("ndb_use_exact_count", null);
sessionVariables.put("ndb_use_transactions", null);
sessionVariables.put("ndbinfo_max_bytes", null);
sessionVariables.put("ndbinfo_max_rows", null);
sessionVariables.put("ndbinfo_show_hidden", null);
sessionVariables.put("ndbinfo_table_prefix", null);
sessionVariables.put("net_buffer_length", null);
sessionVariables.put("net_read_timeout", null);
sessionVariables.put("net_retry_count", null);
sessionVariables.put("net_write_timeout", null);
sessionVariables.put("new", null);
sessionVariables.put("old_alter_table", null);
sessionVariables.put("old_passwords", null);
sessionVariables.put("optimizer_prune_level", null);
sessionVariables.put("optimizer_search_depth", null);
sessionVariables.put("optimizer_switch", null);
sessionVariables.put("optimizer_trace", null);
sessionVariables.put("optimizer_trace_features", null);
sessionVariables.put("optimizer_trace_limit", null);
sessionVariables.put("optimizer_trace_max_mem_size", null);
sessionVariables.put("optimizer_trace_offset", null);
sessionVariables.put("parser_max_mem_size", null);
sessionVariables.put("preload_buffer_size", null);
sessionVariables.put("profiling", null);
sessionVariables.put("profiling_history_size", null);
sessionVariables.put("proxy_user", null);
sessionVariables.put("pseudo_slave_mode", null);
sessionVariables.put("pseudo_thread_id", null);
sessionVariables.put("query_alloc_block_size", null);
sessionVariables.put("query_cache_type", null);
sessionVariables.put("query_cache_wlock_invalidate", null);
sessionVariables.put("query_prealloc_size", null);
sessionVariables.put("rand_seed1", null);
sessionVariables.put("rand_seed2", null);
sessionVariables.put("range_alloc_block_size", null);
sessionVariables.put("range_optimizer_max_mem_size", null);
sessionVariables.put("rbr_exec_mode", null);
sessionVariables.put("read_buffer_size", null);
sessionVariables.put("read_rnd_buffer_size", null);
sessionVariables.put("session_track_gtids", null);
sessionVariables.put("session_track_schema", null);
sessionVariables.put("session_track_state_change", null);
sessionVariables.put("session_track_system_variables", null);
sessionVariables.put("show_old_temporals", null);
sessionVariables.put("sort_buffer_size", null);
sessionVariables.put("sql_auto_is_null", null);
sessionVariables.put("sql_big_selects", null);
sessionVariables.put("sql_buffer_result", null);
sessionVariables.put("sql_log_bin", null);
sessionVariables.put("sql_log_off", null);
sessionVariables.put("sql_mode", null);
sessionVariables.put("sql_notes", null);
sessionVariables.put("sql_quote_show_create", null);
sessionVariables.put("sql_safe_updates", null);
sessionVariables.put("sql_select_limit", null);
sessionVariables.put("sql_warnings", null);
sessionVariables.put("storage_engine", null);
sessionVariables.put("thread_pool_high_priority_connection", null);
sessionVariables.put("thread_pool_prio_kickup_timer", null);
sessionVariables.put("time_zone", null);
sessionVariables.put("timestamp", null);
sessionVariables.put("tmp_table_size", null);
sessionVariables.put("transaction_alloc_block_size", null);
sessionVariables.put("transaction_allow_batching", null);
sessionVariables.put("transaction_prealloc_size", null);
sessionVariables.put("transaction_write_set_extraction", null);
sessionVariables.put("tx_isolation", null); //transaction-isolation
sessionVariables.put("tx_read_only", null); // OFF|0|false //transaction-read-only
sessionVariables.put("unique_checks", null); // ON|1|TRUE
sessionVariables.put("updatable_views_with_limit", null); // ON|1|TRUE
sessionVariables.put("version_tokens_session", null);
sessionVariables.put("version_tokens_session_number", null);
sessionVariables.put("wait_timeout", null);
sessionVariables.put("warning_count", null);
}
public void setDefaultValue(String variable, String value) {
if (StringUtil.isEmpty(variable))
return;
String key = variable.toLowerCase();
if (sessionVariables.containsKey(key)) {
sessionVariables.replace(key, value);
} else {
SystemGlobalVariable gv = globalVariables.get(key);
if (gv != null) {
gv.setVariable(value, this);
}
}
return;
}
public String getGlobalVarValue(String variable) {
SystemGlobalVariable gv = globalVariables.get(variable.toLowerCase());
if (gv != null) {
return gv.getVariable();
} else {
return null;
}
}
public String getDefaultValue(String variable) {
if (StringUtil.isEmpty(variable))
return null;
return sessionVariables.get(variable.toLowerCase());
}
}
@@ -0,0 +1,89 @@
/*
* Copyright (C) 2016-2017 ActionTech.
* License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher.
*/
package com.actiontech.dble.server.variables;
import com.actiontech.dble.DbleServer;
import com.actiontech.dble.backend.datasource.PhysicalDBNode;
import com.actiontech.dble.sqlengine.OneRawSQLQueryResultHandler;
import com.actiontech.dble.sqlengine.SQLJob;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class VarsExtractorHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(VarsExtractorHandler.class);
private static final String[] MYSQL_SHOW_VARIABLES_COLS = new String[]{
"Variable_name",
"Value"};
private static final String MYSQL_SHOW_VARIABLES = "show variables";
private AtomicBoolean extracting;
private Lock lock;
private Condition done;
public VarsExtractorHandler() {
this.extracting = new AtomicBoolean(false);
this.lock = new ReentrantLock();
this.done = lock.newCondition();
}
public void execute() {
Map<String, PhysicalDBNode> dataNodes = DbleServer.getInstance().getConfig().getDataNodes();
for (Map.Entry<String, PhysicalDBNode> entry : dataNodes.entrySet()) {
if (extracting.get()) {
break;
}
OneRawSQLQueryResultHandler resultHandler = new OneRawSQLQueryResultHandler(MYSQL_SHOW_VARIABLES_COLS, new MysqlVarsListener(this));
PhysicalDBNode dn = entry.getValue();
SQLJob sqlJob = new SQLJob(MYSQL_SHOW_VARIABLES, dn.getDatabase(), resultHandler, dn.getDbPool().getSource());
sqlJob.run();
}
waitDone();
}
public void handleVars(Map<String, String> vars) {
for (Map.Entry<String, String> entry : vars.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
SystemVariables.getSysVars().setDefaultValue(key, value);
}
SystemVariables.getSysVars().setInited();
signalDone();
return;
}
public boolean isExtracting() {
return extracting.compareAndSet(false, true);
}
private void signalDone() {
lock.lock();
try {
done.signal();
} finally {
lock.unlock();
}
}
private void waitDone() {
lock.lock();
try {
while (!extracting.get()) {
done.await();
}
} catch (InterruptedException e) {
LOGGER.warn("wait variables grapping done " + e);
} finally {
lock.unlock();
}
}
}
+20 -4
View File
@@ -37,6 +37,13 @@
</rule>
</tableRule>
<tableRule name="sharding-by-hash3">
<rule>
<columns>id</columns>
<algorithm>hashLong3</algorithm>
</rule>
</tableRule>
<tableRule name="sharding-by-mod">
<rule>
<columns>id</columns>
@@ -82,7 +89,7 @@
</function>
<!-- Hash partition,when partitionLength=1, it is a mod partition-->
<!--MAX(sum(count*length[i]) must not more then 1024-->
<!--MAX(sum(count*length[i]) must not more then 2880-->
<function name="hashLong" class="Hash">
<property name="partitionCount">8</property>
<property name="partitionLength">128</property>
@@ -91,7 +98,7 @@
</function>
<!-- Hash partition,when partitionLength=1, it is a mod partition-->
<!--MAX(sum(count*length[i]) must not more then 1024-->
<!--MAX(sum(count*length[i]) must not more then 2880-->
<function name="hashLong2" class="Hash">
<property name="partitionCount">2</property>
<property name="partitionLength">512</property>
@@ -99,6 +106,15 @@
<property name="partitionLength">4,5</property>-->
</function>
<!-- Hash partition,when partitionLength=1, it is a mod partition-->
<!--MAX(sum(count*length[i]) must not more then 2880-->
<function name="hashLong3" class="Hash">
<property name="partitionCount">2,1</property>
<property name="partitionLength">256,512</property>
<!-- <property name="partitionCount">2,3</property>
<property name="partitionLength">4,5</property>-->
</function>
<!-- eg: mod 4 -->
<function name="hashmod" class="Hash">
<property name="partitionCount">4</property>
@@ -117,8 +133,8 @@
<!-- 4 case:
1.set sEndDate and defaultNode: input <sBeginDate ,router to defaultNode; input>sEndDate ,mod the period
2.set sEndDate, but no defaultNode:input <sBeginDate report error; input>sEndDate ,mod the period
3.set defaultNode without sEndDate: input <sBeginDate router to defaultNode;input>sEndDate + (node size)*sPartionDay-1 will report error(expected is defaultNode,but can't control now)
4.sEndDate and defaultNode are all not set: input <sBeginDate report error;input>sEndDate + (node size)*sPartionDay-1 will report error
3.set defaultNode without sEndDate: input <sBeginDate router to defaultNode;input>sBeginDate + (node size)*sPartionDay-1 will report error(expected is defaultNode,but can't control now)
4.sEndDate and defaultNode are all not set: input <sBeginDate report error;input>sBeginDate + (node size)*sPartionDay-1 will report error
-->
<function name="partbydate"
class="Date">
+110 -89
View File
@@ -14,8 +14,6 @@ import com.alibaba.druid.sql.dialect.mysql.ast.statement.*;
import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser;
import com.alibaba.druid.sql.parser.SQLStatementParser;
import java.io.UnsupportedEncodingException;
public class Testparser {
public static void main(String args[]) {
@@ -24,95 +22,95 @@ public class Testparser {
// obj.test("CREATE TABLE `xx`.`char_columns_test` (`id` int(11) NOT NULL,`c_char` char(255) DEFAULT NULL,PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;");
// obj.test("drop table char_columns_test;");
// obj.test("truncate table char_columns_test;");
String strSetSql = "SET SESSION sql_mode = 'TRADITIONAL';";
obj.test(strSetSql);
strSetSql = "SET SESSION sql_mode = `TRADITIONAL`;";
obj.test(strSetSql);
strSetSql = "SET SESSION sql_mode = \"TRADITIONAL\";";
obj.test(strSetSql);
strSetSql = "SET names utf8;";
obj.test(strSetSql);
strSetSql = "SET names `utf8`;";
obj.test(strSetSql);
strSetSql = "SET names 'UTF8';";
obj.test(strSetSql);
strSetSql = "SET names \"UTF8\";";
obj.test(strSetSql);
strSetSql = "SET names utf8 COLLATE default;";
obj.test(strSetSql);
strSetSql = "SET names utf8 COLLATE utf8_general_ci;";
obj.test(strSetSql);
strSetSql = "SET names utf8 COLLATE `utf8_general_ci`;";
obj.test(strSetSql);
strSetSql = "SET names utf8 COLLATE 'utf8_general_ci';";
obj.test(strSetSql);
strSetSql = "SET names default;";
obj.test(strSetSql);
strSetSql = "set names utf8,@@tx_read_only =0;";
obj.test(strSetSql);
strSetSql = "set @@tx_read_only =0,names utf8;";
obj.test(strSetSql);
// String strSetSql = "SET SESSION sql_mode = 'TRADITIONAL';";
// obj.test(strSetSql);
// strSetSql = "SET SESSION sql_mode = `TRADITIONAL`;";
// obj.test(strSetSql);
// strSetSql = "SET SESSION sql_mode = \"TRADITIONAL\";";
// obj.test(strSetSql);
// strSetSql = "SET names utf8;";
// obj.test(strSetSql);
// strSetSql = "SET names `utf8`;";
// obj.test(strSetSql);
// strSetSql = "SET names 'UTF8';";
// obj.test(strSetSql);
// strSetSql = "SET names \"UTF8\";";
// obj.test(strSetSql);
// strSetSql = "SET names utf8 COLLATE default;";
// obj.test(strSetSql);
// strSetSql = "SET names utf8 COLLATE utf8_general_ci;";
// obj.test(strSetSql);
// strSetSql = "SET names utf8 COLLATE `utf8_general_ci`;";
// obj.test(strSetSql);
// strSetSql = "SET names utf8 COLLATE 'utf8_general_ci';";
// obj.test(strSetSql);
// strSetSql = "SET names default;";
// obj.test(strSetSql);
// strSetSql = "set names utf8,@@tx_read_only =0;";
// obj.test(strSetSql);
// strSetSql = "set @@tx_read_only =0,names utf8;";
// obj.test(strSetSql);
// strSetSql = "set @@tx_read_only =0,names utf8,charset utf8;";
// obj.test(strSetSql);
strSetSql = "set @@tx_read_only =0,names utf8 collation default;";
obj.test(strSetSql);
strSetSql = "set @@tx_read_only =0;";
obj.test(strSetSql);
strSetSql = "set @@GLOBAL.tx_read_only =0;";
obj.test(strSetSql);
strSetSql = "set @@Session.tx_read_only =0;";
obj.test(strSetSql);
strSetSql = "set tx_read_only =0;";
obj.test(strSetSql);
strSetSql = "set GLOBAL tx_read_only =0;";
obj.test(strSetSql);
strSetSql = "set Session tx_read_only =0;";
obj.test(strSetSql);
strSetSql = "set Session tx_isolation ='READ-COMMITTED';";
obj.test(strSetSql);
strSetSql = "set Session tx_isolation =`READ-COMMITTED`;";
obj.test(strSetSql);
strSetSql = "set Session tx_isolation =\"READ-COMMITTED\";";
obj.test(strSetSql);
// strSetSql = "set @@tx_read_only =0,names utf8 collation default;";
// obj.test(strSetSql);
// strSetSql = "set @@tx_read_only =0;";
// obj.test(strSetSql);
// strSetSql = "set @@GLOBAL.tx_read_only =0;";
// obj.test(strSetSql);
// strSetSql = "set @@Session.tx_read_only =0;";
// obj.test(strSetSql);
// strSetSql = "set tx_read_only =0;";
// obj.test(strSetSql);
// strSetSql = "set GLOBAL tx_read_only =0;";
// obj.test(strSetSql);
// strSetSql = "set Session tx_read_only =0;";
// obj.test(strSetSql);
// strSetSql = "set Session tx_isolation ='READ-COMMITTED';";
// obj.test(strSetSql);
// strSetSql = "set Session tx_isolation =`READ-COMMITTED`;";
// obj.test(strSetSql);
// strSetSql = "set Session tx_isolation =\"READ-COMMITTED\";";
// obj.test(strSetSql);
// strSetSql = "SET charset utf8;";
// obj.test(strSetSql);
strSetSql = "SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;";
obj.test(strSetSql);
strSetSql = "SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;";
obj.test(strSetSql);
strSetSql = "SET TRANSACTION ISOLATION LEVEL READ COMMITTED ;";
obj.test(strSetSql);
strSetSql = "SET TRANSACTION READ WRITE;";
obj.test(strSetSql);
strSetSql = "SET TRANSACTION read only;";
obj.test(strSetSql);
strSetSql = "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;";
obj.test(strSetSql);
strSetSql = "SET @total_tax = (SELECT SUM(tax) FROM taxable_transactions);";
obj.test(strSetSql);
strSetSql = "SET @@session.sql_mode = 'TRADITIONAL';";
obj.test(strSetSql);
strSetSql = "SET @@global.sql_mode = 'TRADITIONAL';";
obj.test(strSetSql);
strSetSql = "SET @@sql_mode = 'TRADITIONAL';";
obj.test(strSetSql);
strSetSql = "SET GLOBAL sql_log_bin = ON;";
obj.test(strSetSql);
strSetSql = "SET max_connections = 1000;";
obj.test(strSetSql);
strSetSql = "SET @x = 1;";
obj.test(strSetSql);
strSetSql = "SET @x = 1, SESSION sql_mode = '';";
obj.test(strSetSql);
strSetSql = "SET GLOBAL sort_buffer_size = 1000000, SESSION sort_buffer_size = 1000000;";
obj.test(strSetSql);
strSetSql = "SET GLOBAL max_connections = 1000, sort_buffer_size = 1000000;";
obj.test(strSetSql);
strSetSql = "SET xa =0 ;";
obj.test(strSetSql);
strSetSql = "SET xa = off ;";
obj.test(strSetSql);
// strSetSql = "SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;";
// obj.test(strSetSql);
// strSetSql = "SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;";
// obj.test(strSetSql);
// strSetSql = "SET TRANSACTION ISOLATION LEVEL READ COMMITTED ;";
// obj.test(strSetSql);
// strSetSql = "SET TRANSACTION READ WRITE;";
// obj.test(strSetSql);
// strSetSql = "SET TRANSACTION read only;";
// obj.test(strSetSql);
// strSetSql = "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;";
// obj.test(strSetSql);
// strSetSql = "SET @total_tax = (SELECT SUM(tax) FROM taxable_transactions);";
// obj.test(strSetSql);
//
// strSetSql = "SET @@session.sql_mode = 'TRADITIONAL';";
// obj.test(strSetSql);
// strSetSql = "SET @@global.sql_mode = 'TRADITIONAL';";
// obj.test(strSetSql);
// strSetSql = "SET @@sql_mode = 'TRADITIONAL';";
// obj.test(strSetSql);
// strSetSql = "SET GLOBAL sql_log_bin = ON;";
// obj.test(strSetSql);
// strSetSql = "SET max_connections = 1000;";
// obj.test(strSetSql);
// strSetSql = "SET @x = 1;";
// obj.test(strSetSql);
// strSetSql = "SET @x = 1, SESSION sql_mode = '';";
// obj.test(strSetSql);
// strSetSql = "SET GLOBAL sort_buffer_size = 1000000, SESSION sort_buffer_size = 1000000;";
// obj.test(strSetSql);
// strSetSql = "SET GLOBAL max_connections = 1000, sort_buffer_size = 1000000;";
// obj.test(strSetSql);
// strSetSql = "SET xa =0 ;";
// obj.test(strSetSql);
// strSetSql = "SET xa = off ;";
// obj.test(strSetSql);
//String strShowSql = "";
//strShowSql = "show create table a;";
//obj.test(strShowSql);
@@ -231,10 +229,18 @@ public class Testparser {
+ " from char_columns where id =1 and name = 'x';";
// obj.test(selectSQl);
// selectSQl = "select * from constant_one where id > SOME(select name from constant_two);";
// obj.test(selectSQl);
// selectSQl = "select * from constant_one where id > ANY(select name from constant_two);";
// obj.test(selectSQl);
// selectSQl = "select * from constant_one where id > ALL(select name from constant_two);";
// obj.test(selectSQl);
// selectSQl = "select * from constant_one where id <> ALL(select name from constant_two);";
// obj.test(selectSQl);
// selectSQl = "SELECT BINARY 'a' = 'A';";
// obj.test(selectSQl);
selectSQl = "SELECT b'1000001';";
obj.test(selectSQl);
// selectSQl = "SELECT b'1000001';";
// obj.test(selectSQl);
// selectSQl = "SELECT GET_FORMAT(DATE);";
// obj.test(selectSQl);
// selectSQl = "select CURRENT_DATE;";//not support
@@ -356,6 +362,8 @@ public class Testparser {
// //not support
// selectSQl = "select sql_big_result distinct pad from sbtest1;";
// obj.test(selectSQl);
String insertSQl = "insert into test_shard values(1,1,'a\\%string','test001');";
obj.test(insertSQl);
}
@@ -603,6 +611,19 @@ public class Testparser {
System.out.println("---------------------------");
}
}
if (selectQueryBlock.getWhere() != null) {
if(selectQueryBlock.getWhere() instanceof SQLBinaryOpExpr){
SQLBinaryOpExpr where = (SQLBinaryOpExpr)(selectQueryBlock.getWhere());
System.out.println("where right:");
System.out.println("class :" + where.getRight().getClass());
System.out.println("---------------------------");
}
else{
System.out.println("where:");
System.out.println("class :" + selectQueryBlock.getWhere().getClass());
System.out.println("---------------------------");
}
}
} else if (sqlSelectQuery instanceof MySqlUnionQuery) {
}
+1 -1
View File
@@ -36,7 +36,7 @@
<!-- 用户访问定义,用户名、密码、schema等信息。 -->
<user name="test">
<property name="password">test</property>
<property name="schemas">dbtest,mysqldb,cndb,testdb,dubbo,dubbo2,config,none_node_test,solo1,ignoreSchemaTest
<property name="schemas">dbtest,mysqldb,cndb,TESTDB,dubbo,dubbo2,config,none_node_test,solo1,ignoreSchemaTest
</property>
<property name="benchmark">11111</property>
<!-- benchmark 基准, 当前端的整体connection数达到基准值是, 对来自该账户的请求开始拒绝连接,0或不设表示不限制 -->
+1 -1
View File
@@ -1,4 +1,4 @@
BuildTime 2017-10-24 10:24:07
BuildTime 2017-10-17 08:14:49
MavenVersion 2.17.09.0-dev
GitUrl https://github.com/actiontech/dble
WebSite http://dble.cloud/