This is an automated email from the ASF dual-hosted git repository.
jt2594838 pushed a commit to branch dev/1.3
in repository https://gitbox.apache.org/repos/asf/iotdb.git
The following commit(s) were added to refs/heads/dev/1.3 by this push:
new 3c959c399e2 Excluded system & audit from COUNT TIMESERIES and included
views (#17703) (#17792)
3c959c399e2 is described below
commit 3c959c399e25b92c4e54050a367b6c171b8322dc
Author: Caideyipi <[email protected]>
AuthorDate: Tue Jun 2 15:09:17 2026 +0800
Excluded system & audit from COUNT TIMESERIES and included views (#17703)
(#17792)
(cherry picked from commit 312d3841a9715f3ad24394ff38bb5ceccfb5183a)
---
.../iotdb/db/it/schema/IoTDBMetadataFetchIT.java | 28 +++++
.../regionscan/IoTDBActiveSchemaQueryIT.java | 34 +++++
.../db/queryengine/common/TimeseriesContext.java | 106 +++++++++++++++-
.../schema/CountGroupByLevelScanOperator.java | 15 ++-
.../operator/schema/SchemaCountOperator.java | 4 +
.../operator/schema/source/ISchemaSource.java | 13 ++
.../schema/source/SchemaSourceFactory.java | 4 +-
.../schema/source/TimeSeriesSchemaSource.java | 20 +++
.../source/ActiveTimeSeriesRegionScanOperator.java | 15 ++-
.../queryengine/plan/analyze/AnalyzeVisitor.java | 136 +++++++++++++++++---
.../plan/planner/OperatorTreeGenerator.java | 33 ++++-
.../operator/schema/SchemaCountOperatorTest.java | 113 +++++++++++++++++
.../schema/source/TimeSeriesSchemaSourceTest.java | 137 +++++++++++++++++++++
13 files changed, 626 insertions(+), 32 deletions(-)
diff --git
a/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBMetadataFetchIT.java
b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBMetadataFetchIT.java
index 2f1d4e5bed4..4d0c873664d 100644
---
a/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBMetadataFetchIT.java
+++
b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBMetadataFetchIT.java
@@ -26,6 +26,7 @@ import org.apache.iotdb.util.AbstractSchemaIT;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runners.Parameterized;
@@ -494,6 +495,26 @@ public class IoTDBMetadataFetchIT extends AbstractSchemaIT
{
}
}
+ @Test
+ @Ignore
+ public void showCountTimeSeriesExcludeInternalDatabaseAndIncludeView()
throws SQLException {
+ try (Connection connection = EnvFactory.getEnv().getConnection();
+ Statement statement = connection.createStatement()) {
+ final long baseVisibleCount = queryCount(statement, "COUNT TIMESERIES
root.ln*.**");
+ statement.execute("CREATE DATABASE root.count_it");
+ statement.execute(
+ "CREATE TIMESERIES root.count_it.src.s1 WITH DATATYPE = INT32,
ENCODING = PLAIN");
+ statement.execute(
+ "CREATE TIMESERIES root.count_it.src.s2 WITH DATATYPE = INT32,
ENCODING = PLAIN");
+ statement.execute("CREATE VIEW root.count_it.dst.v1 AS SELECT s1 FROM
root.count_it.src;");
+
+ final long localCount = queryCount(statement, "COUNT TIMESERIES
root.count_it.**");
+ assertEquals(3L, localCount);
+ assertEquals(
+ baseVisibleCount + localCount, queryCount(statement, "COUNT
TIMESERIES root.**"));
+ }
+ }
+
@Test
public void showCountTimeSeriesWithTag() throws SQLException {
try (Connection connection = EnvFactory.getEnv().getConnection();
@@ -865,4 +886,11 @@ public class IoTDBMetadataFetchIT extends AbstractSchemaIT
{
}
}
}
+
+ private long queryCount(final Statement statement, final String sql) throws
SQLException {
+ try (ResultSet resultSet = statement.executeQuery(sql)) {
+ Assert.assertTrue(resultSet.next());
+ return resultSet.getLong(1);
+ }
+ }
}
diff --git
a/integration-test/src/test/java/org/apache/iotdb/db/it/schema/regionscan/IoTDBActiveSchemaQueryIT.java
b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/regionscan/IoTDBActiveSchemaQueryIT.java
index 853ef3c87ae..98713b94767 100644
---
a/integration-test/src/test/java/org/apache/iotdb/db/it/schema/regionscan/IoTDBActiveSchemaQueryIT.java
+++
b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/regionscan/IoTDBActiveSchemaQueryIT.java
@@ -27,6 +27,7 @@ import org.apache.iotdb.util.AbstractSchemaIT;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runners.Parameterized;
@@ -235,6 +236,39 @@ public class IoTDBActiveSchemaQueryIT extends
AbstractSchemaIT {
}
}
+ @Test
+ @Ignore
+ public void testCountTimeSeriesWithTimeConditionIncludesView() {
+ try (Connection connection = EnvFactory.getEnv().getConnection();
+ Statement statement = connection.createStatement()) {
+ statement.execute("CREATE DATABASE root.view_count");
+ statement.execute(
+ "CREATE TIMESERIES root.view_count.src.s1 WITH DATATYPE = INT32,
ENCODING = PLAIN");
+ statement.execute(
+ "CREATE TIMESERIES root.view_count.src.s2 WITH DATATYPE = INT32,
ENCODING = PLAIN");
+ statement.execute("CREATE VIEW root.view_count.dst.v1 AS SELECT s1 FROM
root.view_count.src");
+
+ checkResultSet(
+ statement,
+ "count timeseries root.view_count.**",
+ new HashSet<>(Collections.singletonList("3,")));
+
+ statement.execute("insert into root.view_count.src(timestamp,s1)
values(1,1)");
+
+ checkResultSet(
+ statement,
+ "count timeseries root.view_count.** where time>0",
+ new HashSet<>(Collections.singletonList("2,")));
+ checkResultSet(
+ statement,
+ "count timeseries root.view_count.dst.** where time>0",
+ new HashSet<>(Collections.singletonList("1,")));
+ } catch (Exception e) {
+ e.printStackTrace();
+ Assert.fail(e.getMessage());
+ }
+ }
+
@Test
public void testShowDevices() {
try (Connection connection = EnvFactory.getEnv().getConnection();
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/TimeseriesContext.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/TimeseriesContext.java
index 9225b97fc70..aaf8b51787d 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/TimeseriesContext.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/TimeseriesContext.java
@@ -28,7 +28,10 @@ import org.apache.tsfile.utils.ReadWriteIOUtils;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.HashSet;
import java.util.Objects;
+import java.util.Set;
import static
org.apache.iotdb.db.queryengine.execution.operator.schema.source.TimeSeriesSchemaSource.mapToString;
@@ -42,8 +45,17 @@ public class TimeseriesContext {
private final String deadband;
private final String deadbandParameters;
+ private final int activeCountMultiplier;
+ private final Set<String> activeLogicalViewCountSet;
public TimeseriesContext(IMeasurementSchemaInfo schemaInfo) {
+ this(schemaInfo, 1, Collections.emptySet());
+ }
+
+ public TimeseriesContext(
+ IMeasurementSchemaInfo schemaInfo,
+ int activeCountMultiplier,
+ Set<String> activeLogicalViewCountSet) {
this.dataType = schemaInfo.getSchema().getType().toString();
this.encoding = schemaInfo.getSchema().getEncodingType().toString();
this.compression = schemaInfo.getSchema().getCompressor().toString();
@@ -54,6 +66,8 @@ public class TimeseriesContext {
MetaUtils.parseDeadbandInfo(schemaInfo.getSchema().getProps());
this.deadband = deadbandInfo.left;
this.deadbandParameters = deadbandInfo.right;
+ this.activeCountMultiplier = activeCountMultiplier;
+ this.activeLogicalViewCountSet = new HashSet<>(activeLogicalViewCountSet);
}
public String getDataType() {
@@ -88,6 +102,14 @@ public class TimeseriesContext {
return deadband;
}
+ public int getActiveCountMultiplier() {
+ return activeCountMultiplier;
+ }
+
+ public Set<String> getActiveLogicalViewCountSet() {
+ return activeLogicalViewCountSet;
+ }
+
public TimeseriesContext(
String dataType,
String alias,
@@ -97,6 +119,30 @@ public class TimeseriesContext {
String attributes,
String deadband,
String deadbandParameters) {
+ this(
+ dataType,
+ alias,
+ encoding,
+ compression,
+ tags,
+ attributes,
+ deadband,
+ deadbandParameters,
+ 1,
+ Collections.emptySet());
+ }
+
+ public TimeseriesContext(
+ String dataType,
+ String alias,
+ String encoding,
+ String compression,
+ String tags,
+ String attributes,
+ String deadband,
+ String deadbandParameters,
+ int activeCountMultiplier,
+ Set<String> activeLogicalViewCountSet) {
this.dataType = dataType;
this.alias = alias;
this.encoding = encoding;
@@ -105,6 +151,24 @@ public class TimeseriesContext {
this.attributes = attributes;
this.deadband = deadband;
this.deadbandParameters = deadbandParameters;
+ this.activeCountMultiplier = activeCountMultiplier;
+ this.activeLogicalViewCountSet = new HashSet<>(activeLogicalViewCountSet);
+ }
+
+ public TimeseriesContext mergeActiveCount(TimeseriesContext that) {
+ Set<String> mergedActiveLogicalViewCountSet = new
HashSet<>(activeLogicalViewCountSet);
+ mergedActiveLogicalViewCountSet.addAll(that.activeLogicalViewCountSet);
+ return new TimeseriesContext(
+ dataType,
+ alias,
+ encoding,
+ compression,
+ tags,
+ attributes,
+ deadband,
+ deadbandParameters,
+ activeCountMultiplier + that.activeCountMultiplier,
+ mergedActiveLogicalViewCountSet);
}
public void serializeAttributes(ByteBuffer byteBuffer) {
@@ -116,6 +180,11 @@ public class TimeseriesContext {
ReadWriteIOUtils.write(attributes, byteBuffer);
ReadWriteIOUtils.write(deadband, byteBuffer);
ReadWriteIOUtils.write(deadbandParameters, byteBuffer);
+ ReadWriteIOUtils.write(activeCountMultiplier, byteBuffer);
+ ReadWriteIOUtils.write(activeLogicalViewCountSet.size(), byteBuffer);
+ for (String logicalView : activeLogicalViewCountSet) {
+ ReadWriteIOUtils.write(logicalView, byteBuffer);
+ }
}
public void serializeAttributes(DataOutputStream stream) throws IOException {
@@ -127,6 +196,11 @@ public class TimeseriesContext {
ReadWriteIOUtils.write(attributes, stream);
ReadWriteIOUtils.write(deadband, stream);
ReadWriteIOUtils.write(deadbandParameters, stream);
+ ReadWriteIOUtils.write(activeCountMultiplier, stream);
+ ReadWriteIOUtils.write(activeLogicalViewCountSet.size(), stream);
+ for (String logicalView : activeLogicalViewCountSet) {
+ ReadWriteIOUtils.write(logicalView, stream);
+ }
}
public static TimeseriesContext deserialize(ByteBuffer buffer) {
@@ -138,8 +212,23 @@ public class TimeseriesContext {
String attributes = ReadWriteIOUtils.readString(buffer);
String deadband = ReadWriteIOUtils.readString(buffer);
String deadbandParameters = ReadWriteIOUtils.readString(buffer);
+ int activeCountMultiplier = ReadWriteIOUtils.readInt(buffer);
+ int activeLogicalViewCountSetSize = ReadWriteIOUtils.readInt(buffer);
+ Set<String> activeLogicalViewCountSet = new HashSet<>();
+ for (int i = 0; i < activeLogicalViewCountSetSize; i++) {
+ activeLogicalViewCountSet.add(ReadWriteIOUtils.readString(buffer));
+ }
return new TimeseriesContext(
- dataType, alias, encoding, compression, tags, attributes, deadband,
deadbandParameters);
+ dataType,
+ alias,
+ encoding,
+ compression,
+ tags,
+ attributes,
+ deadband,
+ deadbandParameters,
+ activeCountMultiplier,
+ activeLogicalViewCountSet);
}
@Override
@@ -159,13 +248,24 @@ public class TimeseriesContext {
&& Objects.equals(tags, that.tags)
&& Objects.equals(attributes, that.attributes)
&& Objects.equals(deadband, that.deadband)
- && Objects.equals(deadbandParameters, that.deadbandParameters);
+ && Objects.equals(deadbandParameters, that.deadbandParameters)
+ && activeCountMultiplier == that.activeCountMultiplier
+ && Objects.equals(activeLogicalViewCountSet,
that.activeLogicalViewCountSet);
return res;
}
@Override
public int hashCode() {
return Objects.hash(
- dataType, alias, encoding, compression, tags, attributes, deadband,
deadbandParameters);
+ dataType,
+ alias,
+ encoding,
+ compression,
+ tags,
+ attributes,
+ deadband,
+ deadbandParameters,
+ activeCountMultiplier,
+ activeLogicalViewCountSet);
}
}
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/CountGroupByLevelScanOperator.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/CountGroupByLevelScanOperator.java
index 084935f68b0..8d46f25327c 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/CountGroupByLevelScanOperator.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/CountGroupByLevelScanOperator.java
@@ -27,6 +27,7 @@ import
org.apache.iotdb.db.queryengine.execution.operator.OperatorContext;
import
org.apache.iotdb.db.queryengine.execution.operator.schema.source.ISchemaSource;
import
org.apache.iotdb.db.queryengine.execution.operator.source.SourceOperator;
import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeId;
+import org.apache.iotdb.db.schemaengine.schemaregion.ISchemaRegion;
import
org.apache.iotdb.db.schemaengine.schemaregion.read.resp.info.ISchemaInfo;
import
org.apache.iotdb.db.schemaengine.schemaregion.read.resp.reader.ISchemaReader;
@@ -95,6 +96,10 @@ public class CountGroupByLevelScanOperator<T extends
ISchemaInfo> implements Sou
return operatorContext;
}
+ private ISchemaRegion getSchemaRegion() {
+ return ((SchemaDriverContext)
operatorContext.getDriverContext()).getSchemaRegion();
+ }
+
@Override
public ListenableFuture<?> isBlocked() {
if (isBlocked == null) {
@@ -109,6 +114,11 @@ public class CountGroupByLevelScanOperator<T extends
ISchemaInfo> implements Sou
*/
private ListenableFuture<?> tryGetNext() {
if (schemaReader == null) {
+ if (schemaSource.shouldSkipSchemaRegion(getSchemaRegion())) {
+ next = null;
+ isFinished = true;
+ return NOT_BLOCKED;
+ }
schemaReader = createTimeSeriesReader();
}
while (true) {
@@ -172,15 +182,14 @@ public class CountGroupByLevelScanOperator<T extends
ISchemaInfo> implements Sou
@Override
public boolean hasNext() throws Exception {
isBlocked().get(); // wait for the next TsBlock
- if (!schemaReader.isSuccess()) {
+ if (schemaReader != null && !schemaReader.isSuccess()) {
throw new SchemaExecutionException(schemaReader.getFailure());
}
return next != null;
}
public ISchemaReader<T> createTimeSeriesReader() {
- return schemaSource.getSchemaReader(
- ((SchemaDriverContext)
operatorContext.getDriverContext()).getSchemaRegion());
+ return schemaSource.getSchemaReader(getSchemaRegion());
}
private TsBlock constructTsBlockAndClearMap(Map<PartialPath, Long> countMap)
{
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/SchemaCountOperator.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/SchemaCountOperator.java
index 91c7ebda26b..9e7e935dd33 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/SchemaCountOperator.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/SchemaCountOperator.java
@@ -93,6 +93,10 @@ public class SchemaCountOperator<T extends ISchemaInfo>
implements SourceOperato
*/
private ListenableFuture<?> tryGetNext() {
ISchemaRegion schemaRegion = getSchemaRegion();
+ if (schemaSource.shouldSkipSchemaRegion(schemaRegion)) {
+ next = constructTsBlock(0);
+ return NOT_BLOCKED;
+ }
if (schemaSource.hasSchemaStatistic(schemaRegion)) {
next = constructTsBlock(schemaSource.getSchemaStatistic(schemaRegion));
return NOT_BLOCKED;
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/ISchemaSource.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/ISchemaSource.java
index 2a80e1071e5..573c7e35f06 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/ISchemaSource.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/ISchemaSource.java
@@ -24,6 +24,7 @@ import
org.apache.iotdb.db.schemaengine.schemaregion.ISchemaRegion;
import
org.apache.iotdb.db.schemaengine.schemaregion.read.resp.info.ISchemaInfo;
import
org.apache.iotdb.db.schemaengine.schemaregion.read.resp.reader.ISchemaReader;
+import org.apache.tsfile.common.conf.TSFileDescriptor;
import org.apache.tsfile.read.common.block.TsBlockBuilder;
import java.util.List;
@@ -52,4 +53,16 @@ public interface ISchemaSource<T extends ISchemaInfo> {
boolean hasSchemaStatistic(ISchemaRegion schemaRegion);
long getSchemaStatistic(ISchemaRegion schemaRegion);
+
+ default boolean shouldSkipSchemaRegion(ISchemaRegion schemaRegion) {
+ return false;
+ }
+
+ default boolean checkRegionDatabaseIncluded(ISchemaRegion schemaRegion) {
+ return true;
+ }
+
+ default long getMaxMemory(ISchemaRegion schemaRegion) {
+ return
TSFileDescriptor.getInstance().getConfig().getMaxTsBlockSizeInBytes();
+ }
}
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/SchemaSourceFactory.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/SchemaSourceFactory.java
index 7fe10842579..8a0e4abf3f7 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/SchemaSourceFactory.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/SchemaSourceFactory.java
@@ -44,7 +44,7 @@ public class SchemaSourceFactory {
Map<Integer, Template> templateMap,
PathPatternTree scope) {
return new TimeSeriesSchemaSource(
- pathPattern, isPrefixMatch, 0, 0, schemaFilter, templateMap, false,
scope);
+ pathPattern, isPrefixMatch, 0, 0, schemaFilter, templateMap, false,
true, scope);
}
// show time series
@@ -57,7 +57,7 @@ public class SchemaSourceFactory {
Map<Integer, Template> templateMap,
PathPatternTree scope) {
return new TimeSeriesSchemaSource(
- pathPattern, isPrefixMatch, limit, offset, schemaFilter, templateMap,
true, scope);
+ pathPattern, isPrefixMatch, limit, offset, schemaFilter, templateMap,
true, false, scope);
}
// count device
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/TimeSeriesSchemaSource.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/TimeSeriesSchemaSource.java
index 47b73ccb0e5..cc47a9361b6 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/TimeSeriesSchemaSource.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/TimeSeriesSchemaSource.java
@@ -54,6 +54,7 @@ public class TimeSeriesSchemaSource implements
ISchemaSource<ITimeSeriesSchemaIn
private final SchemaFilter schemaFilter;
private final Map<Integer, Template> templateMap;
private final boolean needViewDetail;
+ private final boolean excludeInternalDatabase;
TimeSeriesSchemaSource(
PartialPath pathPattern,
@@ -63,6 +64,7 @@ public class TimeSeriesSchemaSource implements
ISchemaSource<ITimeSeriesSchemaIn
SchemaFilter schemaFilter,
Map<Integer, Template> templateMap,
boolean needViewDetail,
+ boolean excludeInternalDatabase,
PathPatternTree scope) {
this.pathPattern = pathPattern;
this.isPrefixMatch = isPrefixMatch;
@@ -71,6 +73,7 @@ public class TimeSeriesSchemaSource implements
ISchemaSource<ITimeSeriesSchemaIn
this.schemaFilter = schemaFilter;
this.templateMap = templateMap;
this.needViewDetail = needViewDetail;
+ this.excludeInternalDatabase = excludeInternalDatabase;
this.scope = scope;
}
@@ -136,6 +139,23 @@ public class TimeSeriesSchemaSource implements
ISchemaSource<ITimeSeriesSchemaIn
return schemaRegion.getSchemaRegionStatistics().getSeriesNumber(true);
}
+ @Override
+ public boolean shouldSkipSchemaRegion(final ISchemaRegion schemaRegion) {
+ if (!excludeInternalDatabase) {
+ return false;
+ }
+
+ final String database = schemaRegion.getDatabaseFullPath();
+ if (!SchemaConstant.SYSTEM_DATABASE.equals(database)) {
+ return false;
+ }
+
+ final String[] nodes = pathPattern.getNodes();
+ return nodes.length < 2
+ || !SchemaConstant.ROOT.equals(nodes[0])
+ || !database.endsWith("." + nodes[1]);
+ }
+
public static String mapToString(Map<String, String> map) {
if (map == null || map.isEmpty()) {
return null;
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/ActiveTimeSeriesRegionScanOperator.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/ActiveTimeSeriesRegionScanOperator.java
index a9cbea64ddb..264bea0dd0e 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/ActiveTimeSeriesRegionScanOperator.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/ActiveTimeSeriesRegionScanOperator.java
@@ -36,13 +36,16 @@ import org.apache.tsfile.utils.Binary;
import org.apache.tsfile.utils.RamUsageEstimator;
import java.io.IOException;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.stream.Collectors;
public class ActiveTimeSeriesRegionScanOperator extends
AbstractRegionScanDataSourceOperator {
// Timeseries which need to be checked.
private final Map<IDeviceID, Map<String, TimeseriesContext>>
timeSeriesToSchemasInfo;
+ private final Set<String> countedLogicalViews;
private static final Binary VIEW_TYPE = new Binary("BASE".getBytes());
private final Binary dataBaseName;
private static final long INSTANCE_SIZE =
@@ -61,6 +64,7 @@ public class ActiveTimeSeriesRegionScanOperator extends
AbstractRegionScanDataSo
this.operatorContext = operatorContext;
this.sourceId = sourceId;
this.timeSeriesToSchemasInfo = timeSeriesToSchemasInfo;
+ this.countedLogicalViews = new HashSet<>();
this.regionScanUtil = new RegionScanForActiveTimeSeriesUtil(timeFilter,
ttlCache);
this.dataBaseName =
new Binary(
@@ -102,7 +106,16 @@ public class ActiveTimeSeriesRegionScanOperator extends
AbstractRegionScanDataSo
if (outputCount) {
for (Map.Entry<IDeviceID, List<String>> entry :
activeTimeSeries.entrySet()) {
List<String> timeSeriesList = entry.getValue();
- count += timeSeriesList.size();
+ Map<String, TimeseriesContext> timeSeriesInfo =
timeSeriesToSchemasInfo.get(entry.getKey());
+ for (String timeSeries : timeSeriesList) {
+ TimeseriesContext schemaInfo = timeSeriesInfo.get(timeSeries);
+ count += schemaInfo.getActiveCountMultiplier();
+ for (String logicalView : schemaInfo.getActiveLogicalViewCountSet())
{
+ if (countedLogicalViews.add(logicalView)) {
+ count++;
+ }
+ }
+ }
removeTimeseriesListFromDevice(entry.getKey(), timeSeriesList);
}
return;
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeVisitor.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeVisitor.java
index a28ca79c956..b4d056c1ff7 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeVisitor.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeVisitor.java
@@ -3112,7 +3112,8 @@ public class AnalyzeVisitor extends
StatementVisitor<Analysis, MPPQueryContext>
PathPatternTree patternTree,
Analysis analysis,
MPPQueryContext context,
- PathPatternTree authorityScope)
+ PathPatternTree authorityScope,
+ boolean includeLogicalView)
throws IllegalPathException {
analyzeGlobalTimeConditionInShowMetaData(timeCondition, analysis);
context.generateGlobalTimeFilter(analysis);
@@ -3124,7 +3125,15 @@ public class AnalyzeVisitor extends
StatementVisitor<Analysis, MPPQueryContext>
analysis.setFinishQueryAfterAnalyze(true);
return false;
}
- removeLogicViewMeasurement(schemaTree);
+ List<DeviceSchemaInfo> deviceSchemaInfoList;
+ if (includeLogicalView) {
+ deviceSchemaInfoList = schemaTree.getMatchedDevices(ALL_MATCH_PATTERN);
+ updateSchemaTreeByViews(analysis, schemaTree, context);
+ } else {
+ removeLogicViewMeasurement(schemaTree);
+ deviceSchemaInfoList = schemaTree.getMatchedDevices(ALL_MATCH_PATTERN);
+ }
+
Map<PartialPath, Map<PartialPath, List<TimeseriesContext>>>
deviceToTimeseriesContext =
new HashMap<>();
/**
@@ -3132,38 +3141,56 @@ public class AnalyzeVisitor extends
StatementVisitor<Analysis, MPPQueryContext>
* as a normal node, not a device+templateId. This means that all nodes
are what we need.). We
* can use ALL_MATCH_PATTERN to get result.
*/
- List<DeviceSchemaInfo> deviceSchemaInfoList =
schemaTree.getMatchedDevices(ALL_MATCH_PATTERN);
Set<String> deviceSet = new HashSet<>();
for (DeviceSchemaInfo deviceSchemaInfo : deviceSchemaInfoList) {
boolean isAligned = deviceSchemaInfo.isAligned();
PartialPath devicePath = deviceSchemaInfo.getDevicePath();
- deviceSet.add(devicePath.getFullPath());
if (isAligned) {
List<String> measurementList = new ArrayList<>();
List<IMeasurementSchema> schemaList = new ArrayList<>();
List<TimeseriesContext> timeseriesContextList = new ArrayList<>();
for (IMeasurementSchemaInfo measurementSchemaInfo :
deviceSchemaInfo.getMeasurementSchemaInfoList()) {
+ if (includeLogicalView && measurementSchemaInfo.isLogicalView()) {
+ addLogicalViewSourcesForActiveCount(
+ devicePath,
+ measurementSchemaInfo,
+ schemaTree,
+ deviceToTimeseriesContext,
+ deviceSet);
+ continue;
+ }
schemaList.add(measurementSchemaInfo.getSchema());
measurementList.add(measurementSchemaInfo.getName());
timeseriesContextList.add(new
TimeseriesContext(measurementSchemaInfo));
}
- AlignedPath alignedPath =
- new AlignedPath(devicePath.getNodes(), measurementList,
schemaList);
- deviceToTimeseriesContext
- .computeIfAbsent(devicePath, k -> new HashMap<>())
- .put(alignedPath, timeseriesContextList);
+ if (!measurementList.isEmpty()) {
+ deviceSet.add(devicePath.getFullPath());
+ AlignedPath alignedPath =
+ new AlignedPath(devicePath.getNodes(), measurementList,
schemaList);
+ deviceToTimeseriesContext
+ .computeIfAbsent(devicePath, k -> new HashMap<>())
+ .put(alignedPath, timeseriesContextList);
+ }
} else {
for (IMeasurementSchemaInfo measurementSchemaInfo :
deviceSchemaInfo.getMeasurementSchemaInfoList()) {
- MeasurementPath measurementPath =
- new MeasurementPath(
-
devicePath.concatNode(measurementSchemaInfo.getName()).getNodes());
- deviceToTimeseriesContext
- .computeIfAbsent(devicePath, k -> new HashMap<>())
- .put(
- measurementPath,
- Collections.singletonList(new
TimeseriesContext(measurementSchemaInfo)));
+ if (includeLogicalView && measurementSchemaInfo.isLogicalView()) {
+ addLogicalViewSourcesForActiveCount(
+ devicePath,
+ measurementSchemaInfo,
+ schemaTree,
+ deviceToTimeseriesContext,
+ deviceSet);
+ } else {
+ addPhysicalTimeseriesForActiveCount(
+ devicePath,
+ measurementSchemaInfo,
+ false,
+ new TimeseriesContext(measurementSchemaInfo),
+ deviceToTimeseriesContext,
+ deviceSet);
+ }
}
}
}
@@ -3175,6 +3202,75 @@ public class AnalyzeVisitor extends
StatementVisitor<Analysis, MPPQueryContext>
return true;
}
+ private void addLogicalViewSourcesForActiveCount(
+ PartialPath viewDevicePath,
+ IMeasurementSchemaInfo viewSchemaInfo,
+ ISchemaTree schemaTree,
+ Map<PartialPath, Map<PartialPath, List<TimeseriesContext>>>
deviceToTimeseriesContext,
+ Set<String> deviceSet) {
+ LogicalViewSchema logicalViewSchema =
viewSchemaInfo.getSchemaAsLogicalViewSchema();
+ if (logicalViewSchema == null) {
+ return;
+ }
+
+ String viewPath =
viewDevicePath.concatNode(viewSchemaInfo.getName()).getFullPath();
+ for (PartialPath sourcePath :
getSourcePaths(logicalViewSchema.getExpression())) {
+ if (sourcePath.getNodeLength() <= 1) {
+ continue;
+ }
+ PartialPath sourceDevicePath =
+ new PartialPath(Arrays.copyOf(sourcePath.getNodes(),
sourcePath.getNodeLength() - 1));
+ DeviceSchemaInfo sourceDeviceSchemaInfo =
+ schemaTree.searchDeviceSchemaInfo(
+ sourceDevicePath,
Collections.singletonList(sourcePath.getMeasurement()));
+ if (sourceDeviceSchemaInfo == null
+ || sourceDeviceSchemaInfo.getMeasurementSchemaInfoList().isEmpty()) {
+ continue;
+ }
+
+ IMeasurementSchemaInfo sourceSchemaInfo =
+ sourceDeviceSchemaInfo.getMeasurementSchemaInfoList().get(0);
+ if (sourceSchemaInfo == null || sourceSchemaInfo.isLogicalView()) {
+ continue;
+ }
+
+ addPhysicalTimeseriesForActiveCount(
+ sourceDevicePath,
+ sourceSchemaInfo,
+ sourceDeviceSchemaInfo.isAligned(),
+ new TimeseriesContext(sourceSchemaInfo, 0,
Collections.singleton(viewPath)),
+ deviceToTimeseriesContext,
+ deviceSet);
+ }
+ }
+
+ private void addPhysicalTimeseriesForActiveCount(
+ PartialPath devicePath,
+ IMeasurementSchemaInfo measurementSchemaInfo,
+ boolean isAligned,
+ TimeseriesContext timeseriesContext,
+ Map<PartialPath, Map<PartialPath, List<TimeseriesContext>>>
deviceToTimeseriesContext,
+ Set<String> deviceSet) {
+ deviceSet.add(devicePath.getFullPath());
+ PartialPath timeseriesPath =
+ isAligned
+ ? new AlignedPath(
+ devicePath.getNodes(),
+ Collections.singletonList(measurementSchemaInfo.getName()),
+ Collections.singletonList(measurementSchemaInfo.getSchema()))
+ : new MeasurementPath(
+
devicePath.concatNode(measurementSchemaInfo.getName()).getNodes());
+ Map<PartialPath, List<TimeseriesContext>> timeseriesContextMap =
+ deviceToTimeseriesContext.computeIfAbsent(devicePath, k -> new
HashMap<>());
+ List<TimeseriesContext> existingContextList =
timeseriesContextMap.get(timeseriesPath);
+ if (existingContextList == null) {
+ timeseriesContextMap.put(
+ timeseriesPath, new
ArrayList<>(Collections.singletonList(timeseriesContext)));
+ } else {
+ existingContextList.set(0,
existingContextList.get(0).mergeActiveCount(timeseriesContext));
+ }
+ }
+
@Override
public Analysis visitShowTimeSeries(
ShowTimeSeriesStatement showTimeSeriesStatement, MPPQueryContext
context) {
@@ -3193,7 +3289,8 @@ public class AnalyzeVisitor extends
StatementVisitor<Analysis, MPPQueryContext>
patternTree,
analysis,
context,
- showTimeSeriesStatement.getAuthorityScope());
+ showTimeSeriesStatement.getAuthorityScope(),
+ false);
if (!hasSchema) {
analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowTimeSeriesHeader());
return analysis;
@@ -3437,7 +3534,8 @@ public class AnalyzeVisitor extends
StatementVisitor<Analysis, MPPQueryContext>
patternTree,
analysis,
context,
- countTimeSeriesStatement.getAuthorityScope());
+ countTimeSeriesStatement.getAuthorityScope(),
+ true);
if (!hasSchema) {
analysis.setRespDatasetHeader(DatasetHeaderFactory.getCountTimeSeriesHeader());
return analysis;
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/OperatorTreeGenerator.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/OperatorTreeGenerator.java
index 0649f808c4f..c93912c27eb 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/OperatorTreeGenerator.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/OperatorTreeGenerator.java
@@ -3781,9 +3781,17 @@ public class OperatorTreeGenerator extends
PlanVisitor<Operator, LocalExecutionP
Map<String, TimeseriesContext> timeseriesSchemaInfoMap = new HashMap<>();
for (Map.Entry<PartialPath, List<TimeseriesContext>> entry :
entryMap.getValue().entrySet()) {
PartialPath path = entry.getKey();
- context.addPath(path);
if (path instanceof MeasurementPath) {
- timeseriesSchemaInfoMap.put(path.getMeasurement(),
entry.getValue().get(0));
+ String measurement = path.getMeasurement();
+ TimeseriesContext timeseriesContext = entry.getValue().get(0);
+ TimeseriesContext existingContext =
timeseriesSchemaInfoMap.get(measurement);
+ if (existingContext == null) {
+ timeseriesSchemaInfoMap.put(measurement, timeseriesContext);
+ context.addPath(path);
+ } else {
+ timeseriesSchemaInfoMap.put(
+ measurement,
existingContext.mergeActiveCount(timeseriesContext));
+ }
} else if (path instanceof AlignedPath) {
AlignedPath alignedPath = (AlignedPath) path;
List<String> measurementList = alignedPath.getMeasurementList();
@@ -3791,8 +3799,25 @@ public class OperatorTreeGenerator extends
PlanVisitor<Operator, LocalExecutionP
throw new IllegalArgumentException(
"The size of measurementList and timeseriesSchemaInfoList should
be equal in aligned path.");
}
- for (int i = 0; i < measurementList.size(); i++) {
- timeseriesSchemaInfoMap.put(measurementList.get(i),
entry.getValue().get(i));
+ int size = measurementList.size();
+ List<IMeasurementSchema> schemaList = new ArrayList<>(size);
+ List<String> newMeasurementList = new ArrayList<>(size);
+ List<IMeasurementSchema> alignedSchemaList =
alignedPath.getSchemaList();
+ for (int i = 0; i < size; i++) {
+ String measurement = measurementList.get(i);
+ TimeseriesContext timeseriesContext = entry.getValue().get(i);
+ TimeseriesContext existingContext =
timeseriesSchemaInfoMap.get(measurement);
+ if (existingContext == null) {
+ timeseriesSchemaInfoMap.put(measurement, timeseriesContext);
+ newMeasurementList.add(measurement);
+ schemaList.add(alignedSchemaList.get(i));
+ } else {
+ timeseriesSchemaInfoMap.put(
+ measurement,
existingContext.mergeActiveCount(timeseriesContext));
+ }
+ }
+ if (!newMeasurementList.isEmpty()) {
+ context.addPath(new AlignedPath(path.getNodes(), newMeasurementList,
schemaList));
}
}
}
diff --git
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/execution/operator/schema/SchemaCountOperatorTest.java
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/execution/operator/schema/SchemaCountOperatorTest.java
index 3bdd80a3c1b..c5e8335ebf5 100644
---
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/execution/operator/schema/SchemaCountOperatorTest.java
+++
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/execution/operator/schema/SchemaCountOperatorTest.java
@@ -114,6 +114,82 @@ public class SchemaCountOperatorTest {
}
}
+ @Test
+ public void testSchemaCountOperatorSkipSchemaRegion() throws Exception {
+ ExecutorService instanceNotificationExecutor =
+ IoTDBThreadPoolFactory.newFixedThreadPool(1,
"test-instance-notification");
+ try {
+ QueryId queryId = new QueryId("stub_query");
+ FragmentInstanceId instanceId =
+ new FragmentInstanceId(new PlanFragmentId(queryId, 0),
"stub-instance");
+ FragmentInstanceStateMachine stateMachine =
+ new FragmentInstanceStateMachine(instanceId,
instanceNotificationExecutor);
+ FragmentInstanceContext fragmentInstanceContext =
+ createFragmentInstanceContext(instanceId, stateMachine);
+ DriverContext driverContext = new DriverContext(fragmentInstanceContext,
0);
+ PlanNodeId planNodeId = queryId.genPlanNodeId();
+ ISchemaRegion schemaRegion = Mockito.mock(ISchemaRegion.class);
+ OperatorContext operatorContext =
+ driverContext.addOperatorContext(
+ 1, planNodeId, SchemaCountOperator.class.getSimpleName());
+ operatorContext.setDriverContext(
+ new SchemaDriverContext(fragmentInstanceContext, schemaRegion, 0));
+ ISchemaSource<ISchemaInfo> schemaSource =
Mockito.mock(ISchemaSource.class);
+
Mockito.when(schemaSource.shouldSkipSchemaRegion(schemaRegion)).thenReturn(true);
+
+ SchemaCountOperator<?> schemaCountOperator =
+ new SchemaCountOperator<>(
+ planNodeId, driverContext.getOperatorContexts().get(0),
schemaSource);
+
+ assertTrue(schemaCountOperator.hasNext());
+ TsBlock tsBlock = schemaCountOperator.next();
+ assertEquals(0, tsBlock.getColumn(0).getLong(0));
+ assertTrue(schemaCountOperator.isFinished());
+ Mockito.verify(schemaSource,
Mockito.never()).getSchemaReader(schemaRegion);
+ } finally {
+ instanceNotificationExecutor.shutdown();
+ }
+ }
+
+ @Test
+ public void testSchemaCountOperatorUseSchemaStatistic() throws Exception {
+ ExecutorService instanceNotificationExecutor =
+ IoTDBThreadPoolFactory.newFixedThreadPool(1,
"test-instance-notification");
+ try {
+ QueryId queryId = new QueryId("stub_query");
+ FragmentInstanceId instanceId =
+ new FragmentInstanceId(new PlanFragmentId(queryId, 0),
"stub-instance");
+ FragmentInstanceStateMachine stateMachine =
+ new FragmentInstanceStateMachine(instanceId,
instanceNotificationExecutor);
+ FragmentInstanceContext fragmentInstanceContext =
+ createFragmentInstanceContext(instanceId, stateMachine);
+ DriverContext driverContext = new DriverContext(fragmentInstanceContext,
0);
+ PlanNodeId planNodeId = queryId.genPlanNodeId();
+ ISchemaRegion schemaRegion = Mockito.mock(ISchemaRegion.class);
+ OperatorContext operatorContext =
+ driverContext.addOperatorContext(
+ 1, planNodeId, SchemaCountOperator.class.getSimpleName());
+ operatorContext.setDriverContext(
+ new SchemaDriverContext(fragmentInstanceContext, schemaRegion, 0));
+ ISchemaSource<ISchemaInfo> schemaSource =
Mockito.mock(ISchemaSource.class);
+
Mockito.when(schemaSource.hasSchemaStatistic(schemaRegion)).thenReturn(true);
+
Mockito.when(schemaSource.getSchemaStatistic(schemaRegion)).thenReturn(7L);
+
Mockito.when(schemaSource.checkRegionDatabaseIncluded(schemaRegion)).thenReturn(true);
+
+ SchemaCountOperator<?> schemaCountOperator =
+ new SchemaCountOperator<>(
+ planNodeId, driverContext.getOperatorContexts().get(0),
schemaSource);
+
+ assertTrue(schemaCountOperator.hasNext());
+ TsBlock tsBlock = schemaCountOperator.next();
+ assertEquals(7, tsBlock.getColumn(0).getLong(0));
+ Mockito.verify(schemaSource).getSchemaStatistic(schemaRegion);
+ Mockito.verify(schemaSource,
Mockito.never()).getSchemaReader(schemaRegion);
+ } finally {
+ instanceNotificationExecutor.shutdown();
+ }
+ }
+
@Test
public void testLevelTimeSeriesCountOperator() {
ExecutorService instanceNotificationExecutor =
@@ -185,6 +261,43 @@ public class SchemaCountOperatorTest {
}
}
+ @Test
+ public void testLevelTimeSeriesCountOperatorSkipSchemaRegion() {
+ ExecutorService instanceNotificationExecutor =
+ IoTDBThreadPoolFactory.newFixedThreadPool(1,
"test-instance-notification");
+ try {
+ QueryId queryId = new QueryId("stub_query");
+ FragmentInstanceId instanceId =
+ new FragmentInstanceId(new PlanFragmentId(queryId, 0),
"stub-instance");
+ FragmentInstanceStateMachine stateMachine =
+ new FragmentInstanceStateMachine(instanceId,
instanceNotificationExecutor);
+ FragmentInstanceContext fragmentInstanceContext =
+ createFragmentInstanceContext(instanceId, stateMachine);
+ DriverContext driverContext = new DriverContext(fragmentInstanceContext,
0);
+ PlanNodeId planNodeId = queryId.genPlanNodeId();
+ OperatorContext operatorContext =
+ driverContext.addOperatorContext(
+ 1, planNodeId,
CountGroupByLevelScanOperator.class.getSimpleName());
+ ISchemaRegion schemaRegion = Mockito.mock(ISchemaRegion.class);
+ operatorContext.setDriverContext(
+ new SchemaDriverContext(fragmentInstanceContext, schemaRegion, 0));
+ ISchemaSource<ITimeSeriesSchemaInfo> schemaSource =
Mockito.mock(ISchemaSource.class);
+
Mockito.when(schemaSource.shouldSkipSchemaRegion(schemaRegion)).thenReturn(true);
+
+ CountGroupByLevelScanOperator<ITimeSeriesSchemaInfo>
timeSeriesCountOperator =
+ new CountGroupByLevelScanOperator<>(
+ planNodeId, driverContext.getOperatorContexts().get(0), 1,
schemaSource);
+
+ assertTrue(collectResult(timeSeriesCountOperator).isEmpty());
+ Mockito.verify(schemaSource,
Mockito.never()).getSchemaReader(schemaRegion);
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail();
+ } finally {
+ instanceNotificationExecutor.shutdown();
+ }
+ }
+
private List<TsBlock> collectResult(CountGroupByLevelScanOperator<?>
operator) throws Exception {
List<TsBlock> tsBlocks = new ArrayList<>();
while (operator.hasNext()) {
diff --git
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/TimeSeriesSchemaSourceTest.java
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/TimeSeriesSchemaSourceTest.java
new file mode 100644
index 00000000000..b7becf649c9
--- /dev/null
+++
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/TimeSeriesSchemaSourceTest.java
@@ -0,0 +1,137 @@
+/*
+ * 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.iotdb.db.queryengine.execution.operator.schema.source;
+
+import org.apache.iotdb.commons.path.PartialPath;
+import org.apache.iotdb.commons.schema.SchemaConstant;
+import org.apache.iotdb.db.schemaengine.rescon.ISchemaRegionStatistics;
+import org.apache.iotdb.db.schemaengine.schemaregion.ISchemaRegion;
+import
org.apache.iotdb.db.schemaengine.schemaregion.read.resp.info.ITimeSeriesSchemaInfo;
+
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import java.util.Collections;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class TimeSeriesSchemaSourceTest {
+
+ @Test
+ public void testCountSourceSkipsImplicitInternalDatabases() throws Exception
{
+ final ISchemaSource<ITimeSeriesSchemaInfo> countSource =
+ SchemaSourceFactory.getTimeSeriesSchemaCountSource(
+ new PartialPath("root.**"),
+ false,
+ null,
+ Collections.emptyMap(),
+ SchemaConstant.ALL_MATCH_SCOPE);
+
+ assertTrue(
+
countSource.shouldSkipSchemaRegion(mockSchemaRegion(SchemaConstant.SYSTEM_DATABASE)));
+
assertFalse(countSource.shouldSkipSchemaRegion(mockSchemaRegion("root.sg")));
+ }
+
+ @Test
+ public void testCountSourceKeepsExplicitInternalDatabaseQueries() throws
Exception {
+ final ISchemaSource<ITimeSeriesSchemaInfo> systemCountSource =
+ SchemaSourceFactory.getTimeSeriesSchemaCountSource(
+ new PartialPath("root.__system.**"),
+ false,
+ null,
+ Collections.emptyMap(),
+ SchemaConstant.ALL_MATCH_SCOPE);
+ assertFalse(
+
systemCountSource.shouldSkipSchemaRegion(mockSchemaRegion(SchemaConstant.SYSTEM_DATABASE)));
+ }
+
+ @Test
+ public void testCountSourceSkipsWildcardSecondNodeForInternalDatabases()
throws Exception {
+ final ISchemaSource<ITimeSeriesSchemaInfo> countSource =
+ SchemaSourceFactory.getTimeSeriesSchemaCountSource(
+ new PartialPath("root.*.**"),
+ false,
+ null,
+ Collections.emptyMap(),
+ SchemaConstant.ALL_MATCH_SCOPE);
+
+ assertTrue(
+
countSource.shouldSkipSchemaRegion(mockSchemaRegion(SchemaConstant.SYSTEM_DATABASE)));
+
assertFalse(countSource.shouldSkipSchemaRegion(mockSchemaRegion("root.sg")));
+ }
+
+ @Test
+ public void testCountSourceKeepsExactInternalDatabaseQueries() throws
Exception {
+ final ISchemaSource<ITimeSeriesSchemaInfo> systemCountSource =
+ SchemaSourceFactory.getTimeSeriesSchemaCountSource(
+ new PartialPath("root.__system"),
+ false,
+ null,
+ Collections.emptyMap(),
+ SchemaConstant.ALL_MATCH_SCOPE);
+ assertFalse(
+
systemCountSource.shouldSkipSchemaRegion(mockSchemaRegion(SchemaConstant.SYSTEM_DATABASE)));
+ }
+
+ @Test
+ public void testShowSourceDoesNotSkipInternalDatabases() throws Exception {
+ final ISchemaSource<ITimeSeriesSchemaInfo> showSource =
+ SchemaSourceFactory.getTimeSeriesSchemaScanSource(
+ new PartialPath("root.**"),
+ false,
+ 0,
+ 0,
+ null,
+ Collections.emptyMap(),
+ SchemaConstant.ALL_MATCH_SCOPE);
+
+ assertFalse(
+
showSource.shouldSkipSchemaRegion(mockSchemaRegion(SchemaConstant.SYSTEM_DATABASE)));
+ }
+
+ @Test
+ public void testCountStatisticIncludesView() throws Exception {
+ final ISchemaSource<ITimeSeriesSchemaInfo> countSource =
+ SchemaSourceFactory.getTimeSeriesSchemaCountSource(
+ new PartialPath("root.sg.**"),
+ false,
+ null,
+ Collections.emptyMap(),
+ SchemaConstant.ALL_MATCH_SCOPE);
+ final ISchemaRegion schemaRegion = mockSchemaRegion("root.sg");
+ final ISchemaRegionStatistics schemaRegionStatistics =
+ Mockito.mock(ISchemaRegionStatistics.class);
+
+
Mockito.when(schemaRegion.getSchemaRegionStatistics()).thenReturn(schemaRegionStatistics);
+ Mockito.when(schemaRegionStatistics.getSeriesNumber(true)).thenReturn(5L);
+
+ assertEquals(5L, countSource.getSchemaStatistic(schemaRegion));
+ Mockito.verify(schemaRegionStatistics).getSeriesNumber(true);
+ Mockito.verify(schemaRegionStatistics,
Mockito.never()).getSeriesNumber(false);
+ }
+
+ private ISchemaRegion mockSchemaRegion(final String database) {
+ final ISchemaRegion schemaRegion = Mockito.mock(ISchemaRegion.class);
+ Mockito.when(schemaRegion.getDatabaseFullPath()).thenReturn(database);
+ return schemaRegion;
+ }
+}