diff --git a/src/main/java/com/actiontech/dble/backend/mysql/nio/handler/builder/BaseHandlerBuilder.java b/src/main/java/com/actiontech/dble/backend/mysql/nio/handler/builder/BaseHandlerBuilder.java index 01de7b994..da0f8b881 100644 --- a/src/main/java/com/actiontech/dble/backend/mysql/nio/handler/builder/BaseHandlerBuilder.java +++ b/src/main/java/com/actiontech/dble/backend/mysql/nio/handler/builder/BaseHandlerBuilder.java @@ -43,7 +43,6 @@ import org.apache.log4j.Logger; import java.nio.charset.StandardCharsets; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; @@ -53,7 +52,7 @@ 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; @@ -73,7 +72,7 @@ abstract class BaseHandlerBuilder { protected boolean needSendMaker = true; protected boolean isExplain = false; - protected List endHandlerList = new ArrayList<>(1); + protected List subQueryBuilderList = new ArrayList<>(1); protected BaseHandlerBuilder(NonBlockingSession session, PlanNode node, HandlerBuilder hBuilder, boolean isExplain) { this.session = session; @@ -89,8 +88,8 @@ abstract class BaseHandlerBuilder { return currentLast; } - public List getEndHandlerList() { - return endHandlerList; + public List getSubQueryBuilderList() { + return subQueryBuilderList; } /** @@ -438,13 +437,25 @@ abstract class BaseHandlerBuilder { for (ItemSubQuery itemSubQuery : node.getSubQueries()) { if (itemSubQuery instanceof ItemSingleRowSubQuery) { final SubQueryHandler tempHandler = new SingleRowSubQueryHandler(getSequenceId(), session, (ItemSingleRowSubQuery) itemSubQuery); - handleSubQuery(lock, finishSubQuery, finished, subNodes, errorPackets, itemSubQuery.getPlanNode(), tempHandler); + 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); - handleSubQuery(lock, finishSubQuery, finished, subNodes, errorPackets, itemSubQuery.getPlanNode(), tempHandler); + 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); - handleSubQuery(lock, finishSubQuery, finished, subNodes, errorPackets, itemSubQuery.getPlanNode(), tempHandler); + if (isExplain) { + handleSubQueryForExplain(lock, finishSubQuery, finished, subNodes, itemSubQuery.getPlanNode(), tempHandler); + } else { + handleSubQuery(lock, finishSubQuery, finished, subNodes, errorPackets, itemSubQuery.getPlanNode(), tempHandler); + } } } lock.lock(); @@ -467,33 +478,35 @@ abstract class BaseHandlerBuilder { } } + 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 errorPackets, final PlanNode planNode, final SubQueryHandler tempHandler) { DbleServer.getInstance().getComplexQueryExecutor().execute(new Runnable() { @Override public void run() { try { - DMLResponseHandler endHandler = hBuilder.buildNode(session, planNode); + DMLResponseHandler endHandler = hBuilder.buildNode(session, planNode, false); endHandler.setNextHandler(tempHandler); - HandlerBuilder.startHandler(endHandler); CallBackHandler tempDone = new CallBackHandler() { @Override public void call() throws Exception { if (tempHandler.getErrorPacket() != null) { errorPackets.add(tempHandler.getErrorPacket()); } - if (subNodes.decrementAndGet() == 0) { - lock.lock(); - try { - finished.set(true); - finishSubQuery.signal(); - } finally { - lock.unlock(); - } - } + subQueryFinished(subNodes, lock, finished, finishSubQuery); } }; tempHandler.setTempDoneCallBack(tempDone); + HandlerBuilder.startHandler(endHandler); } catch (Exception e) { LOGGER.warn("execute ItemScalarSubQuery error", e); ErrorPacket errorPackage = new ErrorPacket(); @@ -506,4 +519,16 @@ abstract class BaseHandlerBuilder { }); } + 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(); + } + } + } + } diff --git a/src/main/java/com/actiontech/dble/backend/mysql/nio/handler/builder/HandlerBuilder.java b/src/main/java/com/actiontech/dble/backend/mysql/nio/handler/builder/HandlerBuilder.java index 52939555a..ec192ad92 100644 --- a/src/main/java/com/actiontech/dble/backend/mysql/nio/handler/builder/HandlerBuilder.java +++ b/src/main/java/com/actiontech/dble/backend/mysql/nio/handler/builder/HandlerBuilder.java @@ -15,7 +15,6 @@ import com.actiontech.dble.server.NonBlockingSession; import org.apache.log4j.Logger; import java.util.HashSet; -import java.util.List; import java.util.Set; public class HandlerBuilder { @@ -55,22 +54,20 @@ public class HandlerBuilder { * @param planNode * @return */ - public DMLResponseHandler buildNode(NonBlockingSession nonBlockingSession, PlanNode planNode) { - BaseHandlerBuilder builder = createBuilder(nonBlockingSession, planNode, false); - builder.build(); + public DMLResponseHandler buildNode(NonBlockingSession nonBlockingSession, PlanNode planNode, boolean isExplain) { + BaseHandlerBuilder builder = getBuilder(nonBlockingSession, planNode, isExplain); return builder.getEndHandler(); } - public List buildNodes(NonBlockingSession nonBlockingSession, PlanNode planNode) { - BaseHandlerBuilder builder = createBuilder(nonBlockingSession, planNode, true); + public BaseHandlerBuilder getBuilder(NonBlockingSession nonBlockingSession, PlanNode planNode, boolean isExplain) { + BaseHandlerBuilder builder = createBuilder(nonBlockingSession, planNode, isExplain); builder.build(); - builder.getEndHandlerList().add(builder.getEndHandler()); - return builder.getEndHandlerList(); + 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); diff --git a/src/main/java/com/actiontech/dble/backend/mysql/nio/handler/builder/JoinNodeHandlerBuilder.java b/src/main/java/com/actiontech/dble/backend/mysql/nio/handler/builder/JoinNodeHandlerBuilder.java index a0b394fa0..0731b3b05 100644 --- a/src/main/java/com/actiontech/dble/backend/mysql/nio/handler/builder/JoinNodeHandlerBuilder.java +++ b/src/main/java/com/actiontech/dble/backend/mysql/nio/handler/builder/JoinNodeHandlerBuilder.java @@ -126,7 +126,7 @@ class JoinNodeHandlerBuilder extends BaseHandlerBuilder { } private DMLResponseHandler buildJoinChild(PlanNode child, boolean isLeft) { - DMLResponseHandler endHandler = hBuilder.buildNode(session, child); + DMLResponseHandler endHandler = hBuilder.buildNode(session, child, isExplain); if (isLeft) { if (!node.isLeftOrderMatch()) { OrderByHandler oh = new OrderByHandler(getSequenceId(), session, node.getLeftJoinOnOrders()); diff --git a/src/main/java/com/actiontech/dble/backend/mysql/nio/handler/builder/MergeNodeHandlerBuilder.java b/src/main/java/com/actiontech/dble/backend/mysql/nio/handler/builder/MergeNodeHandlerBuilder.java index 98d9c479a..a9b68ed29 100644 --- a/src/main/java/com/actiontech/dble/backend/mysql/nio/handler/builder/MergeNodeHandlerBuilder.java +++ b/src/main/java/com/actiontech/dble/backend/mysql/nio/handler/builder/MergeNodeHandlerBuilder.java @@ -31,7 +31,7 @@ class MergeNodeHandlerBuilder extends BaseHandlerBuilder { protected List buildPre() { List pres = new ArrayList<>(); for (PlanNode child : node.getChildren()) { - DMLResponseHandler ch = hBuilder.buildNode(session, child); + DMLResponseHandler ch = hBuilder.buildNode(session, child, isExplain); pres.add(ch); } return pres; diff --git a/src/main/java/com/actiontech/dble/backend/mysql/nio/handler/builder/QueryNodeHandlerBuilder.java b/src/main/java/com/actiontech/dble/backend/mysql/nio/handler/builder/QueryNodeHandlerBuilder.java index 2c8ced7a9..0dfac8799 100644 --- a/src/main/java/com/actiontech/dble/backend/mysql/nio/handler/builder/QueryNodeHandlerBuilder.java +++ b/src/main/java/com/actiontech/dble/backend/mysql/nio/handler/builder/QueryNodeHandlerBuilder.java @@ -31,7 +31,7 @@ class QueryNodeHandlerBuilder extends BaseHandlerBuilder { public List buildPre() { List pres = new ArrayList<>(); PlanNode subNode = node.getChild(); - DMLResponseHandler subHandler = hBuilder.buildNode(session, subNode); + DMLResponseHandler subHandler = hBuilder.buildNode(session, subNode, isExplain); pres.add(subHandler); return pres; } diff --git a/src/main/java/com/actiontech/dble/backend/mysql/nio/handler/query/impl/subquery/AllAnySubQueryHandler.java b/src/main/java/com/actiontech/dble/backend/mysql/nio/handler/query/impl/subquery/AllAnySubQueryHandler.java index 45ca65e87..a267d7e1f 100644 --- a/src/main/java/com/actiontech/dble/backend/mysql/nio/handler/query/impl/subquery/AllAnySubQueryHandler.java +++ b/src/main/java/com/actiontech/dble/backend/mysql/nio/handler/query/impl/subquery/AllAnySubQueryHandler.java @@ -13,6 +13,7 @@ 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; @@ -129,5 +130,42 @@ public class AllAnySubQueryHandler extends SubQueryHandler { } - + @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; + } + } } diff --git a/src/main/java/com/actiontech/dble/backend/mysql/nio/handler/query/impl/subquery/InSubQueryHandler.java b/src/main/java/com/actiontech/dble/backend/mysql/nio/handler/query/impl/subquery/InSubQueryHandler.java index 77cab4cfb..c65c3bccb 100644 --- a/src/main/java/com/actiontech/dble/backend/mysql/nio/handler/query/impl/subquery/InSubQueryHandler.java +++ b/src/main/java/com/actiontech/dble/backend/mysql/nio/handler/query/impl/subquery/InSubQueryHandler.java @@ -13,12 +13,15 @@ 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; @@ -95,4 +98,8 @@ public class InSubQueryHandler extends SubQueryHandler { return HandlerType.IN_SUB_QUERY; } + @Override + public void setForExplain() { + itemSubQuery.getValue().add(new ItemString(NEED_REPLACE)); + } } diff --git a/src/main/java/com/actiontech/dble/backend/mysql/nio/handler/query/impl/subquery/SingleRowSubQueryHandler.java b/src/main/java/com/actiontech/dble/backend/mysql/nio/handler/query/impl/subquery/SingleRowSubQueryHandler.java index 8358d3ee0..5b08f0831 100644 --- a/src/main/java/com/actiontech/dble/backend/mysql/nio/handler/query/impl/subquery/SingleRowSubQueryHandler.java +++ b/src/main/java/com/actiontech/dble/backend/mysql/nio/handler/query/impl/subquery/SingleRowSubQueryHandler.java @@ -12,12 +12,15 @@ 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; @@ -88,4 +91,9 @@ public class SingleRowSubQueryHandler extends SubQueryHandler { 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)); + } } diff --git a/src/main/java/com/actiontech/dble/backend/mysql/nio/handler/query/impl/subquery/SubQueryHandler.java b/src/main/java/com/actiontech/dble/backend/mysql/nio/handler/query/impl/subquery/SubQueryHandler.java index c275e868d..2230d5ef7 100644 --- a/src/main/java/com/actiontech/dble/backend/mysql/nio/handler/query/impl/subquery/SubQueryHandler.java +++ b/src/main/java/com/actiontech/dble/backend/mysql/nio/handler/query/impl/subquery/SubQueryHandler.java @@ -22,6 +22,7 @@ public abstract class SubQueryHandler extends BaseDMLHandler { 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(); diff --git a/src/main/java/com/actiontech/dble/plan/common/item/subquery/ItemAllAnySubQuery.java b/src/main/java/com/actiontech/dble/plan/common/item/subquery/ItemAllAnySubQuery.java index 6a83ca81b..e372fc8ff 100644 --- a/src/main/java/com/actiontech/dble/plan/common/item/subquery/ItemAllAnySubQuery.java +++ b/src/main/java/com/actiontech/dble/plan/common/item/subquery/ItemAllAnySubQuery.java @@ -10,6 +10,8 @@ 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; @@ -17,6 +19,8 @@ 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; @@ -46,6 +50,11 @@ public class ItemAllAnySubQuery extends ItemMultiRowSubQuery { } } + @Override + protected Item cloneStruct(boolean forCalculate, List calArgs, boolean isPushDown, List fields) { + return new ItemAllAnySubQuery(this.currentDb, this.operator, this.query, this.isAll); + } + public boolean isAll() { return isAll; } diff --git a/src/main/java/com/actiontech/dble/plan/common/item/subquery/ItemExistsSubQuery.java b/src/main/java/com/actiontech/dble/plan/common/item/subquery/ItemExistsSubQuery.java index 2e26835a6..e9b87a3c2 100644 --- a/src/main/java/com/actiontech/dble/plan/common/item/subquery/ItemExistsSubQuery.java +++ b/src/main/java/com/actiontech/dble/plan/common/item/subquery/ItemExistsSubQuery.java @@ -76,7 +76,7 @@ public class ItemExistsSubQuery extends ItemSingleRowSubQuery { @Override protected Item cloneStruct(boolean forCalculate, List calArgs, boolean isPushDown, List fields) { - throw new MySQLOutPutException(ErrorCode.ER_OPTIMIZER, "", "unexpected!"); + return new ItemExistsSubQuery(this.currentDb, this.query, this.isNot); } @Override public SubSelectType subType() { diff --git a/src/main/java/com/actiontech/dble/plan/common/item/subquery/ItemInSubQuery.java b/src/main/java/com/actiontech/dble/plan/common/item/subquery/ItemInSubQuery.java index 5171498ae..7e282f464 100644 --- a/src/main/java/com/actiontech/dble/plan/common/item/subquery/ItemInSubQuery.java +++ b/src/main/java/com/actiontech/dble/plan/common/item/subquery/ItemInSubQuery.java @@ -3,24 +3,25 @@ * 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; @@ -62,6 +63,11 @@ public class ItemInSubQuery extends ItemMultiRowSubQuery { return inSub; } + @Override + protected Item cloneStruct(boolean forCalculate, List calArgs, boolean isPushDown, List fields) { + return new ItemInSubQuery(this.currentDb, this.leftOperand.cloneItem(), this.query, this.isNeg); + } + public Item getLeftOperand() { return leftOperand; } diff --git a/src/main/java/com/actiontech/dble/plan/common/item/subquery/ItemMultiRowSubQuery.java b/src/main/java/com/actiontech/dble/plan/common/item/subquery/ItemMultiRowSubQuery.java index 3c509c20b..862518be6 100644 --- a/src/main/java/com/actiontech/dble/plan/common/item/subquery/ItemMultiRowSubQuery.java +++ b/src/main/java/com/actiontech/dble/plan/common/item/subquery/ItemMultiRowSubQuery.java @@ -10,7 +10,6 @@ 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.statement.SQLSelectQuery; @@ -66,10 +65,6 @@ public abstract class ItemMultiRowSubQuery extends ItemSubQuery { throw new MySQLOutPutException(ErrorCode.ER_OPTIMIZER, "", "not support yet!"); } - @Override - protected Item cloneStruct(boolean forCalculate, List calArgs, boolean isPushDown, List fields) { - throw new MySQLOutPutException(ErrorCode.ER_OPTIMIZER, "", "unexpected!"); - } public Item getSelect() { diff --git a/src/main/java/com/actiontech/dble/plan/common/item/subquery/ItemScalarSubQuery.java b/src/main/java/com/actiontech/dble/plan/common/item/subquery/ItemScalarSubQuery.java index bd28bd6d9..3077dce06 100644 --- a/src/main/java/com/actiontech/dble/plan/common/item/subquery/ItemScalarSubQuery.java +++ b/src/main/java/com/actiontech/dble/plan/common/item/subquery/ItemScalarSubQuery.java @@ -52,7 +52,7 @@ public class ItemScalarSubQuery extends ItemSingleRowSubQuery { @Override protected Item cloneStruct(boolean forCalculate, List calArgs, boolean isPushDown, List fieldList) { - throw new MySQLOutPutException(ErrorCode.ER_OPTIMIZER, "", "unexpected!"); + return new ItemScalarSubQuery(this.currentDb, this.query); } diff --git a/src/main/java/com/actiontech/dble/plan/common/item/subquery/ItemSingleRowSubQuery.java b/src/main/java/com/actiontech/dble/plan/common/item/subquery/ItemSingleRowSubQuery.java index 8e6a352dd..54328a970 100644 --- a/src/main/java/com/actiontech/dble/plan/common/item/subquery/ItemSingleRowSubQuery.java +++ b/src/main/java/com/actiontech/dble/plan/common/item/subquery/ItemSingleRowSubQuery.java @@ -5,16 +5,12 @@ 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.statement.SQLSelectQuery; import java.math.BigDecimal; import java.math.BigInteger; -import java.util.List; public abstract class ItemSingleRowSubQuery extends ItemSubQuery { protected Item value; @@ -117,11 +113,6 @@ public abstract class ItemSingleRowSubQuery extends ItemSubQuery { } - @Override - protected Item cloneStruct(boolean forCalculate, List calArgs, boolean isPushDown, List fieldList) { - throw new MySQLOutPutException(ErrorCode.ER_OPTIMIZER, "", "unexpected!"); - } - /*--------------------------------------getter/setter-----------------------------------*/ public Item getValue() { diff --git a/src/main/java/com/actiontech/dble/plan/common/item/subquery/ItemSubQuery.java b/src/main/java/com/actiontech/dble/plan/common/item/subquery/ItemSubQuery.java index 36af728f1..f89251c2c 100644 --- a/src/main/java/com/actiontech/dble/plan/common/item/subquery/ItemSubQuery.java +++ b/src/main/java/com/actiontech/dble/plan/common/item/subquery/ItemSubQuery.java @@ -19,7 +19,7 @@ import com.alibaba.druid.sql.ast.statement.SQLSelectQuery; public abstract class ItemSubQuery extends ItemResultField { protected SQLSelectQuery query; - private String currentDb; + protected String currentDb; protected PlanNode planNode; public enum SubSelectType { diff --git a/src/main/java/com/actiontech/dble/plan/optimizer/GlobalTableProcessor.java b/src/main/java/com/actiontech/dble/plan/optimizer/GlobalTableProcessor.java index 5c69e2130..1e096233b 100644 --- a/src/main/java/com/actiontech/dble/plan/optimizer/GlobalTableProcessor.java +++ b/src/main/java/com/actiontech/dble/plan/optimizer/GlobalTableProcessor.java @@ -120,7 +120,11 @@ public final class GlobalTableProcessor { } } if (tn.getNoshardNode() != null) { - tn.getNoshardNode().retainAll(tnChild.getNoshardNode()); + if (tnChild.getNoshardNode() != null) { + tn.getNoshardNode().retainAll(tnChild.getNoshardNode()); + } else { + tn.setNoshardNode(null); + } } } diff --git a/src/main/java/com/actiontech/dble/server/handler/ExplainHandler.java b/src/main/java/com/actiontech/dble/server/handler/ExplainHandler.java index aaac12792..2ade0282f 100644 --- a/src/main/java/com/actiontech/dble/server/handler/ExplainHandler.java +++ b/src/main/java/com/actiontech/dble/server/handler/ExplainHandler.java @@ -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,24 +118,51 @@ public final class ExplainHandler { } private static List getComplexQueryResult(RouteResultset rrs, ServerConnection c) { - List endHandlers = buildNodes(rrs, c); - if (endHandlers.size() == 1) { - DMLResponseHandler endHandler = endHandlers.get(0); - Map refMap = new HashMap<>(); - String rootName = buildHandlerTree(endHandler, refMap, new HashMap(), new HashMap(), null); - List resultList = new ArrayList<>(refMap.size()); - getDFSHandlers(refMap, rootName, resultList); - List result = new ArrayList<>(); - for (int i = resultList.size() - 1; i >= 0; i--) { - RefHandlerInfo handlerInfo = resultList.get(i); - result.add(new String[]{handlerInfo.name, handlerInfo.type, handlerInfo.getRefOrSQL()}); + List builderList = getBaseHandlerBuilders(rrs, c); + Map nameMap = new HashMap<>(); + List result = new ArrayList<>(); + + Map builderNameMap = new HashMap<>(); + for (int i = builderList.size() - 1; i >= 0; i--) { + BaseHandlerBuilder tmpBuilder = builderList.get(i); + Set subQueries = new LinkedHashSet<>(); + for (BaseHandlerBuilder childBuilder : tmpBuilder.getSubQueryBuilderList()) { + subQueries.add(builderNameMap.get(childBuilder)); } - return result; + String subQueryRootName = buildResultByEndHandler(subQueries, result, tmpBuilder.getEndHandler(), nameMap); + builderNameMap.put(tmpBuilder, subQueryRootName); } - return null; + return result; } - private static String buildHandlerTree(DMLResponseHandler endHandler, Map refMap, Map handlerMap, Map nameMap, String brotherName) { + private static List getBaseHandlerBuilders(RouteResultset rrs, ServerConnection c) { + BaseHandlerBuilder builder = buildNodes(rrs, c); + Queue queue = new LinkedList<>(); + queue.add(builder); + List 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 subQueries, List result, DMLResponseHandler endHandler, Map nameMap) { + Map refMap = new HashMap<>(); + String rootName = buildHandlerTree(endHandler, refMap, new HashMap(), nameMap, subQueries); + List 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 refMap, Map handlerMap, Map nameMap, Set dependencies) { String rootName = null; for (DMLResponseHandler startHandler : endHandler.getMerges()) { MultiNodeMergeHandler mergeHandler = (MultiNodeMergeHandler) startHandler; @@ -146,13 +177,13 @@ public final class ExplainHandler { String dateNode = rrss.getName() + "." + rrss.getMultiplexNum(); refInfo.addChild(dateNode); String type = "BASE SQL"; - if (brotherName != null) { + if (dependencies != null && dependencies.size() > 0) { type += "(May No Need)"; } RefHandlerInfo baseSQLInfo = new RefHandlerInfo(dateNode, type, rrss.getStatement()); refMap.put(dateNode, baseSQLInfo); - if (brotherName != null) { - baseSQLInfo.addBrother(brotherName); + if (dependencies != null && dependencies.size() > 0) { + baseSQLInfo.addAllStepChildren(dependencies); } } String mergeRootName = getAllNodesFromLeaf(mergeHandler, refMap, handlerMap, nameMap); @@ -204,7 +235,7 @@ public final class ExplainHandler { TempTableHandler tmp = (TempTableHandler) handler; DMLResponseHandler endHandler = tmp.getCreatedHandler(); endHandler.setNextHandler(nextHandler); - buildHandlerTree(endHandler, refMap, handlerMap, nameMap, childName + "'s RESULTS add to QUERY's WHERE"); + buildHandlerTree(endHandler, refMap, handlerMap, nameMap, Collections.singleton(childName + "'s RESULTS")); } handler = nextHandler; nextHandler = skipSendMake(nextHandler.getNextHandler()); @@ -257,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 List buildNodes(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); @@ -270,7 +307,7 @@ public final class ExplainHandler { node.setUpFields(); node = MyOptimizer.optimize(node); HandlerBuilder builder = new HandlerBuilder(node, c.getSession2()); - return builder.buildNodes(c.getSession2(), node); + return builder.getBuilder(c.getSession2(), node, true); } private static RowDataPacket getRow(RouteResultsetNode node, String charset) { @@ -341,7 +378,7 @@ public final class ExplainHandler { private String type; private String baseSQL; private Set children = new LinkedHashSet<>(); - private Set brothers = new LinkedHashSet<>(); + private Set stepChildren = new LinkedHashSet<>(); RefHandlerInfo(String name, String type, String baseSQL) { this(name, type); @@ -354,7 +391,7 @@ public final class ExplainHandler { String getRefOrSQL() { StringBuilder names = new StringBuilder(""); - for (String child : brothers) { + for (String child : stepChildren) { if (names.length() > 0) { names.append("; "); } @@ -380,8 +417,8 @@ public final class ExplainHandler { return children; } - void addBrother(String brother) { - this.brothers.add(brother); + void addAllStepChildren(Set dependencies) { + this.stepChildren.addAll(dependencies); } void addChild(String child) { this.children.add(child);