This is an automated email from the ASF dual-hosted git repository.
JackieTien97 pushed a commit to branch rc/2.0.10
in repository https://gitbox.apache.org/repos/asf/iotdb.git
The following commit(s) were added to refs/heads/rc/2.0.10 by this push:
new 425bde45810 Fix count and show timeseries follow-up (#17804)
425bde45810 is described below
commit 425bde45810c7c9b2793a89316f98b6a08763908
Author: Caideyipi <[email protected]>
AuthorDate: Mon Jun 29 13:42:24 2026 +0800
Fix count and show timeseries follow-up (#17804)
---
.../regionscan/IoTDBActiveSchemaQueryIT.java | 47 ++++
.../impl/DataNodeInternalRPCServiceImpl.java | 6 +-
.../db/queryengine/common/TimeseriesContext.java | 294 ++++++++++++++++++++-
.../schema/CountGroupByLevelScanOperator.java | 15 +-
.../operator/schema/SchemaCountOperator.java | 4 +
.../operator/schema/source/ISchemaSource.java | 4 +
.../schema/source/SchemaSourceFactory.java | 18 +-
.../schema/source/TimeSeriesSchemaSource.java | 20 ++
.../source/ActiveTimeSeriesRegionScanOperator.java | 92 +++++--
.../queryengine/plan/analyze/AnalyzeVisitor.java | 189 +++++++++++--
.../plan/planner/LogicalPlanBuilder.java | 16 +-
.../plan/planner/LogicalPlanVisitor.java | 8 +-
.../plan/planner/OperatorTreeGenerator.java | 8 +-
.../plan/planner/distribution/SourceRewriter.java | 10 +-
.../metadata/read/LevelTimeSeriesCountNode.java | 48 +++-
.../node/metadata/read/TimeSeriesCountNode.java | 49 +++-
.../plan/node/source/TimeseriesRegionScanNode.java | 7 +
.../security/TreeAccessCheckVisitor.java | 99 ++++++-
.../plan/statement/metadata/CountStatement.java | 9 +
.../org/apache/iotdb/db/auth/TreeAccessTest.java | 133 ++++++++++
.../schema/source/TimeSeriesSchemaSourceTest.java | 183 +++++++++++++
.../distribution/RegionScanPlanningTest.java | 81 ++++++
.../logical/RegionScanLogicalPlannerTest.java | 47 ++++
.../metadata/read/SchemaCountNodeSerdeTest.java | 8 +-
24 files changed, 1312 insertions(+), 83 deletions(-)
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 c0e7673d7d6..1361f360202 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;
@@ -236,6 +237,52 @@ 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,
+ "show timeseries root.view_count.** where time>0",
+ new HashSet<>(
+ Arrays.asList(
+
"root.view_count.src.s1,null,root.view_count,INT32,PLAIN,LZ4,null,null,null,null,BASE,",
+
"root.view_count.dst.v1,null,root.view_count,INT32,null,null,null,null,null,null,VIEW,")));
+ checkResultSet(
+ statement,
+ "count timeseries root.view_count.dst.** where time>0",
+ new HashSet<>(Collections.singletonList("1,")));
+ checkResultSet(
+ statement,
+ "show timeseries root.view_count.dst.** where time>0",
+ new HashSet<>(
+ Collections.singletonList(
+
"root.view_count.dst.v1,null,root.view_count,INT32,null,null,null,null,null,null,VIEW,")));
+ } 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/protocol/thrift/impl/DataNodeInternalRPCServiceImpl.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/DataNodeInternalRPCServiceImpl.java
index e5c99640564..ebef68b0486 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/DataNodeInternalRPCServiceImpl.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/DataNodeInternalRPCServiceImpl.java
@@ -1153,7 +1153,7 @@ public class DataNodeInternalRPCServiceImpl implements
IDataNodeRPCService.Iface
for (final PartialPath pattern :
filteredPatternTree.getAllPathPatterns()) {
ISchemaSource<ITimeSeriesSchemaInfo> schemaSource =
SchemaSourceFactory.getTimeSeriesSchemaCountSource(
- pattern, false, null, null,
SchemaConstant.ALL_MATCH_SCOPE);
+ pattern, false, null, null,
SchemaConstant.ALL_MATCH_SCOPE, true, true);
try (final ISchemaReader<ITimeSeriesSchemaInfo> schemaReader
=
schemaSource.getSchemaReader(schemaRegion)) {
if (schemaReader.hasNext()) {
@@ -1996,7 +1996,9 @@ public class DataNodeInternalRPCServiceImpl implements
IDataNodeRPCService.Iface
// Does not support logical view currently
SchemaFilterFactory.createViewTypeFilter(ViewType.BASE),
null,
- SchemaConstant.ALL_MATCH_SCOPE);
+ SchemaConstant.ALL_MATCH_SCOPE,
+ true,
+ true);
try (final ISchemaReader<ITimeSeriesSchemaInfo> schemaReader =
schemaSource.getSchemaReader(schemaRegion)) {
final Map<String, Byte> updateMap =
resp.getDeviewViewFieldTypeMap();
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..ecad26bac00 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,11 @@ 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.HashMap;
+import java.util.Map;
import java.util.Objects;
+import java.util.Set;
import static
org.apache.iotdb.db.queryengine.execution.operator.schema.source.TimeSeriesSchemaSource.mapToString;
@@ -42,11 +46,70 @@ public class TimeseriesContext {
private final String deadband;
private final String deadbandParameters;
+ private final String database;
+ private final int activeCountMultiplier;
+ private final boolean logicalView;
+ private final Map<String, TimeseriesContext> activeLogicalViewContextMap;
public TimeseriesContext(IMeasurementSchemaInfo schemaInfo) {
+ this(schemaInfo, 1, Collections.emptyMap());
+ }
+
+ public TimeseriesContext(
+ IMeasurementSchemaInfo schemaInfo,
+ int activeCountMultiplier,
+ Set<String> activeLogicalViewCountSet) {
+ this(schemaInfo, activeCountMultiplier,
createLogicalViewContextMap(activeLogicalViewCountSet));
+ }
+
+ public TimeseriesContext(
+ IMeasurementSchemaInfo schemaInfo,
+ int activeCountMultiplier,
+ Map<String, TimeseriesContext> activeLogicalViewContextMap) {
this.dataType = schemaInfo.getSchema().getType().toString();
- this.encoding = schemaInfo.getSchema().getEncodingType().toString();
- this.compression = schemaInfo.getSchema().getCompressor().toString();
+ this.logicalView = schemaInfo.isLogicalView();
+ if (logicalView) {
+ this.encoding = null;
+ this.compression = null;
+ } else {
+ this.encoding = schemaInfo.getSchema().getEncodingType().toString();
+ this.compression = schemaInfo.getSchema().getCompressor().toString();
+ }
+ this.alias = schemaInfo.getAlias();
+ this.tags = mapToString(schemaInfo.getTagMap());
+ this.attributes = mapToString(schemaInfo.getAttributeMap());
+ Pair<String, String> deadbandInfo =
+ MetaUtils.parseDeadbandInfo(schemaInfo.getSchema().getProps());
+ this.deadband = deadbandInfo.left;
+ this.deadbandParameters = deadbandInfo.right;
+ this.database = null;
+ this.activeCountMultiplier = activeCountMultiplier;
+ this.activeLogicalViewContextMap = new
HashMap<>(activeLogicalViewContextMap);
+ }
+
+ public TimeseriesContext(
+ IMeasurementSchemaInfo schemaInfo,
+ String dataType,
+ int activeCountMultiplier,
+ Map<String, TimeseriesContext> activeLogicalViewContextMap) {
+ this(schemaInfo, dataType, null, activeCountMultiplier,
activeLogicalViewContextMap);
+ }
+
+ public TimeseriesContext(
+ IMeasurementSchemaInfo schemaInfo,
+ String dataType,
+ String database,
+ int activeCountMultiplier,
+ Map<String, TimeseriesContext> activeLogicalViewContextMap) {
+ this.dataType = dataType;
+ this.logicalView = schemaInfo.isLogicalView();
+ if (logicalView) {
+ this.encoding = null;
+ this.compression = null;
+ } else {
+ this.encoding = schemaInfo.getSchema().getEncodingType().toString();
+ this.compression = schemaInfo.getSchema().getCompressor().toString();
+ }
this.alias = schemaInfo.getAlias();
this.tags = mapToString(schemaInfo.getTagMap());
this.attributes = mapToString(schemaInfo.getAttributeMap());
@@ -54,6 +117,9 @@ public class TimeseriesContext {
MetaUtils.parseDeadbandInfo(schemaInfo.getSchema().getProps());
this.deadband = deadbandInfo.left;
this.deadbandParameters = deadbandInfo.right;
+ this.database = database;
+ this.activeCountMultiplier = activeCountMultiplier;
+ this.activeLogicalViewContextMap = new
HashMap<>(activeLogicalViewContextMap);
}
public String getDataType() {
@@ -88,6 +154,26 @@ public class TimeseriesContext {
return deadband;
}
+ public String getDatabase() {
+ return database;
+ }
+
+ public int getActiveCountMultiplier() {
+ return activeCountMultiplier;
+ }
+
+ public Set<String> getActiveLogicalViewCountSet() {
+ return activeLogicalViewContextMap.keySet();
+ }
+
+ public Map<String, TimeseriesContext> getActiveLogicalViewContextMap() {
+ return activeLogicalViewContextMap;
+ }
+
+ public boolean isLogicalView() {
+ return logicalView;
+ }
+
public TimeseriesContext(
String dataType,
String alias,
@@ -97,6 +183,113 @@ public class TimeseriesContext {
String attributes,
String deadband,
String deadbandParameters) {
+ this(
+ dataType,
+ alias,
+ encoding,
+ compression,
+ tags,
+ attributes,
+ deadband,
+ deadbandParameters,
+ 1,
+ false,
+ null,
+ Collections.emptyMap());
+ }
+
+ 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,
+ alias,
+ encoding,
+ compression,
+ tags,
+ attributes,
+ deadband,
+ deadbandParameters,
+ activeCountMultiplier,
+ false,
+ null,
+ createLogicalViewContextMap(activeLogicalViewCountSet));
+ }
+
+ public TimeseriesContext(
+ String dataType,
+ String alias,
+ String encoding,
+ String compression,
+ String tags,
+ String attributes,
+ String deadband,
+ String deadbandParameters,
+ int activeCountMultiplier,
+ Map<String, TimeseriesContext> activeLogicalViewContextMap) {
+ this(
+ dataType,
+ alias,
+ encoding,
+ compression,
+ tags,
+ attributes,
+ deadband,
+ deadbandParameters,
+ activeCountMultiplier,
+ false,
+ null,
+ activeLogicalViewContextMap);
+ }
+
+ public TimeseriesContext(
+ String dataType,
+ String alias,
+ String encoding,
+ String compression,
+ String tags,
+ String attributes,
+ String deadband,
+ String deadbandParameters,
+ int activeCountMultiplier,
+ boolean logicalView,
+ Map<String, TimeseriesContext> activeLogicalViewContextMap) {
+ this(
+ dataType,
+ alias,
+ encoding,
+ compression,
+ tags,
+ attributes,
+ deadband,
+ deadbandParameters,
+ activeCountMultiplier,
+ logicalView,
+ null,
+ activeLogicalViewContextMap);
+ }
+
+ public TimeseriesContext(
+ String dataType,
+ String alias,
+ String encoding,
+ String compression,
+ String tags,
+ String attributes,
+ String deadband,
+ String deadbandParameters,
+ int activeCountMultiplier,
+ boolean logicalView,
+ String database,
+ Map<String, TimeseriesContext> activeLogicalViewContextMap) {
this.dataType = dataType;
this.alias = alias;
this.encoding = encoding;
@@ -105,6 +298,44 @@ public class TimeseriesContext {
this.attributes = attributes;
this.deadband = deadband;
this.deadbandParameters = deadbandParameters;
+ this.database = database;
+ this.activeCountMultiplier = activeCountMultiplier;
+ this.logicalView = logicalView;
+ this.activeLogicalViewContextMap = new
HashMap<>(activeLogicalViewContextMap);
+ }
+
+ private static Map<String, TimeseriesContext> createLogicalViewContextMap(
+ Set<String> activeLogicalViewCountSet) {
+ if (activeLogicalViewCountSet.isEmpty()) {
+ return Collections.emptyMap();
+ }
+ Map<String, TimeseriesContext> activeLogicalViewContextMap = new
HashMap<>();
+ for (String logicalView : activeLogicalViewCountSet) {
+ activeLogicalViewContextMap.put(
+ logicalView,
+ new TimeseriesContext(
+ null, null, null, null, null, null, null, null, 1, true,
Collections.emptyMap()));
+ }
+ return activeLogicalViewContextMap;
+ }
+
+ public TimeseriesContext mergeActiveCount(TimeseriesContext that) {
+ Map<String, TimeseriesContext> mergedActiveLogicalViewContextMap =
+ new HashMap<>(activeLogicalViewContextMap);
+ mergedActiveLogicalViewContextMap.putAll(that.activeLogicalViewContextMap);
+ return new TimeseriesContext(
+ dataType,
+ alias,
+ encoding,
+ compression,
+ tags,
+ attributes,
+ deadband,
+ deadbandParameters,
+ activeCountMultiplier + that.activeCountMultiplier,
+ logicalView,
+ database,
+ mergedActiveLogicalViewContextMap);
}
public void serializeAttributes(ByteBuffer byteBuffer) {
@@ -116,6 +347,14 @@ public class TimeseriesContext {
ReadWriteIOUtils.write(attributes, byteBuffer);
ReadWriteIOUtils.write(deadband, byteBuffer);
ReadWriteIOUtils.write(deadbandParameters, byteBuffer);
+ ReadWriteIOUtils.write(database, byteBuffer);
+ ReadWriteIOUtils.write(activeCountMultiplier, byteBuffer);
+ ReadWriteIOUtils.write(logicalView, byteBuffer);
+ ReadWriteIOUtils.write(activeLogicalViewContextMap.size(), byteBuffer);
+ for (Map.Entry<String, TimeseriesContext> entry :
activeLogicalViewContextMap.entrySet()) {
+ ReadWriteIOUtils.write(entry.getKey(), byteBuffer);
+ entry.getValue().serializeAttributes(byteBuffer);
+ }
}
public void serializeAttributes(DataOutputStream stream) throws IOException {
@@ -127,6 +366,14 @@ public class TimeseriesContext {
ReadWriteIOUtils.write(attributes, stream);
ReadWriteIOUtils.write(deadband, stream);
ReadWriteIOUtils.write(deadbandParameters, stream);
+ ReadWriteIOUtils.write(database, stream);
+ ReadWriteIOUtils.write(activeCountMultiplier, stream);
+ ReadWriteIOUtils.write(logicalView, stream);
+ ReadWriteIOUtils.write(activeLogicalViewContextMap.size(), stream);
+ for (Map.Entry<String, TimeseriesContext> entry :
activeLogicalViewContextMap.entrySet()) {
+ ReadWriteIOUtils.write(entry.getKey(), stream);
+ entry.getValue().serializeAttributes(stream);
+ }
}
public static TimeseriesContext deserialize(ByteBuffer buffer) {
@@ -138,8 +385,28 @@ public class TimeseriesContext {
String attributes = ReadWriteIOUtils.readString(buffer);
String deadband = ReadWriteIOUtils.readString(buffer);
String deadbandParameters = ReadWriteIOUtils.readString(buffer);
+ String database = ReadWriteIOUtils.readString(buffer);
+ int activeCountMultiplier = ReadWriteIOUtils.readInt(buffer);
+ boolean logicalView = ReadWriteIOUtils.readBool(buffer);
+ int activeLogicalViewContextMapSize = ReadWriteIOUtils.readInt(buffer);
+ Map<String, TimeseriesContext> activeLogicalViewContextMap = new
HashMap<>();
+ for (int i = 0; i < activeLogicalViewContextMapSize; i++) {
+ activeLogicalViewContextMap.put(
+ ReadWriteIOUtils.readString(buffer),
TimeseriesContext.deserialize(buffer));
+ }
return new TimeseriesContext(
- dataType, alias, encoding, compression, tags, attributes, deadband,
deadbandParameters);
+ dataType,
+ alias,
+ encoding,
+ compression,
+ tags,
+ attributes,
+ deadband,
+ deadbandParameters,
+ activeCountMultiplier,
+ logicalView,
+ database,
+ activeLogicalViewContextMap);
}
@Override
@@ -154,18 +421,33 @@ public class TimeseriesContext {
boolean res =
Objects.equals(dataType, that.dataType)
&& Objects.equals(alias, that.alias)
- && encoding.equals(that.encoding)
+ && Objects.equals(encoding, that.encoding)
&& Objects.equals(compression, that.compression)
&& 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)
+ && Objects.equals(database, that.database)
+ && activeCountMultiplier == that.activeCountMultiplier
+ && logicalView == that.logicalView
+ && Objects.equals(activeLogicalViewContextMap,
that.activeLogicalViewContextMap);
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,
+ database,
+ activeCountMultiplier,
+ logicalView,
+ activeLogicalViewContextMap);
}
}
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 69f36680fb7..35c57dafa4d 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.driver.SchemaDriverContext;
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.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 9b2884233c1..4cafe40c36b 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
@@ -100,6 +100,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)) {
long statisticCount = schemaSource.getSchemaStatistic(schemaRegion);
// Check if database path itself is counted as a device (bug fix)
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 41bd5f3fbe0..4417203fdc8 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
@@ -57,6 +57,10 @@ public interface ISchemaSource<T extends ISchemaInfo> {
long getSchemaStatistic(final ISchemaRegion schemaRegion);
+ default boolean shouldSkipSchemaRegion(final ISchemaRegion schemaRegion) {
+ return false;
+ }
+
default boolean checkRegionDatabaseIncluded(final ISchemaRegion
schemaRegion) {
return true;
}
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 87560ad47be..85bc9bcb77c 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
@@ -46,9 +46,21 @@ public class SchemaSourceFactory {
boolean isPrefixMatch,
SchemaFilter schemaFilter,
Map<Integer, Template> templateMap,
- PathPatternTree scope) {
+ PathPatternTree scope,
+ boolean includeSystemDatabase,
+ boolean includeAuditDatabase) {
return new TimeSeriesSchemaSource(
- pathPattern, isPrefixMatch, 0, 0, schemaFilter, templateMap, false,
scope, null);
+ pathPattern,
+ isPrefixMatch,
+ 0,
+ 0,
+ schemaFilter,
+ templateMap,
+ false,
+ includeSystemDatabase,
+ includeAuditDatabase,
+ scope,
+ null);
}
// show time series
@@ -69,6 +81,8 @@ public class SchemaSourceFactory {
schemaFilter,
templateMap,
true,
+ true,
+ true,
scope,
timeseriesOrdering);
}
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 a56cfa228bf..0b89998052b 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
@@ -27,6 +27,7 @@ import org.apache.iotdb.commons.schema.SchemaConstant;
import org.apache.iotdb.commons.schema.column.ColumnHeader;
import org.apache.iotdb.commons.schema.column.ColumnHeaderConstant;
import org.apache.iotdb.commons.schema.filter.SchemaFilter;
+import org.apache.iotdb.commons.schema.table.Audit;
import org.apache.iotdb.commons.schema.template.Template;
import org.apache.iotdb.commons.schema.view.ViewType;
import org.apache.iotdb.db.queryengine.plan.statement.component.Ordering;
@@ -55,6 +56,8 @@ public class TimeSeriesSchemaSource implements
ISchemaSource<ITimeSeriesSchemaIn
private final SchemaFilter schemaFilter;
private final Map<Integer, Template> templateMap;
private final boolean needViewDetail;
+ private final boolean includeSystemDatabase;
+ private final boolean includeAuditDatabase;
private final Ordering timeseriesOrdering;
TimeSeriesSchemaSource(
@@ -65,6 +68,8 @@ public class TimeSeriesSchemaSource implements
ISchemaSource<ITimeSeriesSchemaIn
SchemaFilter schemaFilter,
Map<Integer, Template> templateMap,
boolean needViewDetail,
+ boolean includeSystemDatabase,
+ boolean includeAuditDatabase,
PathPatternTree scope,
Ordering timeseriesOrdering) {
this.pathPattern = pathPattern;
@@ -74,6 +79,8 @@ public class TimeSeriesSchemaSource implements
ISchemaSource<ITimeSeriesSchemaIn
this.schemaFilter = schemaFilter;
this.templateMap = templateMap;
this.needViewDetail = needViewDetail;
+ this.includeSystemDatabase = includeSystemDatabase;
+ this.includeAuditDatabase = includeAuditDatabase;
this.scope = scope;
this.timeseriesOrdering = timeseriesOrdering;
}
@@ -141,6 +148,19 @@ public class TimeSeriesSchemaSource implements
ISchemaSource<ITimeSeriesSchemaIn
return schemaRegion.getSchemaRegionStatistics().getSeriesNumber(true);
}
+ @Override
+ public boolean shouldSkipSchemaRegion(final ISchemaRegion schemaRegion) {
+ final String database = schemaRegion.getDatabaseFullPath();
+ if (SchemaConstant.SYSTEM_DATABASE.equals(database)) {
+ return !includeSystemDatabase;
+ }
+ if (SchemaConstant.AUDIT_DATABASE.equals(database)
+ || Audit.TABLE_MODEL_AUDIT_DATABASE.equals(database)) {
+ return !includeAuditDatabase;
+ }
+ return false;
+ }
+
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 b6ac9ecd850..e61de2818b6 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
@@ -35,15 +35,22 @@ 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 static final Binary VIEW_TYPE = new Binary("BASE".getBytes());
+ private final Set<String> countedLogicalViews;
+ private static final Binary BASE_VIEW_TYPE =
+ new Binary("BASE".getBytes(TSFileConfig.STRING_CHARSET));
+ private static final Binary LOGICAL_VIEW_TYPE =
+ new Binary("VIEW".getBytes(TSFileConfig.STRING_CHARSET));
private final Binary dataBaseName;
+ private final String dataBaseNameString;
private static final long INSTANCE_SIZE =
RamUsageEstimator.shallowSizeOfInstance(ActiveTimeSeriesRegionScanOperator.class)
+ RamUsageEstimator.shallowSizeOfInstance(Map.class)
@@ -60,15 +67,15 @@ 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(
- operatorContext
- .getDriverContext()
- .getFragmentInstanceContext()
- .getDataRegion()
- .getDatabaseName()
- .getBytes(TSFileConfig.STRING_CHARSET));
+ this.dataBaseNameString =
+ operatorContext
+ .getDriverContext()
+ .getFragmentInstanceContext()
+ .getDataRegion()
+ .getDatabaseName();
+ this.dataBaseName = new
Binary(this.dataBaseNameString.getBytes(TSFileConfig.STRING_CHARSET));
}
@Override
@@ -92,16 +99,22 @@ public class ActiveTimeSeriesRegionScanOperator extends
AbstractRegionScanDataSo
@Override
protected void updateActiveData() {
- TimeColumnBuilder timeColumnBuilder =
resultTsBlockBuilder.getTimeColumnBuilder();
- ColumnBuilder[] columnBuilders =
resultTsBlockBuilder.getValueColumnBuilders();
-
Map<IDeviceID, List<String>> activeTimeSeries =
((RegionScanForActiveTimeSeriesUtil)
regionScanUtil).getActiveTimeSeries();
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;
@@ -114,26 +127,49 @@ public class ActiveTimeSeriesRegionScanOperator extends
AbstractRegionScanDataSo
Map<String, TimeseriesContext> timeSeriesInfo =
timeSeriesToSchemasInfo.get(deviceID);
for (String timeSeries : timeSeriesList) {
TimeseriesContext schemaInfo = timeSeriesInfo.get(timeSeries);
- timeColumnBuilder.writeLong(-1);
- columnBuilders[0].writeBinary(
- new Binary(contactDeviceAndMeasurement(deviceStr, timeSeries)));
-
- checkAndAppend(schemaInfo.getAlias(), columnBuilders[1]); //
Measurement
- columnBuilders[2].writeBinary(dataBaseName); // Database
- checkAndAppend(schemaInfo.getDataType(), columnBuilders[3]); //
DataType
- checkAndAppend(schemaInfo.getEncoding(), columnBuilders[4]); //
Encoding
- checkAndAppend(schemaInfo.getCompression(), columnBuilders[5]); //
Compression
- checkAndAppend(schemaInfo.getTags(), columnBuilders[6]); // Tags
- checkAndAppend(schemaInfo.getAttributes(), columnBuilders[7]); //
Attributes
- checkAndAppend(schemaInfo.getDeadband(), columnBuilders[8]); //
Description
- checkAndAppend(schemaInfo.getDeadbandParameters(), columnBuilders[9]);
// DeadbandParameters
- columnBuilders[10].writeBinary(VIEW_TYPE); // ViewType
- resultTsBlockBuilder.declarePosition();
+ if (schemaInfo.getActiveCountMultiplier() > 0) {
+ appendTimeseries(
+ contactDeviceAndMeasurement(deviceStr, timeSeries), schemaInfo,
BASE_VIEW_TYPE);
+ }
+ for (Map.Entry<String, TimeseriesContext> logicalViewEntry :
+ schemaInfo.getActiveLogicalViewContextMap().entrySet()) {
+ if (countedLogicalViews.add(logicalViewEntry.getKey())) {
+ appendTimeseries(
+
logicalViewEntry.getKey().getBytes(TSFileConfig.STRING_CHARSET),
+ logicalViewEntry.getValue(),
+ LOGICAL_VIEW_TYPE);
+ }
+ }
}
removeTimeseriesListFromDevice(deviceID, timeSeriesList);
}
}
+ private void appendTimeseries(
+ byte[] timeseriesPath, TimeseriesContext schemaInfo, Binary viewType) {
+ TimeColumnBuilder timeColumnBuilder =
resultTsBlockBuilder.getTimeColumnBuilder();
+ ColumnBuilder[] columnBuilders =
resultTsBlockBuilder.getValueColumnBuilders();
+
+ timeColumnBuilder.writeLong(-1);
+ columnBuilders[0].writeBinary(new Binary(timeseriesPath));
+
+ checkAndAppend(schemaInfo.getAlias(), columnBuilders[1]); // Measurement
+ if (schemaInfo.getDatabase() == null ||
dataBaseNameString.equals(schemaInfo.getDatabase())) {
+ columnBuilders[2].writeBinary(dataBaseName); // Database
+ } else {
+ checkAndAppend(schemaInfo.getDatabase(), columnBuilders[2]); // Database
+ }
+ checkAndAppend(schemaInfo.getDataType(), columnBuilders[3]); // DataType
+ checkAndAppend(schemaInfo.getEncoding(), columnBuilders[4]); // Encoding
+ checkAndAppend(schemaInfo.getCompression(), columnBuilders[5]); //
Compression
+ checkAndAppend(schemaInfo.getTags(), columnBuilders[6]); // Tags
+ checkAndAppend(schemaInfo.getAttributes(), columnBuilders[7]); //
Attributes
+ checkAndAppend(schemaInfo.getDeadband(), columnBuilders[8]); // Description
+ checkAndAppend(schemaInfo.getDeadbandParameters(), columnBuilders[9]); //
DeadbandParameters
+ columnBuilders[10].writeBinary(viewType); // ViewType
+ resultTsBlockBuilder.declarePosition();
+ }
+
private void removeTimeseriesListFromDevice(IDeviceID deviceID, List<String>
timeSeriesList) {
Map<String, TimeseriesContext> timeSeriesInfo =
timeSeriesToSchemasInfo.get(deviceID);
for (String timeSeries : timeSeriesList) {
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 7aa8d1e8636..22d5b0518ac 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
@@ -35,8 +35,11 @@ import org.apache.iotdb.commons.path.AlignedPath;
import org.apache.iotdb.commons.path.MeasurementPath;
import org.apache.iotdb.commons.path.PartialPath;
import org.apache.iotdb.commons.path.PathPatternTree;
+import org.apache.iotdb.commons.queryengine.common.NodeRef;
+import org.apache.iotdb.commons.schema.SchemaConstant;
import org.apache.iotdb.commons.schema.column.ColumnHeader;
import org.apache.iotdb.commons.schema.column.ColumnHeaderConstant;
+import org.apache.iotdb.commons.schema.table.Audit;
import org.apache.iotdb.commons.schema.template.Template;
import org.apache.iotdb.commons.schema.view.LogicalViewSchema;
import org.apache.iotdb.commons.schema.view.viewExpression.ViewExpression;
@@ -71,6 +74,7 @@ import
org.apache.iotdb.db.queryengine.plan.expression.binary.CompareBinaryExpre
import org.apache.iotdb.db.queryengine.plan.expression.leaf.ConstantOperand;
import org.apache.iotdb.db.queryengine.plan.expression.leaf.TimeSeriesOperand;
import
org.apache.iotdb.db.queryengine.plan.expression.multi.FunctionExpression;
+import
org.apache.iotdb.db.queryengine.plan.expression.visitor.CompleteMeasurementSchemaVisitor;
import
org.apache.iotdb.db.queryengine.plan.expression.visitor.ExistUnknownTypeInExpression;
import
org.apache.iotdb.db.queryengine.plan.planner.plan.node.metadata.write.MeasurementGroup;
import
org.apache.iotdb.db.queryengine.plan.planner.plan.parameter.DeviceViewIntoPathDescriptor;
@@ -142,6 +146,7 @@ import
org.apache.iotdb.db.queryengine.plan.statement.sys.ExplainStatement;
import
org.apache.iotdb.db.queryengine.plan.statement.sys.ShowDiskUsageStatement;
import org.apache.iotdb.db.queryengine.plan.statement.sys.ShowQueriesStatement;
import org.apache.iotdb.db.queryengine.plan.statement.sys.ShowVersionStatement;
+import
org.apache.iotdb.db.schemaengine.schemaregion.view.visitor.TransformToExpressionVisitor;
import org.apache.iotdb.rpc.RpcUtils;
import org.apache.iotdb.rpc.TSStatusCode;
@@ -2931,7 +2936,9 @@ public class AnalyzeVisitor extends
StatementVisitor<Analysis, MPPQueryContext>
Analysis analysis,
MPPQueryContext context,
PathPatternTree authorityScope,
- boolean canSeeAuditDB)
+ boolean canSeeAuditDB,
+ boolean canSeeSystemDB,
+ boolean includeLogicalView)
throws IllegalPathException {
analyzeGlobalTimeConditionInShowMetaData(timeCondition, analysis);
context.generateGlobalTimeFilter(analysis);
@@ -2944,7 +2951,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, canSeeAuditDB);
+ } else {
+ removeLogicViewMeasurement(schemaTree);
+ deviceSchemaInfoList = schemaTree.getMatchedDevices(ALL_MATCH_PATTERN);
+ }
+
Map<PartialPath, Map<PartialPath, List<TimeseriesContext>>>
deviceToTimeseriesContext =
new HashMap<>();
/**
@@ -2952,38 +2967,60 @@ 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<IDeviceID> deviceSet = new HashSet<>();
for (DeviceSchemaInfo deviceSchemaInfo : deviceSchemaInfoList) {
boolean isAligned = deviceSchemaInfo.isAligned();
PartialPath devicePath = deviceSchemaInfo.getDevicePath();
- deviceSet.add(devicePath.getIDeviceIDAsFullDevice());
+ if (shouldSkipInternalDatabaseForActiveCount(
+ devicePath, schemaTree, canSeeAuditDB, canSeeSystemDB)) {
+ continue;
+ }
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.getIDeviceIDAsFullDevice());
+ 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);
+ }
}
}
}
@@ -2995,6 +3032,116 @@ public class AnalyzeVisitor extends
StatementVisitor<Analysis, MPPQueryContext>
return true;
}
+ private boolean shouldSkipInternalDatabaseForActiveCount(
+ PartialPath devicePath,
+ ISchemaTree schemaTree,
+ boolean canSeeAuditDB,
+ boolean canSeeSystemDB) {
+ String database = schemaTree.getBelongedDatabase(devicePath);
+ if (SchemaConstant.SYSTEM_DATABASE.equals(database)) {
+ return !canSeeSystemDB;
+ }
+ if (SchemaConstant.AUDIT_DATABASE.equals(database)
+ || Audit.TABLE_MODEL_AUDIT_DATABASE.equals(database)) {
+ return !canSeeAuditDB;
+ }
+ return false;
+ }
+
+ private void addLogicalViewSourcesForActiveCount(
+ PartialPath viewDevicePath,
+ IMeasurementSchemaInfo viewSchemaInfo,
+ ISchemaTree schemaTree,
+ Map<PartialPath, Map<PartialPath, List<TimeseriesContext>>>
deviceToTimeseriesContext,
+ Set<IDeviceID> deviceSet) {
+ LogicalViewSchema logicalViewSchema =
viewSchemaInfo.getSchemaAsLogicalViewSchema();
+ if (logicalViewSchema == null) {
+ return;
+ }
+
+ String viewPath =
viewDevicePath.concatNode(viewSchemaInfo.getName()).getFullPath();
+ String viewDataType = getLogicalViewDataType(logicalViewSchema,
schemaTree);
+ String viewDatabase = schemaTree.getBelongedDatabase(viewDevicePath);
+ 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;
+ }
+
+ Map<String, TimeseriesContext> activeLogicalViewContextMap =
+ Collections.singletonMap(
+ viewPath,
+ new TimeseriesContext(
+ viewSchemaInfo, viewDataType, viewDatabase, 1,
Collections.emptyMap()));
+ addPhysicalTimeseriesForActiveCount(
+ sourceDevicePath,
+ sourceSchemaInfo,
+ sourceDeviceSchemaInfo.isAligned(),
+ new TimeseriesContext(sourceSchemaInfo, 0,
activeLogicalViewContextMap),
+ deviceToTimeseriesContext,
+ deviceSet);
+ }
+ }
+
+ private String getLogicalViewDataType(
+ LogicalViewSchema logicalViewSchema, ISchemaTree schemaTree) {
+ if (logicalViewSchema.getType() != TSDataType.UNKNOWN) {
+ return logicalViewSchema.getType().toString();
+ }
+ try {
+ Expression expression =
+ new
TransformToExpressionVisitor().process(logicalViewSchema.getExpression(), null);
+ expression = new CompleteMeasurementSchemaVisitor().process(expression,
schemaTree);
+ Map<NodeRef<Expression>, TSDataType> expressionTypes = new HashMap<>();
+ analyzeExpression(expressionTypes, expression);
+ TSDataType dataType = expressionTypes.get(NodeRef.of(expression));
+ return dataType == null ? TSDataType.UNKNOWN.toString() :
dataType.toString();
+ } catch (Exception e) {
+ return TSDataType.UNKNOWN.toString();
+ }
+ }
+
+ private void addPhysicalTimeseriesForActiveCount(
+ PartialPath devicePath,
+ IMeasurementSchemaInfo measurementSchemaInfo,
+ boolean isAligned,
+ TimeseriesContext timeseriesContext,
+ Map<PartialPath, Map<PartialPath, List<TimeseriesContext>>>
deviceToTimeseriesContext,
+ Set<IDeviceID> deviceSet) {
+ deviceSet.add(devicePath.getIDeviceIDAsFullDevice());
+ 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) {
@@ -3020,7 +3167,9 @@ public class AnalyzeVisitor extends
StatementVisitor<Analysis, MPPQueryContext>
analysis,
context,
showTimeSeriesStatement.getAuthorityScope(),
- showTimeSeriesStatement.isCanSeeAuditDB());
+ showTimeSeriesStatement.isCanSeeAuditDB(),
+ true,
+ true);
if (!hasSchema) {
analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowTimeSeriesHeader());
return analysis;
@@ -3271,7 +3420,9 @@ public class AnalyzeVisitor extends
StatementVisitor<Analysis, MPPQueryContext>
analysis,
context,
countTimeSeriesStatement.getAuthorityScope(),
- countTimeSeriesStatement.isCanSeeAuditDB());
+ countTimeSeriesStatement.isCanSeeAuditDB(),
+ countTimeSeriesStatement.isCanSeeSystemDB(),
+ 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/LogicalPlanBuilder.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/LogicalPlanBuilder.java
index fff2aa07b49..26d361c1f21 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/LogicalPlanBuilder.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/LogicalPlanBuilder.java
@@ -1176,7 +1176,9 @@ public class LogicalPlanBuilder {
boolean prefixPath,
SchemaFilter schemaFilter,
Map<Integer, Template> templateMap,
- PathPatternTree scope) {
+ PathPatternTree scope,
+ boolean includeSystemDatabase,
+ boolean includeAuditDatabase) {
this.root =
new TimeSeriesCountNode(
context.getQueryId().genPlanNodeId(),
@@ -1184,7 +1186,9 @@ public class LogicalPlanBuilder {
prefixPath,
schemaFilter,
templateMap,
- scope);
+ scope,
+ includeSystemDatabase,
+ includeAuditDatabase);
return this;
}
@@ -1194,7 +1198,9 @@ public class LogicalPlanBuilder {
int level,
SchemaFilter schemaFilter,
Map<Integer, Template> templateMap,
- PathPatternTree scope) {
+ PathPatternTree scope,
+ boolean includeSystemDatabase,
+ boolean includeAuditDatabase) {
this.root =
new LevelTimeSeriesCountNode(
context.getQueryId().genPlanNodeId(),
@@ -1203,7 +1209,9 @@ public class LogicalPlanBuilder {
level,
schemaFilter,
templateMap,
- scope);
+ scope,
+ includeSystemDatabase,
+ includeAuditDatabase);
return this;
}
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/LogicalPlanVisitor.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/LogicalPlanVisitor.java
index a9b0b9d83f4..2c9304ce0b9 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/LogicalPlanVisitor.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/LogicalPlanVisitor.java
@@ -733,7 +733,9 @@ public class LogicalPlanVisitor extends
StatementVisitor<PlanNode, MPPQueryConte
countTimeSeriesStatement.isPrefixPath(),
countTimeSeriesStatement.getSchemaFilter(),
analysis.getRelatedTemplateInfo(),
- countTimeSeriesStatement.getAuthorityScope())
+ countTimeSeriesStatement.getAuthorityScope(),
+ countTimeSeriesStatement.isCanSeeSystemDB(),
+ countTimeSeriesStatement.isCanSeeAuditDB())
.planCountMerge()
.getRoot();
}
@@ -749,7 +751,9 @@ public class LogicalPlanVisitor extends
StatementVisitor<PlanNode, MPPQueryConte
countLevelTimeSeriesStatement.getLevel(),
countLevelTimeSeriesStatement.getSchemaFilter(),
analysis.getRelatedTemplateInfo(),
- countLevelTimeSeriesStatement.getAuthorityScope())
+ countLevelTimeSeriesStatement.getAuthorityScope(),
+ countLevelTimeSeriesStatement.isCanSeeSystemDB(),
+ countLevelTimeSeriesStatement.isCanSeeAuditDB())
.planCountMerge()
.getRoot();
}
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 9f1aa7fc291..63cb0d861ad 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
@@ -984,7 +984,9 @@ public class OperatorTreeGenerator implements
PlanVisitor<Operator, LocalExecuti
node.isPrefixPath(),
node.getSchemaFilter(),
node.getTemplateMap(),
- node.getScope()));
+ node.getScope(),
+ node.isIncludeSystemDatabase(),
+ node.isIncludeAuditDatabase()));
}
@Override
@@ -1006,7 +1008,9 @@ public class OperatorTreeGenerator implements
PlanVisitor<Operator, LocalExecuti
node.isPrefixPath(),
node.getSchemaFilter(),
node.getTemplateMap(),
- node.getScope()));
+ node.getScope(),
+ node.isIncludeSystemDatabase(),
+ node.isIncludeAuditDatabase()));
}
@Override
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/distribution/SourceRewriter.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/distribution/SourceRewriter.java
index 6582f0a4a68..d326a6de30a 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/distribution/SourceRewriter.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/distribution/SourceRewriter.java
@@ -858,7 +858,10 @@ public class SourceRewriter extends
BaseSourceRewriter<DistributionPlanContext>
return planNodeList;
}
- boolean outputCountInScanNode = node.isOutputCount() &&
!context.isOneSeriesInMultiRegion();
+ boolean outputCountInScanNode =
+ node.isOutputCount()
+ && !context.isOneSeriesInMultiRegion()
+ && !hasActiveLogicalViewContext(node);
ActiveRegionScanMergeNode regionMergeNode =
new ActiveRegionScanMergeNode(
context.queryContext.getQueryId().genPlanNodeId(),
@@ -872,6 +875,11 @@ public class SourceRewriter extends
BaseSourceRewriter<DistributionPlanContext>
return Collections.singletonList(regionMergeNode);
}
+ private boolean hasActiveLogicalViewContext(RegionScanNode node) {
+ return node instanceof TimeseriesRegionScanNode
+ && ((TimeseriesRegionScanNode) node).hasActiveLogicalViewContext();
+ }
+
@Override
public List<PlanNode> visitDeviceRegionScan(
DeviceRegionScanNode node, DistributionPlanContext context) {
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/metadata/read/LevelTimeSeriesCountNode.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/metadata/read/LevelTimeSeriesCountNode.java
index 336ae40f85d..902a2dd69db 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/metadata/read/LevelTimeSeriesCountNode.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/metadata/read/LevelTimeSeriesCountNode.java
@@ -48,6 +48,8 @@ public class LevelTimeSeriesCountNode extends
SchemaQueryScanNode {
private final int level;
private final SchemaFilter schemaFilter;
private final Map<Integer, Template> templateMap;
+ private final boolean includeSystemDatabase;
+ private final boolean includeAuditDatabase;
public LevelTimeSeriesCountNode(
PlanNodeId id,
@@ -56,11 +58,15 @@ public class LevelTimeSeriesCountNode extends
SchemaQueryScanNode {
int level,
SchemaFilter schemaFilter,
@NotNull Map<Integer, Template> templateMap,
- @NotNull PathPatternTree scope) {
+ @NotNull PathPatternTree scope,
+ boolean includeSystemDatabase,
+ boolean includeAuditDatabase) {
super(id, partialPath, isPrefixPath, scope);
this.level = level;
this.schemaFilter = schemaFilter;
this.templateMap = templateMap;
+ this.includeSystemDatabase = includeSystemDatabase;
+ this.includeAuditDatabase = includeAuditDatabase;
}
public SchemaFilter getSchemaFilter() {
@@ -75,6 +81,14 @@ public class LevelTimeSeriesCountNode extends
SchemaQueryScanNode {
return templateMap;
}
+ public boolean isIncludeSystemDatabase() {
+ return includeSystemDatabase;
+ }
+
+ public boolean isIncludeAuditDatabase() {
+ return includeAuditDatabase;
+ }
+
@Override
public PlanNodeType getType() {
return PlanNodeType.LEVEL_TIME_SERIES_COUNT;
@@ -83,7 +97,15 @@ public class LevelTimeSeriesCountNode extends
SchemaQueryScanNode {
@Override
public PlanNode clone() {
return new LevelTimeSeriesCountNode(
- getPlanNodeId(), path, isPrefixPath, level, schemaFilter, templateMap,
scope);
+ getPlanNodeId(),
+ path,
+ isPrefixPath,
+ level,
+ schemaFilter,
+ templateMap,
+ scope,
+ includeSystemDatabase,
+ includeAuditDatabase);
}
@Override
@@ -101,6 +123,8 @@ public class LevelTimeSeriesCountNode extends
SchemaQueryScanNode {
ReadWriteIOUtils.write(isPrefixPath, byteBuffer);
ReadWriteIOUtils.write(level, byteBuffer);
SchemaFilter.serialize(schemaFilter, byteBuffer);
+ ReadWriteIOUtils.write(includeSystemDatabase, byteBuffer);
+ ReadWriteIOUtils.write(includeAuditDatabase, byteBuffer);
ReadWriteIOUtils.write(templateMap.size(), byteBuffer);
for (Template template : templateMap.values()) {
template.serialize(byteBuffer);
@@ -115,6 +139,8 @@ public class LevelTimeSeriesCountNode extends
SchemaQueryScanNode {
ReadWriteIOUtils.write(isPrefixPath, stream);
ReadWriteIOUtils.write(level, stream);
SchemaFilter.serialize(schemaFilter, stream);
+ ReadWriteIOUtils.write(includeSystemDatabase, stream);
+ ReadWriteIOUtils.write(includeAuditDatabase, stream);
ReadWriteIOUtils.write(templateMap.size(), stream);
for (Template template : templateMap.values()) {
template.serialize(stream);
@@ -134,6 +160,8 @@ public class LevelTimeSeriesCountNode extends
SchemaQueryScanNode {
boolean isPrefixPath = ReadWriteIOUtils.readBool(buffer);
int level = ReadWriteIOUtils.readInt(buffer);
SchemaFilter schemaFilter = SchemaFilter.deserialize(buffer);
+ boolean includeSystemDatabase = ReadWriteIOUtils.readBool(buffer);
+ boolean includeAuditDatabase = ReadWriteIOUtils.readBool(buffer);
int templateNum = ReadWriteIOUtils.readInt(buffer);
Map<Integer, Template> templateMap = new HashMap<>();
Template template;
@@ -144,7 +172,15 @@ public class LevelTimeSeriesCountNode extends
SchemaQueryScanNode {
}
PlanNodeId planNodeId = PlanNodeId.deserialize(buffer);
return new LevelTimeSeriesCountNode(
- planNodeId, path, isPrefixPath, level, schemaFilter, templateMap,
scope);
+ planNodeId,
+ path,
+ isPrefixPath,
+ level,
+ schemaFilter,
+ templateMap,
+ scope,
+ includeSystemDatabase,
+ includeAuditDatabase);
}
@Override
@@ -159,12 +195,14 @@ public class LevelTimeSeriesCountNode extends
SchemaQueryScanNode {
return false;
}
LevelTimeSeriesCountNode that = (LevelTimeSeriesCountNode) o;
- return level == that.level;
+ return level == that.level
+ && includeSystemDatabase == that.includeSystemDatabase
+ && includeAuditDatabase == that.includeAuditDatabase;
}
@Override
public int hashCode() {
- return Objects.hash(super.hashCode(), level);
+ return Objects.hash(super.hashCode(), level, includeSystemDatabase,
includeAuditDatabase);
}
@Override
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/metadata/read/TimeSeriesCountNode.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/metadata/read/TimeSeriesCountNode.java
index 6326a38a703..8bcc9e70f5d 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/metadata/read/TimeSeriesCountNode.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/metadata/read/TimeSeriesCountNode.java
@@ -51,16 +51,24 @@ public class TimeSeriesCountNode extends
SchemaQueryScanNode {
private final Map<Integer, Template> templateMap;
+ private final boolean includeSystemDatabase;
+
+ private final boolean includeAuditDatabase;
+
public TimeSeriesCountNode(
PlanNodeId id,
PartialPath partialPath,
boolean isPrefixPath,
SchemaFilter schemaFilter,
@NotNull Map<Integer, Template> templateMap,
- @NotNull PathPatternTree scope) {
+ @NotNull PathPatternTree scope,
+ boolean includeSystemDatabase,
+ boolean includeAuditDatabase) {
super(id, partialPath, isPrefixPath, scope);
this.schemaFilter = schemaFilter;
this.templateMap = templateMap;
+ this.includeSystemDatabase = includeSystemDatabase;
+ this.includeAuditDatabase = includeAuditDatabase;
}
public SchemaFilter getSchemaFilter() {
@@ -71,6 +79,14 @@ public class TimeSeriesCountNode extends SchemaQueryScanNode
{
return templateMap;
}
+ public boolean isIncludeSystemDatabase() {
+ return includeSystemDatabase;
+ }
+
+ public boolean isIncludeAuditDatabase() {
+ return includeAuditDatabase;
+ }
+
@Override
public PlanNodeType getType() {
return PlanNodeType.TIME_SERIES_COUNT;
@@ -79,7 +95,14 @@ public class TimeSeriesCountNode extends SchemaQueryScanNode
{
@Override
public PlanNode clone() {
return new TimeSeriesCountNode(
- getPlanNodeId(), path, isPrefixPath, schemaFilter, templateMap, scope);
+ getPlanNodeId(),
+ path,
+ isPrefixPath,
+ schemaFilter,
+ templateMap,
+ scope,
+ includeSystemDatabase,
+ includeAuditDatabase);
}
@Override
@@ -96,6 +119,8 @@ public class TimeSeriesCountNode extends SchemaQueryScanNode
{
scope.serialize(byteBuffer);
ReadWriteIOUtils.write(isPrefixPath, byteBuffer);
SchemaFilter.serialize(schemaFilter, byteBuffer);
+ ReadWriteIOUtils.write(includeSystemDatabase, byteBuffer);
+ ReadWriteIOUtils.write(includeAuditDatabase, byteBuffer);
ReadWriteIOUtils.write(templateMap.size(), byteBuffer);
for (Template template : templateMap.values()) {
template.serialize(byteBuffer);
@@ -109,6 +134,8 @@ public class TimeSeriesCountNode extends
SchemaQueryScanNode {
scope.serialize(stream);
ReadWriteIOUtils.write(isPrefixPath, stream);
SchemaFilter.serialize(schemaFilter, stream);
+ ReadWriteIOUtils.write(includeSystemDatabase, stream);
+ ReadWriteIOUtils.write(includeAuditDatabase, stream);
ReadWriteIOUtils.write(templateMap.size(), stream);
for (Template template : templateMap.values()) {
template.serialize(stream);
@@ -127,6 +154,8 @@ public class TimeSeriesCountNode extends
SchemaQueryScanNode {
PathPatternTree scope = PathPatternTree.deserialize(buffer);
boolean isPrefixPath = ReadWriteIOUtils.readBool(buffer);
SchemaFilter schemaFilter = SchemaFilter.deserialize(buffer);
+ boolean includeSystemDatabase = ReadWriteIOUtils.readBool(buffer);
+ boolean includeAuditDatabase = ReadWriteIOUtils.readBool(buffer);
int templateNum = ReadWriteIOUtils.readInt(buffer);
Map<Integer, Template> templateMap = new HashMap<>();
@@ -139,7 +168,14 @@ public class TimeSeriesCountNode extends
SchemaQueryScanNode {
PlanNodeId planNodeId = PlanNodeId.deserialize(buffer);
return new TimeSeriesCountNode(
- planNodeId, path, isPrefixPath, schemaFilter, templateMap, scope);
+ planNodeId,
+ path,
+ isPrefixPath,
+ schemaFilter,
+ templateMap,
+ scope,
+ includeSystemDatabase,
+ includeAuditDatabase);
}
@Override
@@ -156,11 +192,14 @@ public class TimeSeriesCountNode extends
SchemaQueryScanNode {
if (!super.equals(o)) return false;
TimeSeriesCountNode that = (TimeSeriesCountNode) o;
return Objects.equals(schemaFilter, that.schemaFilter)
- && Objects.equals(templateMap, that.templateMap);
+ && Objects.equals(templateMap, that.templateMap)
+ && includeSystemDatabase == that.includeSystemDatabase
+ && includeAuditDatabase == that.includeAuditDatabase;
}
@Override
public int hashCode() {
- return Objects.hash(super.hashCode(), schemaFilter, templateMap);
+ return Objects.hash(
+ super.hashCode(), schemaFilter, templateMap, includeSystemDatabase,
includeAuditDatabase);
}
}
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/source/TimeseriesRegionScanNode.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/source/TimeseriesRegionScanNode.java
index b960aa5b507..24bcf288403 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/source/TimeseriesRegionScanNode.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/source/TimeseriesRegionScanNode.java
@@ -86,6 +86,13 @@ public class TimeseriesRegionScanNode extends RegionScanNode
{
return deviceToTimeseriesSchemaInfo;
}
+ public boolean hasActiveLogicalViewContext() {
+ return deviceToTimeseriesSchemaInfo.values().stream()
+ .flatMap(timeseriesContextMap ->
timeseriesContextMap.values().stream())
+ .flatMap(List::stream)
+ .anyMatch(context ->
!context.getActiveLogicalViewContextMap().isEmpty());
+ }
+
@Override
public List<PlanNode> getChildren() {
return ImmutableList.of();
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/TreeAccessCheckVisitor.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/TreeAccessCheckVisitor.java
index 68658529e71..fd9757c5f89 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/TreeAccessCheckVisitor.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/TreeAccessCheckVisitor.java
@@ -30,6 +30,7 @@ import org.apache.iotdb.commons.path.MeasurementPath;
import org.apache.iotdb.commons.path.PartialPath;
import org.apache.iotdb.commons.path.PathPatternTree;
import org.apache.iotdb.commons.path.PathPatternTreeUtils;
+import org.apache.iotdb.commons.schema.SchemaConstant;
import org.apache.iotdb.commons.schema.table.Audit;
import org.apache.iotdb.commons.utils.StatusUtils;
import org.apache.iotdb.db.audit.DNAuditLogger;
@@ -54,6 +55,7 @@ import
org.apache.iotdb.db.queryengine.plan.statement.metadata.CountDatabaseStat
import
org.apache.iotdb.db.queryengine.plan.statement.metadata.CountDevicesStatement;
import
org.apache.iotdb.db.queryengine.plan.statement.metadata.CountLevelTimeSeriesStatement;
import
org.apache.iotdb.db.queryengine.plan.statement.metadata.CountNodesStatement;
+import org.apache.iotdb.db.queryengine.plan.statement.metadata.CountStatement;
import
org.apache.iotdb.db.queryengine.plan.statement.metadata.CountTimeSeriesStatement;
import
org.apache.iotdb.db.queryengine.plan.statement.metadata.CountTimeSlotListStatement;
import
org.apache.iotdb.db.queryengine.plan.statement.metadata.CreateAlignedTimeSeriesStatement;
@@ -1393,13 +1395,19 @@ public class TreeAccessCheckVisitor extends
StatementVisitor<TSStatus, TreeAcces
.setAuditLogOperation(AuditLogOperation.QUERY)
.setPrivilegeType(PrivilegeType.READ_SCHEMA);
if (AuthorityChecker.SUPER_USER.equals(context.getUsername())) {
+ statement.setCanSeeSystemDB(true);
statement.setCanSeeAuditDB(true);
AUDIT_LOGGER.recordObjectAuthenticationAuditLog(
context.setResult(true),
() ->
statement.getPaths().stream().distinct().collect(Collectors.toList()).toString());
return SUCCEED;
}
+ TSStatus internalDatabaseStatus =
checkExplicitInternalDatabaseCount(statement, context);
+ if (internalDatabaseStatus != null) {
+ return internalDatabaseStatus;
+ }
setCanSeeAuditDB(statement, context);
+ setCanSeeSystemDB(statement, context);
if (statement.hasTimeCondition()) {
try {
statement.setAuthorityScope(
@@ -1408,6 +1416,7 @@ public class TreeAccessCheckVisitor extends
StatementVisitor<TSStatus, TreeAcces
context.getUsername(), PrivilegeType.READ_SCHEMA),
AuthorityChecker.getAuthorizedPathTree(
context.getUsername(), PrivilegeType.READ_DATA)));
+ appendInternalDatabaseAuthorityScope(statement);
} catch (AuthException e) {
AUDIT_LOGGER.recordObjectAuthenticationAuditLog(
context.setResult(false),
@@ -1419,14 +1428,22 @@ public class TreeAccessCheckVisitor extends
StatementVisitor<TSStatus, TreeAcces
() ->
statement.getPaths().stream().distinct().collect(Collectors.toList()).toString());
return new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode());
} else {
- return visitAuthorityInformation(statement, context);
+ TSStatus status = visitAuthorityInformation(statement, context);
+ if (status.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
+ appendInternalDatabaseAuthorityScope(statement);
+ }
+ return status;
}
}
@Override
public TSStatus visitCountLevelTimeSeries(
CountLevelTimeSeriesStatement countStatement, TreeAccessCheckContext
context) {
+ context
+ .setAuditLogOperation(AuditLogOperation.QUERY)
+ .setPrivilegeType(PrivilegeType.READ_SCHEMA);
if (AuthorityChecker.SUPER_USER.equals(context.getUsername())) {
+ countStatement.setCanSeeSystemDB(true);
countStatement.setCanSeeAuditDB(true);
AUDIT_LOGGER.recordObjectAuthenticationAuditLog(
context.setResult(true),
@@ -1437,8 +1454,86 @@ public class TreeAccessCheckVisitor extends
StatementVisitor<TSStatus, TreeAcces
.toString());
return SUCCEED;
}
+ TSStatus internalDatabaseStatus =
checkExplicitInternalDatabaseCount(countStatement, context);
+ if (internalDatabaseStatus != null) {
+ return internalDatabaseStatus;
+ }
setCanSeeAuditDB(countStatement, context);
- return visitAuthorityInformation(countStatement, context);
+ setCanSeeSystemDB(countStatement, context);
+ TSStatus status = visitAuthorityInformation(countStatement, context);
+ if (status.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
+ appendInternalDatabaseAuthorityScope(countStatement);
+ }
+ return status;
+ }
+
+ private void setCanSeeSystemDB(CountStatement statement, IAuditEntity
auditEntity) {
+ statement.setCanSeeSystemDB(
+ checkHasGlobalAuth(
+ auditEntity, PrivilegeType.SYSTEM, () ->
SchemaConstant.SYSTEM_DATABASE));
+ }
+
+ private void appendInternalDatabaseAuthorityScope(CountStatement statement) {
+ PathPatternTree authorityScope = statement.getAuthorityScope();
+ if (SchemaConstant.ALL_MATCH_SCOPE.equals(authorityScope)) {
+ return;
+ }
+ if (statement.isCanSeeSystemDB()) {
+ authorityScope.appendPathPattern(
+ createInternalDatabasePathPattern(SchemaConstant.SYSTEM_DATABASE),
true);
+ }
+ if (statement.isCanSeeAuditDB()) {
+
authorityScope.appendPathPattern(Audit.TREE_MODEL_AUDIT_DATABASE_PATH_PATTERN,
true);
+ }
+ authorityScope.constructTree();
+ }
+
+ private PartialPath createInternalDatabasePathPattern(String
internalDatabase) {
+ String[] databaseNodes = internalDatabase.split("\\.");
+ String[] pathPatternNodes = Arrays.copyOf(databaseNodes,
databaseNodes.length + 1);
+ pathPatternNodes[databaseNodes.length] =
IoTDBConstant.MULTI_LEVEL_PATH_WILDCARD;
+ return new PartialPath(pathPatternNodes);
+ }
+
+ private TSStatus checkExplicitInternalDatabaseCount(
+ CountStatement statement, TreeAccessCheckContext context) {
+ String internalDatabase =
getExplicitInternalDatabase(statement.getPathPattern());
+ if (internalDatabase == null) {
+ return null;
+ }
+
+ PrivilegeType requiredPrivilege =
+ SchemaConstant.SYSTEM_DATABASE.equals(internalDatabase)
+ ? PrivilegeType.SYSTEM
+ : PrivilegeType.AUDIT;
+ TSStatus status = checkGlobalAuth(context, requiredPrivilege, () ->
internalDatabase);
+ if (status.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
+ return status;
+ }
+
statement.setCanSeeSystemDB(SchemaConstant.SYSTEM_DATABASE.equals(internalDatabase));
+
statement.setCanSeeAuditDB(SchemaConstant.AUDIT_DATABASE.equals(internalDatabase));
+
statement.setAuthorityScope(createAuthorityScope(statement.getPathPattern()));
+ return SUCCEED;
+ }
+
+ private String getExplicitInternalDatabase(PartialPath pathPattern) {
+ String[] nodes = pathPattern.getNodes();
+ if (nodes.length < 2 || !SchemaConstant.ROOT.equals(nodes[0])) {
+ return null;
+ }
+ String database = SchemaConstant.ROOT + "." + nodes[1];
+ if (SchemaConstant.SYSTEM_DATABASE.equals(database)
+ || SchemaConstant.AUDIT_DATABASE.equals(database)) {
+ return database;
+ }
+ return null;
+ }
+
+ private PathPatternTree createAuthorityScope(PartialPath pathPattern) {
+ PathPatternTree authorityScope = new PathPatternTree();
+ authorityScope.appendPathPattern(pathPattern);
+ authorityScope.constructTree();
+ return authorityScope;
}
@Override
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/CountStatement.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/CountStatement.java
index 529a8660dfb..a74390b7bed 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/CountStatement.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/CountStatement.java
@@ -34,6 +34,7 @@ import java.util.List;
*/
public class CountStatement extends ShowStatement {
protected PartialPath pathPattern;
+ private boolean canSeeSystemDB = true;
public CountStatement(PartialPath pathPattern) {
this.pathPattern = pathPattern;
@@ -52,4 +53,12 @@ public class CountStatement extends ShowStatement {
public List<PartialPath> getPaths() {
return Collections.singletonList(pathPattern);
}
+
+ public boolean isCanSeeSystemDB() {
+ return canSeeSystemDB;
+ }
+
+ public void setCanSeeSystemDB(boolean canSeeSystemDB) {
+ this.canSeeSystemDB = canSeeSystemDB;
+ }
}
diff --git
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/auth/TreeAccessTest.java
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/auth/TreeAccessTest.java
index af8746fae3e..dd1826982c9 100644
---
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/auth/TreeAccessTest.java
+++
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/auth/TreeAccessTest.java
@@ -21,9 +21,12 @@ package org.apache.iotdb.db.auth;
import org.apache.iotdb.commons.auth.entity.PrivilegeType;
import org.apache.iotdb.commons.auth.entity.User;
+import org.apache.iotdb.commons.path.PartialPath;
import
org.apache.iotdb.db.queryengine.plan.relational.security.TreeAccessCheckContext;
import
org.apache.iotdb.db.queryengine.plan.relational.security.TreeAccessCheckVisitor;
import org.apache.iotdb.db.queryengine.plan.statement.AuthorType;
+import
org.apache.iotdb.db.queryengine.plan.statement.metadata.CountLevelTimeSeriesStatement;
+import
org.apache.iotdb.db.queryengine.plan.statement.metadata.CountTimeSeriesStatement;
import org.apache.iotdb.db.queryengine.plan.statement.sys.AuthorStatement;
import org.apache.iotdb.rpc.TSStatusCode;
@@ -33,6 +36,8 @@ import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
+import java.util.Collections;
+
public class TreeAccessTest {
@Before
@@ -81,4 +86,132 @@ public class TreeAccessTest {
.visitAuthor(authorStatement, new TreeAccessCheckContext(10000L,
"user1", ""))
.getCode());
}
+
+ @Test
+ public void testCountTimeSeriesInternalDatabasePermission() throws Exception
{
+ User user = new User("user1", "password");
+
AuthorityChecker.getAuthorityFetcher().getAuthorCache().putUserCache(user.getName(),
user);
+ TreeAccessCheckVisitor treeAccessCheckVisitor = new
TreeAccessCheckVisitor();
+
+ CountTimeSeriesStatement systemStatement =
+ new CountTimeSeriesStatement(new PartialPath("root.__system.**"));
+ Assert.assertEquals(
+ TSStatusCode.NO_PERMISSION.getStatusCode(),
+ treeAccessCheckVisitor
+ .visitCountTimeSeries(systemStatement, new
TreeAccessCheckContext(10000L, "user1", ""))
+ .getCode());
+
+ user.grantSysPrivilege(PrivilegeType.SYSTEM, false);
+ systemStatement = new CountTimeSeriesStatement(new
PartialPath("root.__system.**"));
+ Assert.assertEquals(
+ TSStatusCode.SUCCESS_STATUS.getStatusCode(),
+ treeAccessCheckVisitor
+ .visitCountTimeSeries(systemStatement, new
TreeAccessCheckContext(10000L, "user1", ""))
+ .getCode());
+ Assert.assertEquals(
+ Collections.singletonList(new PartialPath("root.__system.**")),
+ systemStatement.getAuthorityScope().getAllPathPatterns());
+ Assert.assertTrue(systemStatement.isCanSeeSystemDB());
+ Assert.assertFalse(systemStatement.isCanSeeAuditDB());
+
+ CountLevelTimeSeriesStatement systemLevelStatement =
+ new CountLevelTimeSeriesStatement(new PartialPath("root.__system.**"),
1);
+ Assert.assertEquals(
+ TSStatusCode.SUCCESS_STATUS.getStatusCode(),
+ treeAccessCheckVisitor
+ .visitCountLevelTimeSeries(
+ systemLevelStatement, new TreeAccessCheckContext(10000L,
"user1", ""))
+ .getCode());
+ Assert.assertEquals(
+ Collections.singletonList(new PartialPath("root.__system.**")),
+ systemLevelStatement.getAuthorityScope().getAllPathPatterns());
+ Assert.assertTrue(systemLevelStatement.isCanSeeSystemDB());
+ Assert.assertFalse(systemLevelStatement.isCanSeeAuditDB());
+
+ CountTimeSeriesStatement auditStatement =
+ new CountTimeSeriesStatement(new PartialPath("root.__audit.**"));
+ Assert.assertEquals(
+ TSStatusCode.NO_PERMISSION.getStatusCode(),
+ treeAccessCheckVisitor
+ .visitCountTimeSeries(auditStatement, new
TreeAccessCheckContext(10000L, "user1", ""))
+ .getCode());
+
+ user.grantSysPrivilege(PrivilegeType.AUDIT, false);
+ auditStatement = new CountTimeSeriesStatement(new
PartialPath("root.__audit.**"));
+ Assert.assertEquals(
+ TSStatusCode.SUCCESS_STATUS.getStatusCode(),
+ treeAccessCheckVisitor
+ .visitCountTimeSeries(auditStatement, new
TreeAccessCheckContext(10000L, "user1", ""))
+ .getCode());
+ Assert.assertTrue(auditStatement.isCanSeeAuditDB());
+ Assert.assertFalse(auditStatement.isCanSeeSystemDB());
+ Assert.assertEquals(
+ Collections.singletonList(new PartialPath("root.__audit.**")),
+ auditStatement.getAuthorityScope().getAllPathPatterns());
+
+ CountLevelTimeSeriesStatement auditLevelStatement =
+ new CountLevelTimeSeriesStatement(new PartialPath("root.__audit.**"),
1);
+ Assert.assertEquals(
+ TSStatusCode.SUCCESS_STATUS.getStatusCode(),
+ treeAccessCheckVisitor
+ .visitCountLevelTimeSeries(
+ auditLevelStatement, new TreeAccessCheckContext(10000L,
"user1", ""))
+ .getCode());
+ Assert.assertTrue(auditLevelStatement.isCanSeeAuditDB());
+ Assert.assertFalse(auditLevelStatement.isCanSeeSystemDB());
+ Assert.assertEquals(
+ Collections.singletonList(new PartialPath("root.__audit.**")),
+ auditLevelStatement.getAuthorityScope().getAllPathPatterns());
+ }
+
+ @Test
+ public void testCountTimeSeriesImplicitInternalDatabasePermission() throws
Exception {
+ User user = new User("user2", "password");
+
AuthorityChecker.getAuthorityFetcher().getAuthorCache().putUserCache(user.getName(),
user);
+ TreeAccessCheckVisitor treeAccessCheckVisitor = new
TreeAccessCheckVisitor();
+
+ CountTimeSeriesStatement statement = new CountTimeSeriesStatement(new
PartialPath("root.**"));
+ Assert.assertEquals(
+ TSStatusCode.SUCCESS_STATUS.getStatusCode(),
+ treeAccessCheckVisitor
+ .visitCountTimeSeries(statement, new
TreeAccessCheckContext(10000L, "user2", ""))
+ .getCode());
+ Assert.assertFalse(statement.isCanSeeSystemDB());
+ Assert.assertFalse(statement.isCanSeeAuditDB());
+
+ user.grantSysPrivilege(PrivilegeType.SYSTEM, false);
+ statement = new CountTimeSeriesStatement(new PartialPath("root.**"));
+ Assert.assertEquals(
+ TSStatusCode.SUCCESS_STATUS.getStatusCode(),
+ treeAccessCheckVisitor
+ .visitCountTimeSeries(statement, new
TreeAccessCheckContext(10000L, "user2", ""))
+ .getCode());
+ Assert.assertTrue(statement.isCanSeeSystemDB());
+ Assert.assertFalse(statement.isCanSeeAuditDB());
+ Assert.assertTrue(
+ statement
+ .getAuthorityScope()
+ .getAllPathPatterns()
+ .contains(new PartialPath("root.__system.**")));
+
+ user.grantSysPrivilege(PrivilegeType.AUDIT, false);
+ statement = new CountTimeSeriesStatement(new PartialPath("root.**"));
+ Assert.assertEquals(
+ TSStatusCode.SUCCESS_STATUS.getStatusCode(),
+ treeAccessCheckVisitor
+ .visitCountTimeSeries(statement, new
TreeAccessCheckContext(10000L, "user2", ""))
+ .getCode());
+ Assert.assertTrue(statement.isCanSeeSystemDB());
+ Assert.assertTrue(statement.isCanSeeAuditDB());
+ Assert.assertTrue(
+ statement
+ .getAuthorityScope()
+ .getAllPathPatterns()
+ .contains(new PartialPath("root.__system.**")));
+ Assert.assertTrue(
+ statement
+ .getAuthorityScope()
+ .getAllPathPatterns()
+ .contains(new PartialPath("root.__audit.**")));
+ }
}
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..307e69a179e
--- /dev/null
+++
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/TimeSeriesSchemaSourceTest.java
@@ -0,0 +1,183 @@
+/*
+ * 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.commons.schema.table.Audit;
+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 testCountSourceSkipsUnauthorizedInternalDatabases() throws
Exception {
+ final ISchemaSource<ITimeSeriesSchemaInfo> countSource =
+ SchemaSourceFactory.getTimeSeriesSchemaCountSource(
+ new PartialPath("root.**"),
+ false,
+ null,
+ Collections.emptyMap(),
+ SchemaConstant.ALL_MATCH_SCOPE,
+ false,
+ false);
+
+ assertTrue(
+
countSource.shouldSkipSchemaRegion(mockSchemaRegion(SchemaConstant.SYSTEM_DATABASE)));
+
assertTrue(countSource.shouldSkipSchemaRegion(mockSchemaRegion(SchemaConstant.AUDIT_DATABASE)));
+ assertTrue(
+
countSource.shouldSkipSchemaRegion(mockSchemaRegion(Audit.TABLE_MODEL_AUDIT_DATABASE)));
+
assertFalse(countSource.shouldSkipSchemaRegion(mockSchemaRegion("root.sg")));
+ }
+
+ @Test
+ public void testCountSourceKeepsAuthorizedInternalDatabases() throws
Exception {
+ final ISchemaSource<ITimeSeriesSchemaInfo> systemCountSource =
+ SchemaSourceFactory.getTimeSeriesSchemaCountSource(
+ new PartialPath("root.**"),
+ false,
+ null,
+ Collections.emptyMap(),
+ SchemaConstant.ALL_MATCH_SCOPE,
+ true,
+ false);
+ assertFalse(
+
systemCountSource.shouldSkipSchemaRegion(mockSchemaRegion(SchemaConstant.SYSTEM_DATABASE)));
+ assertTrue(
+
systemCountSource.shouldSkipSchemaRegion(mockSchemaRegion(SchemaConstant.AUDIT_DATABASE)));
+
+ final ISchemaSource<ITimeSeriesSchemaInfo> auditCountSource =
+ SchemaSourceFactory.getTimeSeriesSchemaCountSource(
+ new PartialPath("root.**"),
+ false,
+ null,
+ Collections.emptyMap(),
+ SchemaConstant.ALL_MATCH_SCOPE,
+ false,
+ true);
+ assertFalse(
+
auditCountSource.shouldSkipSchemaRegion(mockSchemaRegion(SchemaConstant.AUDIT_DATABASE)));
+ assertTrue(
+
auditCountSource.shouldSkipSchemaRegion(mockSchemaRegion(SchemaConstant.SYSTEM_DATABASE)));
+ }
+
+ @Test
+ public void
testCountSourceSkipsUnauthorizedInternalDatabasesWithWildcardSecondNode()
+ throws Exception {
+ final ISchemaSource<ITimeSeriesSchemaInfo> countSource =
+ SchemaSourceFactory.getTimeSeriesSchemaCountSource(
+ new PartialPath("root.*.**"),
+ false,
+ null,
+ Collections.emptyMap(),
+ SchemaConstant.ALL_MATCH_SCOPE,
+ false,
+ false);
+
+ assertTrue(
+
countSource.shouldSkipSchemaRegion(mockSchemaRegion(SchemaConstant.SYSTEM_DATABASE)));
+
assertTrue(countSource.shouldSkipSchemaRegion(mockSchemaRegion(SchemaConstant.AUDIT_DATABASE)));
+
assertFalse(countSource.shouldSkipSchemaRegion(mockSchemaRegion("root.sg")));
+ }
+
+ @Test
+ public void testCountSourceKeepsExactInternalDatabaseQueriesWithPrivilege()
throws Exception {
+ final ISchemaSource<ITimeSeriesSchemaInfo> systemCountSource =
+ SchemaSourceFactory.getTimeSeriesSchemaCountSource(
+ new PartialPath("root.__system"),
+ false,
+ null,
+ Collections.emptyMap(),
+ SchemaConstant.ALL_MATCH_SCOPE,
+ true,
+ false);
+ assertFalse(
+
systemCountSource.shouldSkipSchemaRegion(mockSchemaRegion(SchemaConstant.SYSTEM_DATABASE)));
+
+ final ISchemaSource<ITimeSeriesSchemaInfo> auditCountSource =
+ SchemaSourceFactory.getTimeSeriesSchemaCountSource(
+ new PartialPath("root.__audit"),
+ false,
+ null,
+ Collections.emptyMap(),
+ SchemaConstant.ALL_MATCH_SCOPE,
+ false,
+ true);
+ assertFalse(
+
auditCountSource.shouldSkipSchemaRegion(mockSchemaRegion(SchemaConstant.AUDIT_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,
+ null);
+
+ assertFalse(
+
showSource.shouldSkipSchemaRegion(mockSchemaRegion(SchemaConstant.SYSTEM_DATABASE)));
+
assertFalse(showSource.shouldSkipSchemaRegion(mockSchemaRegion(SchemaConstant.AUDIT_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,
+ false,
+ false);
+ 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;
+ }
+}
diff --git
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/distribution/RegionScanPlanningTest.java
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/distribution/RegionScanPlanningTest.java
index 205758304e0..892fc4ee3dd 100644
---
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/distribution/RegionScanPlanningTest.java
+++
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/distribution/RegionScanPlanningTest.java
@@ -26,6 +26,7 @@ import org.apache.iotdb.commons.path.PartialPath;
import org.apache.iotdb.commons.queryengine.plan.planner.plan.node.PlanNode;
import org.apache.iotdb.db.queryengine.common.MPPQueryContext;
import org.apache.iotdb.db.queryengine.common.QueryId;
+import org.apache.iotdb.db.queryengine.common.TimeseriesContext;
import org.apache.iotdb.db.queryengine.plan.analyze.Analysis;
import org.apache.iotdb.db.queryengine.plan.planner.plan.DistributedQueryPlan;
import org.apache.iotdb.db.queryengine.plan.planner.plan.LogicalQueryPlan;
@@ -36,10 +37,15 @@ import
org.apache.iotdb.db.queryengine.plan.planner.plan.node.source.TimeseriesR
import org.junit.Test;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
import java.util.Set;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class RegionScanPlanningTest {
@@ -145,4 +151,79 @@ public class RegionScanPlanningTest {
assertEquals(devicePaths, targetDevicePaths);
assertEquals(path, targetMeasurementPaths);
}
+
+ @Test
+ public void testCountTimeseriesWithLogicalViewUsesMergeBeforeCount() throws
IllegalPathException {
+ QueryId queryId = new QueryId("test");
+ MPPQueryContext context =
+ new MPPQueryContext("", queryId, null, new TEndPoint(), new
TEndPoint());
+
+ Map<String, TimeseriesContext> logicalViewContextMap =
+ Collections.singletonMap(
+ "root.sg.view.v1",
+ new TimeseriesContext(
+ "INT32",
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ 1,
+ true,
+ "root.sg",
+ Collections.emptyMap()));
+ Map<PartialPath, Map<PartialPath, List<TimeseriesContext>>>
deviceToTimeseriesSchemaInfo =
+ new HashMap<>();
+ deviceToTimeseriesSchemaInfo.put(
+ new PartialPath("root.sg.d22"),
+ Collections.singletonMap(
+ new MeasurementPath("root.sg.d22.s1"),
+ Collections.singletonList(
+ new TimeseriesContext(
+ "INT32",
+ null,
+ "PLAIN",
+ "LZ4",
+ null,
+ null,
+ null,
+ null,
+ 0,
+ logicalViewContextMap))));
+ deviceToTimeseriesSchemaInfo.put(
+ new PartialPath("root.sg.d55555"),
+ Collections.singletonMap(
+ new MeasurementPath("root.sg.d55555.s1"),
+ Collections.singletonList(
+ new TimeseriesContext(
+ "INT32",
+ null,
+ "PLAIN",
+ "LZ4",
+ null,
+ null,
+ null,
+ null,
+ 0,
+ logicalViewContextMap))));
+
+ TimeseriesRegionScanNode regionScanNode =
+ new TimeseriesRegionScanNode(
+ queryId.genPlanNodeId(), deviceToTimeseriesSchemaInfo, true, null);
+ PlanNode rewrittenRoot =
+ new DistributionPlanner(Util.ANALYSIS, new LogicalQueryPlan(context,
regionScanNode))
+ .rewriteSource();
+
+ assertTrue(rewrittenRoot instanceof ActiveRegionScanMergeNode);
+ ActiveRegionScanMergeNode mergeNode = (ActiveRegionScanMergeNode)
rewrittenRoot;
+ assertTrue(mergeNode.isOutputCount());
+ assertTrue(mergeNode.isNeedMerge());
+ assertEquals(2, mergeNode.getChildren().size());
+ for (PlanNode child : mergeNode.getChildren()) {
+ assertTrue(child instanceof TimeseriesRegionScanNode);
+ assertFalse(((TimeseriesRegionScanNode) child).isOutputCount());
+ }
+ }
}
diff --git
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/logical/RegionScanLogicalPlannerTest.java
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/logical/RegionScanLogicalPlannerTest.java
index dd3b8b6281e..6975d845c03 100644
---
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/logical/RegionScanLogicalPlannerTest.java
+++
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/logical/RegionScanLogicalPlannerTest.java
@@ -276,4 +276,51 @@ public class RegionScanLogicalPlannerTest {
buffer.flip();
Assert.assertEquals(timeseriesRegionScanNode,
PlanNodeType.deserialize(buffer));
}
+
+ @Test
+ public void serializeDeserializeLogicalViewContextTest() throws
IllegalPathException {
+ Map<String, TimeseriesContext> logicalViewContextMap =
+ Collections.singletonMap(
+ "root.sg.view.v1",
+ new TimeseriesContext(
+ "INT32",
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ 1,
+ true,
+ "root.sg",
+ new HashMap<>()));
+ Map<PartialPath, List<TimeseriesContext>> timeseriesSchemaInfoMap = new
HashMap<>();
+ timeseriesSchemaInfoMap.put(
+ new MeasurementPath("root.sg.d3.s1", TSDataType.INT32),
+ Collections.singletonList(
+ new TimeseriesContext(
+ "INT32",
+ null,
+ config.getDefaultInt32Encoding().toString(),
+ "LZ4",
+ null,
+ null,
+ null,
+ null,
+ 0,
+ logicalViewContextMap)));
+ Map<PartialPath, Map<PartialPath, List<TimeseriesContext>>>
deviceToTimeseriesSchemaInfo =
+ new HashMap<>();
+ deviceToTimeseriesSchemaInfo.put(new PartialPath("root.sg.d3"),
timeseriesSchemaInfoMap);
+
+ TimeseriesRegionScanNode timeseriesRegionScanNode =
+ new TimeseriesRegionScanNode(
+ new PlanNodeId("timeseries_test_id"),
deviceToTimeseriesSchemaInfo, false, null);
+
+ ByteBuffer buffer = ByteBuffer.allocate(10240);
+ timeseriesRegionScanNode.serialize(buffer);
+ buffer.flip();
+ Assert.assertEquals(timeseriesRegionScanNode,
PlanNodeType.deserialize(buffer));
+ }
}
diff --git
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/node/metadata/read/SchemaCountNodeSerdeTest.java
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/node/metadata/read/SchemaCountNodeSerdeTest.java
index b5dca437289..6be0ad7fae5 100644
---
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/node/metadata/read/SchemaCountNodeSerdeTest.java
+++
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/node/metadata/read/SchemaCountNodeSerdeTest.java
@@ -87,7 +87,9 @@ public class SchemaCountNodeSerdeTest {
10,
null,
Collections.emptyMap(),
- SchemaConstant.ALL_MATCH_SCOPE);
+ SchemaConstant.ALL_MATCH_SCOPE,
+ true,
+ true);
IdentitySinkNode sinkNode =
new IdentitySinkNode(
new PlanNodeId("sink"),
@@ -122,7 +124,9 @@ public class SchemaCountNodeSerdeTest {
true,
null,
Collections.emptyMap(),
- SchemaConstant.ALL_MATCH_SCOPE);
+ SchemaConstant.ALL_MATCH_SCOPE,
+ true,
+ true);
IdentitySinkNode sinkNode =
new IdentitySinkNode(
new PlanNodeId("sink"),