blob: 5d7ddb5a0b707ea02600f5e88dda20186a78d127 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.doris.qe;
import org.apache.doris.analysis.AccessTestUtil;
import org.apache.doris.analysis.Analyzer;
import org.apache.doris.analysis.DdlStmt;
import org.apache.doris.analysis.Expr;
import org.apache.doris.analysis.KillStmt;
import org.apache.doris.analysis.QueryStmt;
import org.apache.doris.analysis.RedirectStatus;
import org.apache.doris.analysis.SetStmt;
import org.apache.doris.analysis.ShowAuthorStmt;
import org.apache.doris.analysis.ShowStmt;
import org.apache.doris.analysis.SqlParser;
import org.apache.doris.analysis.StatementBase;
import org.apache.doris.analysis.UseStmt;
import org.apache.doris.catalog.Catalog;
import org.apache.doris.common.DdlException;
import org.apache.doris.common.jmockit.Deencapsulation;
import org.apache.doris.common.util.RuntimeProfile;
import org.apache.doris.metric.MetricRepo;
import org.apache.doris.mysql.MysqlChannel;
import org.apache.doris.mysql.MysqlSerializer;
import org.apache.doris.planner.Planner;
import org.apache.doris.rewrite.ExprRewriter;
import org.apache.doris.service.FrontendOptions;
import org.apache.doris.thrift.TQueryOptions;
import org.apache.doris.thrift.TUniqueId;
import com.google.common.collect.Lists;
import org.glassfish.jersey.internal.guava.Sets;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import java.io.IOException;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.List;
import java.util.SortedMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java_cup.runtime.Symbol;
import mockit.Expectations;
import mockit.Mocked;
public class StmtExecutorTest {
private ConnectContext ctx;
private QueryState state;
private ConnectScheduler scheduler;
@Mocked
SocketChannel socketChannel;
@BeforeClass
public static void start() {
MetricRepo.init();
try {
FrontendOptions.init();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Before
public void setUp() throws IOException {
state = new QueryState();
scheduler = new ConnectScheduler(10);
ctx = new ConnectContext(socketChannel);
SessionVariable sessionVariable = new SessionVariable();
MysqlSerializer serializer = MysqlSerializer.newInstance();
Catalog catalog = AccessTestUtil.fetchAdminCatalog();
MysqlChannel channel = new MysqlChannel(socketChannel);
new Expectations(channel) {
{
channel.sendOnePacket((ByteBuffer) any);
minTimes = 0;
channel.reset();
minTimes = 0;
}
};
new Expectations(ctx) {
{
ctx.getMysqlChannel();
minTimes = 0;
result = channel;
ctx.getSerializer();
minTimes = 0;
result = serializer;
ctx.getCatalog();
minTimes = 0;
result = catalog;
ctx.getState();
minTimes = 0;
result = state;
ctx.getConnectScheduler();
minTimes = 0;
result = scheduler;
ctx.getConnectionId();
minTimes = 0;
result = 1;
ctx.getQualifiedUser();
minTimes = 0;
result = "testUser";
ctx.getForwardedStmtId();
minTimes = 0;
result = 123L;
ctx.setKilled();
minTimes = 0;
ctx.updateReturnRows(anyInt);
minTimes = 0;
ctx.setQueryId((TUniqueId) any);
minTimes = 0;
ctx.queryId();
minTimes = 0;
result = new TUniqueId();
ctx.getStartTime();
minTimes = 0;
result = 0L;
ctx.getDatabase();
minTimes = 0;
result = "testCluster:testDb";
ctx.getSessionVariable();
minTimes = 0;
result = sessionVariable;
ctx.setStmtId(anyLong);
minTimes = 0;
ctx.getStmtId();
minTimes = 0;
result = 1L;
}
};
}
@Test
public void testSelect(@Mocked QueryStmt queryStmt,
@Mocked SqlParser parser,
@Mocked Planner planner,
@Mocked Coordinator coordinator) throws Exception {
Catalog catalog = Catalog.getCurrentCatalog();
Deencapsulation.setField(catalog, "canRead", new AtomicBoolean(true));
new Expectations() {
{
queryStmt.analyze((Analyzer) any);
minTimes = 0;
queryStmt.getColLabels();
minTimes = 0;
result = Lists.<String>newArrayList();
queryStmt.getResultExprs();
minTimes = 0;
result = Lists.<Expr>newArrayList();
queryStmt.isExplain();
minTimes = 0;
result = false;
queryStmt.getTables((Analyzer) any, (SortedMap) any, Sets.newHashSet());
minTimes = 0;
queryStmt.getRedirectStatus();
minTimes = 0;
result = RedirectStatus.NO_FORWARD;
queryStmt.rewriteExprs((ExprRewriter) any);
minTimes = 0;
Symbol symbol = new Symbol(0, Lists.newArrayList(queryStmt));
parser.parse();
minTimes = 0;
result = symbol;
planner.plan((QueryStmt) any, (Analyzer) any, (TQueryOptions) any);
minTimes = 0;
// mock coordinator
coordinator.exec();
minTimes = 0;
coordinator.endProfile();
minTimes = 0;
coordinator.getQueryProfile();
minTimes = 0;
result = new RuntimeProfile();
coordinator.getNext();
minTimes = 0;
result = new RowBatch();
coordinator.getJobId();
minTimes = 0;
result = -1L;
Catalog.getCurrentCatalog();
minTimes = 0;
result = catalog;
}
};
StmtExecutor stmtExecutor = new StmtExecutor(ctx, "");
stmtExecutor.execute();
Assert.assertEquals(QueryState.MysqlStateType.EOF, state.getStateType());
}
@Test
public void testShow(@Mocked ShowStmt showStmt, @Mocked SqlParser parser, @Mocked ShowExecutor executor) throws Exception {
new Expectations() {
{
showStmt.analyze((Analyzer) any);
minTimes = 0;
showStmt.getRedirectStatus();
minTimes = 0;
result = RedirectStatus.NO_FORWARD;
showStmt.toSelectStmt((Analyzer) any);
minTimes = 0;
result = null;
Symbol symbol = new Symbol(0, Lists.newArrayList(showStmt));
parser.parse();
minTimes = 0;
result = symbol;
// mock show
List<List<String>> rows = Lists.newArrayList();
rows.add(Lists.newArrayList("abc", "bcd"));
executor.execute();
minTimes = 0;
result = new ShowResultSet(new ShowAuthorStmt().getMetaData(), rows);
}
};
StmtExecutor stmtExecutor = new StmtExecutor(ctx, "");
stmtExecutor.execute();
Assert.assertEquals(QueryState.MysqlStateType.EOF, state.getStateType());
}
@Test
public void testShowNull(@Mocked ShowStmt showStmt, @Mocked SqlParser parser, @Mocked ShowExecutor executor) throws Exception {
new Expectations() {
{
showStmt.analyze((Analyzer) any);
minTimes = 0;
showStmt.getRedirectStatus();
minTimes = 0;
result = RedirectStatus.NO_FORWARD;
showStmt.toSelectStmt((Analyzer) any);
minTimes = 0;
result = null;
Symbol symbol = new Symbol(0, Lists.newArrayList(showStmt));
parser.parse();
minTimes = 0;
result = symbol;
// mock show
List<List<String>> rows = Lists.newArrayList();
rows.add(Lists.newArrayList("abc", "bcd"));
executor.execute();
minTimes = 0;
result = null;
}
};
StmtExecutor stmtExecutor = new StmtExecutor(ctx, "");
stmtExecutor.execute();
Assert.assertEquals(QueryState.MysqlStateType.OK, state.getStateType());
}
@Test
public void testKill(@Mocked KillStmt killStmt, @Mocked SqlParser parser) throws Exception {
new Expectations() {
{
killStmt.analyze((Analyzer) any);
minTimes = 0;
killStmt.getConnectionId();
minTimes = 0;
result = 1L;
killStmt.getRedirectStatus();
minTimes = 0;
result = RedirectStatus.NO_FORWARD;
Symbol symbol = new Symbol(0, Lists.newArrayList(killStmt));
parser.parse();
minTimes = 0;
result = symbol;
}
};
new Expectations(scheduler) {
{
// suicide
scheduler.getContext(1L);
result = ctx;
}
};
StmtExecutor stmtExecutor = new StmtExecutor(ctx, "");
stmtExecutor.execute();
Assert.assertEquals(QueryState.MysqlStateType.OK, state.getStateType());
}
@Test
public void testKillOtherFail(@Mocked KillStmt killStmt, @Mocked SqlParser parser, @Mocked ConnectContext killCtx) throws Exception {
Catalog killCatalog = AccessTestUtil.fetchAdminCatalog();
new Expectations() {
{
killStmt.analyze((Analyzer) any);
minTimes = 0;
killStmt.getConnectionId();
minTimes = 0;
result = 1L;
killStmt.isConnectionKill();
minTimes = 0;
result = true;
killStmt.getRedirectStatus();
minTimes = 0;
result = RedirectStatus.NO_FORWARD;
Symbol symbol = new Symbol(0, Lists.newArrayList(killStmt));
parser.parse();
minTimes = 0;
result = symbol;
killCtx.getCatalog();
minTimes = 0;
result = killCatalog;
killCtx.getQualifiedUser();
minTimes = 0;
result = "blockUser";
killCtx.kill(true);
minTimes = 0;
ConnectContext.get();
minTimes = 0;
result = ctx;
}
};
new Expectations(scheduler) {
{
// suicide
scheduler.getContext(1L);
result = killCtx;
}
};
StmtExecutor stmtExecutor = new StmtExecutor(ctx, "");
stmtExecutor.execute();
Assert.assertEquals(QueryState.MysqlStateType.ERR, state.getStateType());
}
@Test
public void testKillOther(@Mocked KillStmt killStmt, @Mocked SqlParser parser, @Mocked ConnectContext killCtx) throws Exception {
Catalog killCatalog = AccessTestUtil.fetchAdminCatalog();
new Expectations() {
{
killStmt.analyze((Analyzer) any);
minTimes = 0;
killStmt.getConnectionId();
minTimes = 0;
result = 1L;
killStmt.isConnectionKill();
minTimes = 0;
result = true;
killStmt.getRedirectStatus();
minTimes = 0;
result = RedirectStatus.NO_FORWARD;
Symbol symbol = new Symbol(0, Lists.newArrayList(killStmt));
parser.parse();
minTimes = 0;
result = symbol;
killCtx.getCatalog();
minTimes = 0;
result = killCatalog;
killCtx.getQualifiedUser();
minTimes = 0;
result = "killUser";
killCtx.kill(true);
minTimes = 0;
ConnectContext.get();
minTimes = 0;
result = ctx;
}
};
new Expectations(scheduler) {
{
// suicide
scheduler.getContext(1L);
result = killCtx;
}
};
StmtExecutor stmtExecutor = new StmtExecutor(ctx, "");
stmtExecutor.execute();
Assert.assertEquals(QueryState.MysqlStateType.ERR, state.getStateType());
}
@Test
public void testKillNoCtx(@Mocked KillStmt killStmt, @Mocked SqlParser parser) throws Exception {
new Expectations() {
{
killStmt.analyze((Analyzer) any);
minTimes = 0;
killStmt.getConnectionId();
minTimes = 0;
result = 1L;
killStmt.getRedirectStatus();
minTimes = 0;
result = RedirectStatus.NO_FORWARD;
Symbol symbol = new Symbol(0, Lists.newArrayList(killStmt));
parser.parse();
minTimes = 0;
result = symbol;
}
};
new Expectations(scheduler) {
{
scheduler.getContext(1L);
result = null;
}
};
StmtExecutor stmtExecutor = new StmtExecutor(ctx, "");
stmtExecutor.execute();
Assert.assertEquals(QueryState.MysqlStateType.ERR, state.getStateType());
}
@Test
public void testSet(@Mocked SetStmt setStmt, @Mocked SqlParser parser, @Mocked SetExecutor executor) throws Exception {
new Expectations() {
{
setStmt.analyze((Analyzer) any);
minTimes = 0;
setStmt.getRedirectStatus();
minTimes = 0;
result = RedirectStatus.NO_FORWARD;
Symbol symbol = new Symbol(0, Lists.newArrayList(setStmt));
parser.parse();
minTimes = 0;
result = symbol;
// Mock set
executor.execute();
minTimes = 0;
}
};
StmtExecutor stmtExecutor = new StmtExecutor(ctx, "");
stmtExecutor.execute();
Assert.assertEquals(QueryState.MysqlStateType.OK, state.getStateType());
}
@Test
public void testStmtWithUserInfo(@Mocked StatementBase stmt, @Mocked ConnectContext context) throws Exception {
StmtExecutor stmtExecutor = new StmtExecutor(ctx, stmt);
Deencapsulation.setField(stmtExecutor, "parsedStmt", null);
Deencapsulation.setField(stmtExecutor, "originStmt", new OriginStatement("show databases;", 1));
stmtExecutor.execute();
StatementBase newstmt = (StatementBase)Deencapsulation.getField(stmtExecutor, "parsedStmt");
Assert.assertTrue(newstmt.getUserInfo() != null);
}
@Test
public void testSetFail(@Mocked SetStmt setStmt, @Mocked SqlParser parser, @Mocked SetExecutor executor) throws Exception {
new Expectations() {
{
setStmt.analyze((Analyzer) any);
minTimes = 0;
setStmt.getRedirectStatus();
minTimes = 0;
result = RedirectStatus.NO_FORWARD;
Symbol symbol = new Symbol(0, Lists.newArrayList(setStmt));
parser.parse();
minTimes = 0;
result = symbol;
// Mock set
executor.execute();
minTimes = 0;
result = new DdlException("failed");
}
};
StmtExecutor stmtExecutor = new StmtExecutor(ctx, "");
stmtExecutor.execute();
Assert.assertEquals(QueryState.MysqlStateType.ERR, state.getStateType());
}
@Test
public void testDdl(@Mocked DdlStmt ddlStmt, @Mocked SqlParser parser) throws Exception {
new Expectations() {
{
ddlStmt.analyze((Analyzer) any);
minTimes = 0;
ddlStmt.getRedirectStatus();
minTimes = 0;
result = RedirectStatus.NO_FORWARD;
Symbol symbol = new Symbol(0, Lists.newArrayList(ddlStmt));
parser.parse();
minTimes = 0;
result = symbol;
}
};
DdlExecutor ddlExecutor = new DdlExecutor();
new Expectations(ddlExecutor) {
{
// Mock ddl
DdlExecutor.execute((Catalog) any, (DdlStmt) any);
minTimes = 0;
}
};
StmtExecutor executor = new StmtExecutor(ctx, "");
executor.execute();
Assert.assertEquals(QueryState.MysqlStateType.OK, state.getStateType());
}
@Test
public void testDdlFail(@Mocked DdlStmt ddlStmt, @Mocked SqlParser parser) throws Exception {
new Expectations() {
{
ddlStmt.analyze((Analyzer) any);
minTimes = 0;
ddlStmt.getRedirectStatus();
minTimes = 0;
result = RedirectStatus.NO_FORWARD;
Symbol symbol = new Symbol(0, Lists.newArrayList(ddlStmt));
parser.parse();
minTimes = 0;
result = symbol;
}
};
DdlExecutor ddlExecutor = new DdlExecutor();
new Expectations(ddlExecutor) {
{
// Mock ddl
DdlExecutor.execute((Catalog) any, (DdlStmt) any);
minTimes = 0;
result = new DdlException("ddl fail");
}
};
StmtExecutor executor = new StmtExecutor(ctx, "");
executor.execute();
Assert.assertEquals(QueryState.MysqlStateType.ERR, state.getStateType());
}
@Test
public void testDdlFail2(@Mocked DdlStmt ddlStmt, @Mocked SqlParser parser) throws Exception {
new Expectations() {
{
ddlStmt.analyze((Analyzer) any);
minTimes = 0;
ddlStmt.getRedirectStatus();
minTimes = 0;
result = RedirectStatus.NO_FORWARD;
Symbol symbol = new Symbol(0, Lists.newArrayList(ddlStmt));
parser.parse();
minTimes = 0;
result = symbol;
}
};
DdlExecutor ddlExecutor = new DdlExecutor();
new Expectations(ddlExecutor) {
{
// Mock ddl
DdlExecutor.execute((Catalog) any, (DdlStmt) any);
minTimes = 0;
result = new Exception("bug");
}
};
StmtExecutor executor = new StmtExecutor(ctx, "");
executor.execute();
Assert.assertEquals(QueryState.MysqlStateType.ERR, state.getStateType());
}
@Test
public void testUse(@Mocked UseStmt useStmt, @Mocked SqlParser parser) throws Exception {
new Expectations() {
{
useStmt.analyze((Analyzer) any);
minTimes = 0;
useStmt.getDatabase();
minTimes = 0;
result = "testCluster:testDb";
useStmt.getRedirectStatus();
minTimes = 0;
result = RedirectStatus.NO_FORWARD;
useStmt.getClusterName();
minTimes = 0;
result = "testCluster";
Symbol symbol = new Symbol(0, Lists.newArrayList(useStmt));
parser.parse();
minTimes = 0;
result = symbol;
}
};
StmtExecutor executor = new StmtExecutor(ctx, "");
executor.execute();
Assert.assertEquals(QueryState.MysqlStateType.OK, state.getStateType());
}
@Test
public void testUseFail(@Mocked UseStmt useStmt, @Mocked SqlParser parser) throws Exception {
new Expectations() {
{
useStmt.analyze((Analyzer) any);
minTimes = 0;
useStmt.getDatabase();
minTimes = 0;
result = "blockDb";
useStmt.getRedirectStatus();
minTimes = 0;
result = RedirectStatus.NO_FORWARD;
useStmt.getClusterName();
minTimes = 0;
result = "testCluster";
Symbol symbol = new Symbol(0, Lists.newArrayList(useStmt));
parser.parse();
minTimes = 0;
result = symbol;
}
};
StmtExecutor executor = new StmtExecutor(ctx, "");
executor.execute();
Assert.assertEquals(QueryState.MysqlStateType.ERR, state.getStateType());
}
}