Skip to content

Commit 3e6aab7

Browse files
committed
add explain analyze test cases
1 parent f1679f6 commit 3e6aab7

File tree

5 files changed

+304
-0
lines changed

5 files changed

+304
-0
lines changed

integration-test/src/main/java/org/apache/iotdb/it/env/cluster/config/MppCommonConfig.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -627,6 +627,18 @@ public CommonConfig setDatanodeMemoryProportion(String datanodeMemoryProportion)
627627
return this;
628628
}
629629

630+
@Override
631+
public CommonConfig setCteBufferSize(long cteBufferSize) {
632+
setProperty("cte_buffer_size_in_bytes", String.valueOf(cteBufferSize));
633+
return this;
634+
}
635+
636+
@Override
637+
public CommonConfig setMaxRowsInCteBuffer(int maxRows) {
638+
setProperty("max_rows_in_cte_buffer", String.valueOf(maxRows));
639+
return this;
640+
}
641+
630642
// For part of the log directory
631643
public String getClusterConfigStr() {
632644
return fromConsensusFullNameToAbbr(properties.getProperty(CONFIG_NODE_CONSENSUS_PROTOCOL_CLASS))

integration-test/src/main/java/org/apache/iotdb/it/env/cluster/config/MppSharedCommonConfig.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -656,4 +656,18 @@ public CommonConfig setDatanodeMemoryProportion(String datanodeMemoryProportion)
656656
cnConfig.setDatanodeMemoryProportion(datanodeMemoryProportion);
657657
return this;
658658
}
659+
660+
@Override
661+
public CommonConfig setCteBufferSize(long cteBufferSize) {
662+
dnConfig.setCteBufferSize(cteBufferSize);
663+
cnConfig.setCteBufferSize(cteBufferSize);
664+
return this;
665+
}
666+
667+
@Override
668+
public CommonConfig setMaxRowsInCteBuffer(int maxRows) {
669+
dnConfig.setMaxRowsInCteBuffer(maxRows);
670+
cnConfig.setMaxRowsInCteBuffer(maxRows);
671+
return this;
672+
}
659673
}

integration-test/src/main/java/org/apache/iotdb/it/env/remote/config/RemoteCommonConfig.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,4 +457,14 @@ public CommonConfig setTrustStorePwd(String trustStorePwd) {
457457
public CommonConfig setDatanodeMemoryProportion(String datanodeMemoryProportion) {
458458
return this;
459459
}
460+
461+
@Override
462+
public CommonConfig setCteBufferSize(long cteBufferSize) {
463+
return this;
464+
}
465+
466+
@Override
467+
public CommonConfig setMaxRowsInCteBuffer(int maxRows) {
468+
return this;
469+
}
460470
}

