[GroupingSet] Disable column both in select list and aggregate functions when using GROUPING SETS/CUBE/ROLLUP (#2921)
This commit is contained in:
@ -17,6 +17,7 @@
|
||||
|
||||
package org.apache.doris.analysis;
|
||||
|
||||
import org.apache.doris.catalog.AggregateFunction;
|
||||
import org.apache.doris.catalog.AggregateType;
|
||||
import org.apache.doris.catalog.Catalog;
|
||||
import org.apache.doris.catalog.Column;
|
||||
@ -334,7 +335,7 @@ public class SelectStmt extends QueryStmt {
|
||||
// of expr child and depth limits (toColumn() label may call toSql()).
|
||||
item.getExpr().analyze(analyzer);
|
||||
if (item.getExpr().contains(Predicates.instanceOf(Subquery.class))) {
|
||||
throw new AnalysisException("Subqueries are not supported in the select list.");
|
||||
throw new AnalysisException("Subquery is not supported in the select list.");
|
||||
}
|
||||
resultExprs.add(item.getExpr());
|
||||
SlotRef aliasRef = new SlotRef(null, item.toColumnLabel());
|
||||
@ -349,6 +350,17 @@ public class SelectStmt extends QueryStmt {
|
||||
}
|
||||
}
|
||||
if (groupByClause != null && groupByClause.isGroupByExtension()) {
|
||||
for (SelectListItem item : selectList.getItems()) {
|
||||
if (item.getExpr() instanceof FunctionCallExpr && item.getExpr().fn instanceof AggregateFunction) {
|
||||
for (Expr expr: groupByClause.getGroupingExprs()) {
|
||||
if (item.getExpr().contains(expr)) {
|
||||
throw new AnalysisException("column: " + expr.toSql() + " cannot both in select list and "
|
||||
+ "aggregate functions when using GROUPING SETS/CUBE/ROLLUP, please use union"
|
||||
+ " instead.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
groupingInfo = new GroupingInfo(analyzer, groupByClause.getGroupingType());
|
||||
groupingInfo.substituteGroupingFn(resultExprs, analyzer);
|
||||
} else {
|
||||
|
||||
@ -0,0 +1,52 @@
|
||||
package org.apache.doris.analysis;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import org.apache.doris.catalog.Catalog;
|
||||
import org.apache.doris.common.AnalysisException;
|
||||
import org.apache.doris.qe.ConnectContext;
|
||||
import org.apache.doris.utframe.UtFrameUtils;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
public class SelectStmtTest {
|
||||
private static String runningDir = "fe/mocked/DemoTest/" + UUID.randomUUID().toString() + "/";
|
||||
|
||||
@Rule
|
||||
public ExpectedException expectedEx = ExpectedException.none();
|
||||
|
||||
@Test
|
||||
public void testGroupingSets() throws Exception {
|
||||
ConnectContext ctx = UtFrameUtils.createDefaultCtx();
|
||||
UtFrameUtils.createMinDorisCluster(runningDir);
|
||||
String createDbStmtStr = "create database db1;";
|
||||
CreateDbStmt createDbStmt = (CreateDbStmt) UtFrameUtils.parseAndAnalyzeStmt(createDbStmtStr, ctx);
|
||||
Catalog.getCurrentCatalog().createDb(createDbStmt);
|
||||
System.out.println(Catalog.getCurrentCatalog().getDbNames());
|
||||
// 3. create table tbl1
|
||||
String createTblStmtStr = "create table db1.tbl1(k1 varchar(32), k2 varchar(32), k3 varchar(32), k4 int) "
|
||||
+ "AGGREGATE KEY(k1, k2,k3,k4) distributed by hash(k1) buckets 3 properties('replication_num' = '1');";
|
||||
CreateTableStmt createTableStmt = (CreateTableStmt) UtFrameUtils.parseAndAnalyzeStmt(createTblStmtStr, ctx);
|
||||
Catalog.getCurrentCatalog().createTable(createTableStmt);
|
||||
String selectStmtStr = "select k1,k2,MAX(k4) from db1.tbl1 GROUP BY GROUPING sets ((k1,k2),(k1),(k2),());";
|
||||
UtFrameUtils.parseAndAnalyzeStmt(selectStmtStr, ctx);
|
||||
String selectStmtStr2 = "select k1,k4,MAX(k4) from db1.tbl1 GROUP BY GROUPING sets ((k1,k4),(k1),(k4),());";
|
||||
expectedEx.expect(AnalysisException.class);
|
||||
expectedEx.expectMessage("column: `k4` cannot both in select list and aggregate functions when using GROUPING"
|
||||
+ " SETS/CUBE/ROLLUP, please use union instead.");
|
||||
UtFrameUtils.parseAndAnalyzeStmt(selectStmtStr2, ctx);
|
||||
String selectStmtStr3 = "select k1,k4,MAX(k4+k4) from db1.tbl1 GROUP BY GROUPING sets ((k1,k4),(k1),(k4),());";
|
||||
UtFrameUtils.parseAndAnalyzeStmt(selectStmtStr3, ctx);
|
||||
String selectStmtStr4 = "select k1,k4+k4,MAX(k4+k4) from db1.tbl1 GROUP BY GROUPING sets ((k1,k4),(k1),(k4),()"
|
||||
+ ");";
|
||||
UtFrameUtils.parseAndAnalyzeStmt(selectStmtStr4, ctx);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -17,6 +17,7 @@
|
||||
|
||||
package org.apache.doris.utframe;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.doris.analysis.CreateDbStmt;
|
||||
import org.apache.doris.analysis.CreateTableStmt;
|
||||
import org.apache.doris.catalog.Catalog;
|
||||
@ -41,14 +42,16 @@ import com.google.common.base.Strings;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
|
||||
/*
|
||||
@ -69,18 +72,19 @@ public class AnotherDemoTest {
|
||||
|
||||
// use a unique dir so that it won't be conflict with other unit test which
|
||||
// may also start a Mocked Frontend
|
||||
private static String runningDir = "fe/mocked/AnotherDemoTest/" + UUID.randomUUID().toString() + "/";
|
||||
private static String runningDirBase = "fe";
|
||||
private static String runningDir = runningDirBase + "/mocked/AnotherDemoTest/" + UUID.randomUUID().toString() + "/";
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws EnvVarNotSetException, IOException,
|
||||
FeStartException, NotInitException, DdlException, InterruptedException {
|
||||
// get DORIS_HOME
|
||||
final String dorisHome = System.getenv("DORIS_HOME");
|
||||
String dorisHome = System.getenv("DORIS_HOME");
|
||||
if (Strings.isNullOrEmpty(dorisHome)) {
|
||||
throw new EnvVarNotSetException("env DORIS_HOME is not set");
|
||||
dorisHome = Files.createTempDirectory("DORIS_HOME").toAbsolutePath().toString();
|
||||
}
|
||||
|
||||
getRandomPort();
|
||||
getPorts();
|
||||
|
||||
// start fe in "DORIS_HOME/fe/mocked/"
|
||||
MockedFrontend frontend = MockedFrontend.getInstance();
|
||||
@ -111,19 +115,25 @@ public class AnotherDemoTest {
|
||||
Thread.sleep(5000);
|
||||
}
|
||||
|
||||
// generate all port from between 20000 ~ 30000
|
||||
private static void getRandomPort() {
|
||||
Random r = new Random(System.currentTimeMillis());
|
||||
int basePort = 20000 + r.nextInt(9000);
|
||||
fe_http_port = basePort + 1;
|
||||
fe_rpc_port = basePort + 2;
|
||||
fe_query_port = basePort + 3;
|
||||
fe_edit_log_port = basePort + 4;
|
||||
@AfterClass
|
||||
public static void TearDown() {
|
||||
try {
|
||||
FileUtils.deleteDirectory(new File(runningDirBase));
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
|
||||
be_heartbeat_port = basePort + 5;
|
||||
be_thrift_port = basePort + 6;
|
||||
be_brpc_port = basePort + 7;
|
||||
be_http_port = basePort + 8;
|
||||
// generate all port from valid ports
|
||||
private static void getPorts() {
|
||||
fe_http_port = UtFrameUtils.findValidPort();
|
||||
fe_rpc_port = UtFrameUtils.findValidPort();
|
||||
fe_query_port = UtFrameUtils.findValidPort();
|
||||
fe_edit_log_port = UtFrameUtils.findValidPort();
|
||||
|
||||
be_heartbeat_port = UtFrameUtils.findValidPort();
|
||||
be_thrift_port = UtFrameUtils.findValidPort();
|
||||
be_brpc_port = UtFrameUtils.findValidPort();
|
||||
be_http_port = UtFrameUtils.findValidPort();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
|
||||
package org.apache.doris.utframe;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.doris.alter.AlterJobV2;
|
||||
import org.apache.doris.analysis.AlterTableStmt;
|
||||
import org.apache.doris.analysis.CreateDbStmt;
|
||||
@ -43,14 +44,16 @@ import com.google.common.base.Strings;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
|
||||
/*
|
||||
@ -74,18 +77,19 @@ public class DemoTest {
|
||||
private static int be_http_port;
|
||||
// use a unique dir so that it won't be conflict with other unit test which
|
||||
// may also start a Mocked Frontend
|
||||
private static String runningDir = "fe/mocked/DemoTest/" + UUID.randomUUID().toString() + "/";
|
||||
private static String runningDirBase = "fe";
|
||||
private static String runningDir = runningDirBase + "/mocked/DemoTest/" + UUID.randomUUID().toString() + "/";
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws EnvVarNotSetException, IOException,
|
||||
FeStartException, NotInitException, DdlException, InterruptedException {
|
||||
// get DORIS_HOME
|
||||
final String dorisHome = System.getenv("DORIS_HOME");
|
||||
String dorisHome = System.getenv("DORIS_HOME");
|
||||
if (Strings.isNullOrEmpty(dorisHome)) {
|
||||
throw new EnvVarNotSetException("env DORIS_HOME is not set");
|
||||
dorisHome = Files.createTempDirectory("DORIS_HOME").toAbsolutePath().toString();
|
||||
}
|
||||
|
||||
getRandomPort();
|
||||
getPorts();
|
||||
|
||||
// start fe in "DORIS_HOME/fe/mocked/"
|
||||
MockedFrontend frontend = MockedFrontend.getInstance();
|
||||
@ -116,19 +120,26 @@ public class DemoTest {
|
||||
Thread.sleep(6000);
|
||||
}
|
||||
|
||||
// generate all port from between 20000 ~ 30000
|
||||
private static void getRandomPort() {
|
||||
Random r = new Random(System.currentTimeMillis());
|
||||
int basePort = 20000 + r.nextInt(9000);
|
||||
fe_http_port = basePort + 1;
|
||||
fe_rpc_port = basePort + 2;
|
||||
fe_query_port = basePort + 3;
|
||||
fe_edit_log_port = basePort + 4;
|
||||
|
||||
be_heartbeat_port = basePort + 5;
|
||||
be_thrift_port = basePort + 6;
|
||||
be_brpc_port = basePort + 7;
|
||||
be_http_port = basePort + 8;
|
||||
@AfterClass
|
||||
public static void TearDown() {
|
||||
try {
|
||||
FileUtils.deleteDirectory(new File(runningDirBase));
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
|
||||
// generate all port from valid ports
|
||||
private static void getPorts() {
|
||||
fe_http_port = UtFrameUtils.findValidPort();
|
||||
fe_rpc_port = UtFrameUtils.findValidPort();
|
||||
fe_query_port = UtFrameUtils.findValidPort();
|
||||
fe_edit_log_port = UtFrameUtils.findValidPort();
|
||||
|
||||
be_heartbeat_port = UtFrameUtils.findValidPort();
|
||||
be_thrift_port = UtFrameUtils.findValidPort();
|
||||
be_brpc_port = UtFrameUtils.findValidPort();
|
||||
be_http_port = UtFrameUtils.findValidPort();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@ -42,10 +42,11 @@ import com.google.common.collect.Maps;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.net.ServerSocket;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.nio.file.Files;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
||||
public class UtFrameUtils {
|
||||
|
||||
@ -77,22 +78,20 @@ public class UtFrameUtils {
|
||||
public static void createMinDorisCluster(String runningDir) throws EnvVarNotSetException, IOException,
|
||||
FeStartException, NotInitException, DdlException, InterruptedException {
|
||||
// get DORIS_HOME
|
||||
final String dorisHome = System.getenv("DORIS_HOME");
|
||||
String dorisHome = System.getenv("DORIS_HOME");
|
||||
if (Strings.isNullOrEmpty(dorisHome)) {
|
||||
throw new EnvVarNotSetException("env DORIS_HOME is not set");
|
||||
dorisHome = Files.createTempDirectory("DORIS_HOME").toAbsolutePath().toString();
|
||||
}
|
||||
|
||||
Random r = new Random(System.currentTimeMillis());
|
||||
int basePort = 20000 + r.nextInt(9000);
|
||||
int fe_http_port = basePort + 1;
|
||||
int fe_rpc_port = basePort + 2;
|
||||
int fe_query_port = basePort + 3;
|
||||
int fe_edit_log_port = basePort + 4;
|
||||
int fe_http_port = findValidPort();
|
||||
int fe_rpc_port = findValidPort();
|
||||
int fe_query_port = findValidPort();
|
||||
int fe_edit_log_port = findValidPort();
|
||||
|
||||
int be_heartbeat_port = basePort + 5;
|
||||
int be_thrift_port = basePort + 6;
|
||||
int be_brpc_port = basePort + 7;
|
||||
int be_http_port = basePort + 8;
|
||||
int be_heartbeat_port = findValidPort();
|
||||
int be_thrift_port = findValidPort();
|
||||
int be_brpc_port = findValidPort();
|
||||
int be_http_port = findValidPort();
|
||||
|
||||
// start fe in "DORIS_HOME/fe/mocked/"
|
||||
MockedFrontend frontend = MockedFrontend.getInstance();
|
||||
@ -122,4 +121,22 @@ public class UtFrameUtils {
|
||||
// sleep to wait first heartbeat
|
||||
Thread.sleep(6000);
|
||||
}
|
||||
|
||||
public static int findValidPort() {
|
||||
ServerSocket socket = null;
|
||||
try {
|
||||
socket = new ServerSocket(0);
|
||||
socket.setReuseAddress(true);
|
||||
return socket.getLocalPort();
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException("Could not find a free TCP/IP port to start HTTP Server on");
|
||||
} finally {
|
||||
if (socket != null) {
|
||||
try {
|
||||
socket.close();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user