integration-test/src/main/java/org/apache/iotdb/itbase/env/CommonConfig.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,4 +203,8 @@ default CommonConfig setDefaultStorageGroupLevel(int defaultStorageGroupLevel) {
203203
CommonConfig setTrustStorePwd(String trustStorePwd);
204204

205205
CommonConfig setDatanodeMemoryProportion(String datanodeMemoryProportion);
206+
207+
CommonConfig setCteBufferSize(long cteBufferSize);
208+
209+
CommonConfig setMaxRowsInCteBuffer(int maxRows);
206210
}
Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
/*
2+
*
3+
* * Licensed to the Apache Software Foundation (ASF) under one
4+
* * or more contributor license agreements. See the NOTICE file
5+
* * distributed with this work for additional information
6+
* * regarding copyright ownership. The ASF licenses this file
7+
* * to you under the Apache License, Version 2.0 (the
8+
* * "License"); you may not use this file except in compliance
9+
* * with the License. You may obtain a copy of the License at
10+
* *
11+
* * http://www.apache.org/licenses/LICENSE-2.0
12+
* *
13+
* * Unless required by applicable law or agreed to in writing,
14+
* * software distributed under the License is distributed on an
15+
* * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16+
* * KIND, either express or implied. See the License for the
17+
* * specific language governing permissions and limitations
18+
* * under the License.
19+
*
20+
*/
21+
22+
package org.apache.iotdb.relational.it.query.recent;
23+
24+
import org.apache.iotdb.it.env.EnvFactory;
25+
import org.apache.iotdb.it.framework.IoTDBTestRunner;
26+
import org.apache.iotdb.itbase.category.TableClusterIT;
27+
import org.apache.iotdb.itbase.category.TableLocalStandaloneIT;
28+
import org.apache.iotdb.itbase.env.BaseEnv;
29+
30+
import org.junit.After;
31+
import org.junit.AfterClass;
32+
import org.junit.Assert;
33+
import org.junit.Before;
34+
import org.junit.BeforeClass;
35+
import org.junit.Test;
36+
import org.junit.experimental.categories.Category;
37+
import org.junit.runner.RunWith;
38+
39+
import java.sql.Connection;
40+
import java.sql.ResultSet;
41+
import java.sql.SQLException;
42+
import java.sql.Statement;
43+
import java.util.Arrays;
44+
import java.util.Locale;
45+
import java.util.function.ToLongFunction;
46+
import java.util.regex.Matcher;
47+
import java.util.regex.Pattern;
48+
49+
import static org.junit.Assert.assertEquals;
50+
import static org.junit.Assert.fail;
51+
52+
@RunWith(IoTDBTestRunner.class)
53+
@Category({TableLocalStandaloneIT.class, TableClusterIT.class})
54+
public class IoTExplainAnalyzeIT {
55+
private static final String DATABASE_NAME = "testdb";
56+
57+
private static final String[] creationSqls =
58+
new String[] {
59+
"CREATE DATABASE IF NOT EXISTS testdb",
60+
"USE testdb",
61+
"CREATE TABLE IF NOT EXISTS testtb(deviceid STRING TAG, voltage FLOAT FIELD)",
62+
"INSERT INTO testtb VALUES(1000, 'd1', 100.0)",
63+
"INSERT INTO testtb VALUES(2000, 'd1', 200.0)",
64+
"INSERT INTO testtb VALUES(1000, 'd2', 300.0)",
65+
};
66+
67+
private static final String dropDbSqls = "DROP DATABASE IF EXISTS testdb";
68+
69+
@BeforeClass
70+
public static void setUpClass() {
71+
Locale.setDefault(Locale.ENGLISH);
72+
73+
EnvFactory.getEnv()
74+
.getConfig()
75+
.getCommonConfig()
76+
.setPartitionInterval(1000)
77+
.setMemtableSizeThreshold(10000)
78+
.setMaxRowsInCteBuffer(100);
79+
EnvFactory.getEnv().initClusterEnvironment();
80+
}
81+
82+
@AfterClass
83+
public static void tearDownClass() {
84+
EnvFactory.getEnv().cleanClusterEnvironment();
85+
}
86+
87+
@Before
88+
public void setUp() throws SQLException {
89+
prepareData();
90+
}
91+
92+
@After
93+
public void tearDown() {
94+
try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
95+
Statement statement = connection.createStatement()) {
96+
statement.execute(dropDbSqls);
97+
} catch (Exception e) {
98+
fail(e.getMessage());
99+
}
100+
}
101+
102+
@Test
103+
public void testEmptyCteQuery() throws SQLException {
104+
ResultSet resultSet = null;
105+
String sql =
106+
"explain analyze with cte1 as materialized (select * from testtb1) select * from testtb, cte1 where testtb.deviceid = cte1.deviceid";
107+
try (Connection conn = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
108+
Statement statement = conn.createStatement()) {
109+
statement.execute("Use testdb");
110+
statement.execute(
111+
"CREATE TABLE IF NOT EXISTS testtb1(deviceid STRING TAG, voltage FLOAT FIELD)");
112+
resultSet = statement.executeQuery(sql);
113+
StringBuilder sb = new StringBuilder();
114+
while (resultSet.next()) {
115+
sb.append(resultSet.getString(1)).append(System.lineSeparator());
116+
}
117+
String result = sb.toString();
118+
Assert.assertFalse(
119+
"Explain Analyze should not contain ExplainAnalyze node.",
120+
result.contains("ExplainAnalyzeNode"));
121+
122+
String[] lines = result.split(System.lineSeparator());
123+
Assert.assertTrue(lines.length > 3);
124+
Assert.assertEquals("CTE Query : 'cte1'", lines[0]);
125+
Assert.assertEquals("", lines[1]);
126+
Assert.assertEquals("Main Query", lines[2]);
127+
statement.execute("DROP TABLE testtb1");
128+
} finally {
129+
if (resultSet != null) {
130+
resultSet.close();
131+
}
132+
}
133+
}
134+
135+
@Test
136+
public void testCteQueryExceedsThreshold() throws SQLException {
137+
ResultSet resultSet = null;
138+
String sql =
139+
"explain analyze with cte1 as materialized (select * from testtb2) select * from testtb where testtb.deviceid in (select deviceid from cte1)";
140+
try (Connection conn = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
141+
Statement statement = conn.createStatement()) {
142+
statement.execute("Use testdb");
143+
statement.execute(
144+
"CREATE TABLE IF NOT EXISTS testtb2(deviceid STRING TAG, voltage FLOAT FIELD)");
145+
for (int i = 0; i < 100; i++) {
146+
statement.addBatch(
147+
String.format("insert into testtb2(deviceid, voltage) values('d%d', %d)", i, i));
148+
}
149+
statement.executeBatch();
150+
resultSet = statement.executeQuery(sql);
151+
StringBuilder sb = new StringBuilder();
152+
while (resultSet.next()) {
153+
sb.append(resultSet.getString(1)).append(System.lineSeparator());
154+
}
155+
156+
String result = sb.toString();
157+
Assert.assertFalse(
158+
"Main Query should not contain CteScan node when the CTE query's result set exceeds threshold.",
159+
result.contains("CteScanNode(CteScanOperator)"));
160+
Assert.assertTrue(
161+
"CTE Query should contain warning message when CTE query's result set exceeds threshold.",
162+
result.contains("Failed to materialize CTE"));
163+
Assert.assertFalse(
164+
"Explain Analyze should not contain ExplainAnalyze node.",
165+
result.contains("ExplainAnalyzeNode"));
166+
167+
String[] plans = result.split("Main Query");
168+
for (String plan : plans) {
169+
String[] lines = plan.split(System.lineSeparator());
170+
long[] instanceCount =
171+
Arrays.stream(lines)
172+
.filter(line -> line.contains("Fragment Instances Count:"))
173+
.mapToLong(extractNumber("Fragment Instances Count:\\s(\\d+)"))
174+
.toArray();
175+
assertEquals(instanceCount.length, 1);
176+
177+
long totalInstances =
178+
Arrays.stream(lines).filter(line -> line.contains("FRAGMENT-INSTANCE")).count();
179+
assertEquals(totalInstances, instanceCount[0]);
180+
}
181+
182+
statement.execute("DROP TABLE testtb2");
183+
} finally {
184+
if (resultSet != null) {
185+
resultSet.close();
186+
}
187+
}
188+
}
189+
190+
@Test
191+
public void testCteQuerySuccess() throws SQLException {
192+
ResultSet resultSet = null;
193+
String sql =
194+
"explain analyze with cte1 as materialized (select * from testtb3) select * from testtb where testtb.deviceid in (select deviceid from cte1)";
195+
try (Connection conn = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
196+
Statement statement = conn.createStatement()) {
197+
statement.execute("Use testdb");
198+
statement.execute(
199+
"CREATE TABLE IF NOT EXISTS testtb3(deviceid STRING TAG, voltage FLOAT FIELD)");
200+
for (int i = 0; i < 50; i++) {
201+
statement.addBatch(
202+
String.format("insert into testtb3(deviceid, voltage) values('d%d', %d)", i, i));
203+
}
204+
statement.executeBatch();
205+
resultSet = statement.executeQuery(sql);
206+
StringBuilder sb = new StringBuilder();
207+
while (resultSet.next()) {
208+
sb.append(resultSet.getString(1)).append(System.lineSeparator());
209+
}
210+
211+
String result = sb.toString();
212+
Assert.assertTrue(
213+
"Main Query should contain CteScan node when the CTE query's result set exceeds threshold.",
214+
result.contains("CteScanNode(CteScanOperator)"));
215+
Assert.assertFalse(
216+
"Explain Analyze should not contain ExplainAnalyze node.",
217+
result.contains("ExplainAnalyzeNode"));
218+
219+
String[] plans = result.split("Main Query");
220+
for (String plan : plans) {
221+
String[] lines = plan.split(System.lineSeparator());
222+
long[] instanceCount =
223+
Arrays.stream(lines)
224+
.filter(line -> line.contains("Fragment Instances Count:"))
225+
.mapToLong(extractNumber("Fragment Instances Count:\\s(\\d+)"))
226+
.toArray();
227+
assertEquals(instanceCount.length, 1);
228+
229+
long totalInstances =
230+
Arrays.stream(lines).filter(line -> line.contains("FRAGMENT-INSTANCE")).count();
231+
assertEquals(totalInstances, instanceCount[0]);
232+
}
233+
234+
statement.execute("DROP TABLE testtb3");
235+
} finally {
236+
if (resultSet != null) {
237+
resultSet.close();
238+
}
239+
}
240+
}
241+
242+
private static ToLongFunction<String> extractNumber(String regex) {
243+
return line -> {
244+
Pattern pattern = Pattern.compile(regex);
245+
Matcher matcher = pattern.matcher(line);
246+
if (matcher.find()) {
247+
return Long.parseLong(matcher.group(1));
248+
}
249+
return 0;
250+
};
251+
}
252+
253+
private static void prepareData() {
254+
try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
255+
Statement statement = connection.createStatement()) {
256+
257+
for (String sql : creationSqls) {
258+
statement.execute(sql);
259+
}
260+
} catch (Exception e) {
261+
fail(e.getMessage());
262+
}
263+
}
264+
}

0 commit comments

Comments
 (0)