This is an automated email from the ASF dual-hosted git repository.
Caideyipi 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 3af79aa3b47 [to dev/1.3] Fix count and show timeseries follow-up
(#17837)
3af79aa3b47 is described below
commit 3af79aa3b47c888336898da22b74c19d62008c90
Author: Caideyipi <[email protected]>
AuthorDate: Fri Jun 5 15:08:50 2026 +0800
[to dev/1.3] Fix count and show timeseries follow-up (#17837)
* Fix count and show timeseries follow-up (#17804)
* Fix count and show timeseries follow-up
* Refine internal timeseries count permissions
* fix
* Fix timeseries count source permission tests
---
.../regionscan/IoTDBActiveSchemaQueryIT.java | 13 ++
.../impl/DataNodeInternalRPCServiceImpl.java | 2 +-
.../db/queryengine/common/TimeseriesContext.java | 234 ++++++++++++++++++---
.../schema/source/SchemaSourceFactory.java | 15 +-
.../schema/source/TimeSeriesSchemaSource.java | 20 +-
.../source/ActiveTimeSeriesRegionScanOperator.java | 77 ++++---
.../queryengine/plan/analyze/AnalyzeVisitor.java | 48 ++++-
.../plan/planner/LogicalPlanBuilder.java | 12 +-
.../plan/planner/LogicalPlanVisitor.java | 6 +-
.../plan/planner/OperatorTreeGenerator.java | 6 +-
.../plan/planner/distribution/SourceRewriter.java | 10 +-
.../metedata/read/LevelTimeSeriesCountNode.java | 34 ++-
.../node/metedata/read/TimeSeriesCountNode.java | 28 ++-
.../plan/node/source/TimeseriesRegionScanNode.java | 7 +
.../plan/statement/metadata/CountStatement.java | 81 +++++++
.../metadata/CountTimeSeriesStatement.java | 33 +--
.../apache/iotdb/db/auth/AuthorityCheckerTest.java | 74 +++++++
.../schema/source/TimeSeriesSchemaSourceTest.java | 26 ++-
.../distribution/RegionScanPlanningTest.java | 81 +++++++
.../logical/RegionScanLogicalPlannerTest.java | 47 +++++
.../metadata/read/SchemaCountNodeSerdeTest.java | 6 +-
21 files changed, 742 insertions(+), 118 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 98713b94767..f062994fa3d 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
@@ -259,10 +259,23 @@ public class IoTDBActiveSchemaQueryIT extends
AbstractSchemaIT {
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());
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 e265994a370..f5c84a2375f 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
@@ -926,7 +926,7 @@ public class DataNodeInternalRPCServiceImpl implements
IDataNodeRPCService.Iface
for (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);
try (ISchemaReader<ITimeSeriesSchemaInfo> schemaReader =
schemaSource.getSchemaReader(schemaRegion)) {
if (schemaReader.hasNext()) {
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 aaf8b51787d..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
@@ -29,7 +29,8 @@ import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Collections;
-import java.util.HashSet;
+import java.util.HashMap;
+import java.util.Map;
import java.util.Objects;
import java.util.Set;
@@ -45,20 +46,70 @@ public class TimeseriesContext {
private final String deadband;
private final String deadbandParameters;
+ private final String database;
private final int activeCountMultiplier;
- private final Set<String> activeLogicalViewCountSet;
+ private final boolean logicalView;
+ private final Map<String, TimeseriesContext> activeLogicalViewContextMap;
public TimeseriesContext(IMeasurementSchemaInfo schemaInfo) {
- this(schemaInfo, 1, Collections.emptySet());
+ 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());
@@ -66,8 +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.activeLogicalViewCountSet = new HashSet<>(activeLogicalViewCountSet);
+ this.activeLogicalViewContextMap = new
HashMap<>(activeLogicalViewContextMap);
}
public String getDataType() {
@@ -102,12 +154,24 @@ public class TimeseriesContext {
return deadband;
}
+ public String getDatabase() {
+ return database;
+ }
+
public int getActiveCountMultiplier() {
return activeCountMultiplier;
}
public Set<String> getActiveLogicalViewCountSet() {
- return activeLogicalViewCountSet;
+ return activeLogicalViewContextMap.keySet();
+ }
+
+ public Map<String, TimeseriesContext> getActiveLogicalViewContextMap() {
+ return activeLogicalViewContextMap;
+ }
+
+ public boolean isLogicalView() {
+ return logicalView;
}
public TimeseriesContext(
@@ -129,7 +193,9 @@ public class TimeseriesContext {
deadband,
deadbandParameters,
1,
- Collections.emptySet());
+ false,
+ null,
+ Collections.emptyMap());
}
public TimeseriesContext(
@@ -143,6 +209,87 @@ public class TimeseriesContext {
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;
@@ -151,13 +298,31 @@ public class TimeseriesContext {
this.attributes = attributes;
this.deadband = deadband;
this.deadbandParameters = deadbandParameters;
+ this.database = database;
this.activeCountMultiplier = activeCountMultiplier;
- this.activeLogicalViewCountSet = new HashSet<>(activeLogicalViewCountSet);
+ 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) {
- Set<String> mergedActiveLogicalViewCountSet = new
HashSet<>(activeLogicalViewCountSet);
- mergedActiveLogicalViewCountSet.addAll(that.activeLogicalViewCountSet);
+ Map<String, TimeseriesContext> mergedActiveLogicalViewContextMap =
+ new HashMap<>(activeLogicalViewContextMap);
+ mergedActiveLogicalViewContextMap.putAll(that.activeLogicalViewContextMap);
return new TimeseriesContext(
dataType,
alias,
@@ -168,7 +333,9 @@ public class TimeseriesContext {
deadband,
deadbandParameters,
activeCountMultiplier + that.activeCountMultiplier,
- mergedActiveLogicalViewCountSet);
+ logicalView,
+ database,
+ mergedActiveLogicalViewContextMap);
}
public void serializeAttributes(ByteBuffer byteBuffer) {
@@ -180,10 +347,13 @@ 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(activeLogicalViewCountSet.size(), byteBuffer);
- for (String logicalView : activeLogicalViewCountSet) {
- ReadWriteIOUtils.write(logicalView, 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);
}
}
@@ -196,10 +366,13 @@ 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(activeLogicalViewCountSet.size(), stream);
- for (String logicalView : activeLogicalViewCountSet) {
- ReadWriteIOUtils.write(logicalView, 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);
}
}
@@ -212,11 +385,14 @@ 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);
- int activeLogicalViewCountSetSize = ReadWriteIOUtils.readInt(buffer);
- Set<String> activeLogicalViewCountSet = new HashSet<>();
- for (int i = 0; i < activeLogicalViewCountSetSize; i++) {
- activeLogicalViewCountSet.add(ReadWriteIOUtils.readString(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,
@@ -228,7 +404,9 @@ public class TimeseriesContext {
deadband,
deadbandParameters,
activeCountMultiplier,
- activeLogicalViewCountSet);
+ logicalView,
+ database,
+ activeLogicalViewContextMap);
}
@Override
@@ -243,14 +421,16 @@ 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(database, that.database)
&& activeCountMultiplier == that.activeCountMultiplier
- && Objects.equals(activeLogicalViewCountSet,
that.activeLogicalViewCountSet);
+ && logicalView == that.logicalView
+ && Objects.equals(activeLogicalViewContextMap,
that.activeLogicalViewContextMap);
return res;
}
@@ -265,7 +445,9 @@ public class TimeseriesContext {
attributes,
deadband,
deadbandParameters,
+ database,
activeCountMultiplier,
- activeLogicalViewCountSet);
+ logicalView,
+ activeLogicalViewContextMap);
}
}
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 8a0e4abf3f7..ee8ea51baaf 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
@@ -42,9 +42,18 @@ public class SchemaSourceFactory {
boolean isPrefixMatch,
SchemaFilter schemaFilter,
Map<Integer, Template> templateMap,
- PathPatternTree scope) {
+ PathPatternTree scope,
+ boolean includeSystemDatabase) {
return new TimeSeriesSchemaSource(
- pathPattern, isPrefixMatch, 0, 0, schemaFilter, templateMap, false,
true, scope);
+ pathPattern,
+ isPrefixMatch,
+ 0,
+ 0,
+ schemaFilter,
+ templateMap,
+ false,
+ includeSystemDatabase,
+ scope);
}
// show time series
@@ -57,7 +66,7 @@ public class SchemaSourceFactory {
Map<Integer, Template> templateMap,
PathPatternTree scope) {
return new TimeSeriesSchemaSource(
- pathPattern, isPrefixMatch, limit, offset, schemaFilter, templateMap,
true, false, scope);
+ pathPattern, isPrefixMatch, limit, offset, schemaFilter, templateMap,
true, true, 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 cc47a9361b6..6ecd9dc282d 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,7 +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;
+ private final boolean includeSystemDatabase;
TimeSeriesSchemaSource(
PartialPath pathPattern,
@@ -64,7 +64,7 @@ public class TimeSeriesSchemaSource implements
ISchemaSource<ITimeSeriesSchemaIn
SchemaFilter schemaFilter,
Map<Integer, Template> templateMap,
boolean needViewDetail,
- boolean excludeInternalDatabase,
+ boolean includeSystemDatabase,
PathPatternTree scope) {
this.pathPattern = pathPattern;
this.isPrefixMatch = isPrefixMatch;
@@ -73,7 +73,7 @@ public class TimeSeriesSchemaSource implements
ISchemaSource<ITimeSeriesSchemaIn
this.schemaFilter = schemaFilter;
this.templateMap = templateMap;
this.needViewDetail = needViewDetail;
- this.excludeInternalDatabase = excludeInternalDatabase;
+ this.includeSystemDatabase = includeSystemDatabase;
this.scope = scope;
}
@@ -141,19 +141,11 @@ public class TimeSeriesSchemaSource implements
ISchemaSource<ITimeSeriesSchemaIn
@Override
public boolean shouldSkipSchemaRegion(final ISchemaRegion schemaRegion) {
- if (!excludeInternalDatabase) {
- return false;
- }
-
final String database = schemaRegion.getDatabaseFullPath();
- if (!SchemaConstant.SYSTEM_DATABASE.equals(database)) {
- return false;
+ if (SchemaConstant.SYSTEM_DATABASE.equals(database)) {
+ return !includeSystemDatabase;
}
-
- final String[] nodes = pathPattern.getNodes();
- return nodes.length < 2
- || !SchemaConstant.ROOT.equals(nodes[0])
- || !database.endsWith("." + nodes[1]);
+ return false;
}
public static String mapToString(Map<String, String> map) {
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 264bea0dd0e..a42386dfd4e 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
@@ -46,8 +46,12 @@ public class ActiveTimeSeriesRegionScanOperator extends
AbstractRegionScanDataSo
// 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 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)
@@ -66,14 +70,13 @@ public class ActiveTimeSeriesRegionScanOperator extends
AbstractRegionScanDataSo
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
@@ -97,9 +100,6 @@ 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();
@@ -128,26 +128,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 b4d056c1ff7..a7f95534670 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
@@ -36,6 +36,7 @@ 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.schema.SchemaConstant;
import org.apache.iotdb.commons.schema.view.LogicalViewSchema;
import org.apache.iotdb.commons.schema.view.viewExpression.ViewExpression;
import org.apache.iotdb.commons.service.metric.PerformanceOverviewMetrics;
@@ -53,6 +54,7 @@ import
org.apache.iotdb.db.protocol.client.ConfigNodeClientManager;
import org.apache.iotdb.db.protocol.client.ConfigNodeInfo;
import org.apache.iotdb.db.queryengine.common.DeviceContext;
import org.apache.iotdb.db.queryengine.common.MPPQueryContext;
+import org.apache.iotdb.db.queryengine.common.NodeRef;
import org.apache.iotdb.db.queryengine.common.TimeseriesContext;
import org.apache.iotdb.db.queryengine.common.header.ColumnHeader;
import org.apache.iotdb.db.queryengine.common.header.ColumnHeaderConstant;
@@ -83,6 +85,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.metedata.write.MeasurementGroup;
import
org.apache.iotdb.db.queryengine.plan.planner.plan.parameter.DeviceViewIntoPathDescriptor;
@@ -157,6 +160,7 @@ import
org.apache.iotdb.db.queryengine.plan.statement.sys.ExplainAnalyzeStatemen
import org.apache.iotdb.db.queryengine.plan.statement.sys.ExplainStatement;
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.db.schemaengine.template.Template;
import org.apache.iotdb.db.utils.constant.SqlConstant;
import org.apache.iotdb.rpc.RpcUtils;
@@ -3113,6 +3117,7 @@ public class AnalyzeVisitor extends
StatementVisitor<Analysis, MPPQueryContext>
Analysis analysis,
MPPQueryContext context,
PathPatternTree authorityScope,
+ boolean canSeeSystemDB,
boolean includeLogicalView)
throws IllegalPathException {
analyzeGlobalTimeConditionInShowMetaData(timeCondition, analysis);
@@ -3145,6 +3150,9 @@ public class AnalyzeVisitor extends
StatementVisitor<Analysis, MPPQueryContext>
for (DeviceSchemaInfo deviceSchemaInfo : deviceSchemaInfoList) {
boolean isAligned = deviceSchemaInfo.isAligned();
PartialPath devicePath = deviceSchemaInfo.getDevicePath();
+ if (shouldSkipInternalDatabaseForActiveCount(devicePath, schemaTree,
canSeeSystemDB)) {
+ continue;
+ }
if (isAligned) {
List<String> measurementList = new ArrayList<>();
List<IMeasurementSchema> schemaList = new ArrayList<>();
@@ -3202,6 +3210,15 @@ public class AnalyzeVisitor extends
StatementVisitor<Analysis, MPPQueryContext>
return true;
}
+ private boolean shouldSkipInternalDatabaseForActiveCount(
+ PartialPath devicePath, ISchemaTree schemaTree, boolean canSeeSystemDB) {
+ String database = schemaTree.getBelongedDatabase(devicePath);
+ if (SchemaConstant.SYSTEM_DATABASE.equals(database)) {
+ return !canSeeSystemDB;
+ }
+ return false;
+ }
+
private void addLogicalViewSourcesForActiveCount(
PartialPath viewDevicePath,
IMeasurementSchemaInfo viewSchemaInfo,
@@ -3214,6 +3231,8 @@ public class AnalyzeVisitor extends
StatementVisitor<Analysis, MPPQueryContext>
}
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;
@@ -3234,16 +3253,39 @@ public class AnalyzeVisitor extends
StatementVisitor<Analysis, MPPQueryContext>
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,
Collections.singleton(viewPath)),
+ 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,
@@ -3290,7 +3332,8 @@ public class AnalyzeVisitor extends
StatementVisitor<Analysis, MPPQueryContext>
analysis,
context,
showTimeSeriesStatement.getAuthorityScope(),
- false);
+ true,
+ true);
if (!hasSchema) {
analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowTimeSeriesHeader());
return analysis;
@@ -3535,6 +3578,7 @@ public class AnalyzeVisitor extends
StatementVisitor<Analysis, MPPQueryContext>
analysis,
context,
countTimeSeriesStatement.getAuthorityScope(),
+ countTimeSeriesStatement.isCanSeeSystemDB(),
true);
if (!hasSchema) {
analysis.setRespDatasetHeader(DatasetHeaderFactory.getCountTimeSeriesHeader());
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 401e5393aac..32d7b312257 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
@@ -1164,7 +1164,8 @@ public class LogicalPlanBuilder {
boolean prefixPath,
SchemaFilter schemaFilter,
Map<Integer, Template> templateMap,
- PathPatternTree scope) {
+ PathPatternTree scope,
+ boolean includeSystemDatabase) {
this.root =
new TimeSeriesCountNode(
context.getQueryId().genPlanNodeId(),
@@ -1172,7 +1173,8 @@ public class LogicalPlanBuilder {
prefixPath,
schemaFilter,
templateMap,
- scope);
+ scope,
+ includeSystemDatabase);
return this;
}
@@ -1182,7 +1184,8 @@ public class LogicalPlanBuilder {
int level,
SchemaFilter schemaFilter,
Map<Integer, Template> templateMap,
- PathPatternTree scope) {
+ PathPatternTree scope,
+ boolean includeSystemDatabase) {
this.root =
new LevelTimeSeriesCountNode(
context.getQueryId().genPlanNodeId(),
@@ -1191,7 +1194,8 @@ public class LogicalPlanBuilder {
level,
schemaFilter,
templateMap,
- scope);
+ scope,
+ includeSystemDatabase);
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 69fd1208535..5a004d79038 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
@@ -660,7 +660,8 @@ public class LogicalPlanVisitor extends
StatementVisitor<PlanNode, MPPQueryConte
countTimeSeriesStatement.isPrefixPath(),
countTimeSeriesStatement.getSchemaFilter(),
analysis.getRelatedTemplateInfo(),
- countTimeSeriesStatement.getAuthorityScope())
+ countTimeSeriesStatement.getAuthorityScope(),
+ countTimeSeriesStatement.isCanSeeSystemDB())
.planCountMerge()
.getRoot();
}
@@ -676,7 +677,8 @@ public class LogicalPlanVisitor extends
StatementVisitor<PlanNode, MPPQueryConte
countLevelTimeSeriesStatement.getLevel(),
countLevelTimeSeriesStatement.getSchemaFilter(),
analysis.getRelatedTemplateInfo(),
- countLevelTimeSeriesStatement.getAuthorityScope())
+ countLevelTimeSeriesStatement.getAuthorityScope(),
+ countLevelTimeSeriesStatement.isCanSeeSystemDB())
.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 c93912c27eb..2ec962c8274 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
@@ -993,7 +993,8 @@ public class OperatorTreeGenerator extends
PlanVisitor<Operator, LocalExecutionP
node.isPrefixPath(),
node.getSchemaFilter(),
node.getTemplateMap(),
- node.getScope()));
+ node.getScope(),
+ node.isIncludeSystemDatabase()));
}
@Override
@@ -1015,7 +1016,8 @@ public class OperatorTreeGenerator extends
PlanVisitor<Operator, LocalExecutionP
node.isPrefixPath(),
node.getSchemaFilter(),
node.getTemplateMap(),
- node.getScope()));
+ node.getScope(),
+ node.isIncludeSystemDatabase()));
}
@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 380a351f65e..60bb2807668 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
@@ -823,7 +823,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(),
@@ -837,6 +840,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/metedata/read/LevelTimeSeriesCountNode.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/metedata/read/LevelTimeSeriesCountNode.java
index 2178e06c9e7..c4c05893300 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/metedata/read/LevelTimeSeriesCountNode.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/metedata/read/LevelTimeSeriesCountNode.java
@@ -47,6 +47,7 @@ public class LevelTimeSeriesCountNode extends
SchemaQueryScanNode {
private final int level;
private final SchemaFilter schemaFilter;
private final Map<Integer, Template> templateMap;
+ private final boolean includeSystemDatabase;
public LevelTimeSeriesCountNode(
PlanNodeId id,
@@ -55,11 +56,13 @@ public class LevelTimeSeriesCountNode extends
SchemaQueryScanNode {
int level,
SchemaFilter schemaFilter,
@NotNull Map<Integer, Template> templateMap,
- @NotNull PathPatternTree scope) {
+ @NotNull PathPatternTree scope,
+ boolean includeSystemDatabase) {
super(id, partialPath, isPrefixPath, scope);
this.level = level;
this.schemaFilter = schemaFilter;
this.templateMap = templateMap;
+ this.includeSystemDatabase = includeSystemDatabase;
}
public SchemaFilter getSchemaFilter() {
@@ -74,6 +77,10 @@ public class LevelTimeSeriesCountNode extends
SchemaQueryScanNode {
return templateMap;
}
+ public boolean isIncludeSystemDatabase() {
+ return includeSystemDatabase;
+ }
+
@Override
public PlanNodeType getType() {
return PlanNodeType.LEVEL_TIME_SERIES_COUNT;
@@ -82,7 +89,14 @@ 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);
}
@Override
@@ -100,6 +114,7 @@ public class LevelTimeSeriesCountNode extends
SchemaQueryScanNode {
ReadWriteIOUtils.write(isPrefixPath, byteBuffer);
ReadWriteIOUtils.write(level, byteBuffer);
SchemaFilter.serialize(schemaFilter, byteBuffer);
+ ReadWriteIOUtils.write(includeSystemDatabase, byteBuffer);
ReadWriteIOUtils.write(templateMap.size(), byteBuffer);
for (Template template : templateMap.values()) {
template.serialize(byteBuffer);
@@ -114,6 +129,7 @@ public class LevelTimeSeriesCountNode extends
SchemaQueryScanNode {
ReadWriteIOUtils.write(isPrefixPath, stream);
ReadWriteIOUtils.write(level, stream);
SchemaFilter.serialize(schemaFilter, stream);
+ ReadWriteIOUtils.write(includeSystemDatabase, stream);
ReadWriteIOUtils.write(templateMap.size(), stream);
for (Template template : templateMap.values()) {
template.serialize(stream);
@@ -132,6 +148,7 @@ 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);
int templateNum = ReadWriteIOUtils.readInt(buffer);
Map<Integer, Template> templateMap = new HashMap<>();
Template template;
@@ -142,7 +159,14 @@ 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);
}
@Override
@@ -157,12 +181,12 @@ public class LevelTimeSeriesCountNode extends
SchemaQueryScanNode {
return false;
}
LevelTimeSeriesCountNode that = (LevelTimeSeriesCountNode) o;
- return level == that.level;
+ return level == that.level && includeSystemDatabase ==
that.includeSystemDatabase;
}
@Override
public int hashCode() {
- return Objects.hash(super.hashCode(), level);
+ return Objects.hash(super.hashCode(), level, includeSystemDatabase);
}
@Override
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/metedata/read/TimeSeriesCountNode.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/metedata/read/TimeSeriesCountNode.java
index 473d59b8d15..6f7483132a3 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/metedata/read/TimeSeriesCountNode.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/metedata/read/TimeSeriesCountNode.java
@@ -49,16 +49,20 @@ public class TimeSeriesCountNode extends
SchemaQueryScanNode {
private final Map<Integer, Template> templateMap;
+ private final boolean includeSystemDatabase;
+
public TimeSeriesCountNode(
PlanNodeId id,
PartialPath partialPath,
boolean isPrefixPath,
SchemaFilter schemaFilter,
@NotNull Map<Integer, Template> templateMap,
- @NotNull PathPatternTree scope) {
+ @NotNull PathPatternTree scope,
+ boolean includeSystemDatabase) {
super(id, partialPath, isPrefixPath, scope);
this.schemaFilter = schemaFilter;
this.templateMap = templateMap;
+ this.includeSystemDatabase = includeSystemDatabase;
}
public SchemaFilter getSchemaFilter() {
@@ -69,6 +73,10 @@ public class TimeSeriesCountNode extends SchemaQueryScanNode
{
return templateMap;
}
+ public boolean isIncludeSystemDatabase() {
+ return includeSystemDatabase;
+ }
+
@Override
public PlanNodeType getType() {
return PlanNodeType.TIME_SERIES_COUNT;
@@ -77,7 +85,13 @@ 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);
}
@Override
@@ -94,6 +108,7 @@ public class TimeSeriesCountNode extends SchemaQueryScanNode
{
scope.serialize(byteBuffer);
ReadWriteIOUtils.write(isPrefixPath, byteBuffer);
SchemaFilter.serialize(schemaFilter, byteBuffer);
+ ReadWriteIOUtils.write(includeSystemDatabase, byteBuffer);
ReadWriteIOUtils.write(templateMap.size(), byteBuffer);
for (Template template : templateMap.values()) {
template.serialize(byteBuffer);
@@ -107,6 +122,7 @@ public class TimeSeriesCountNode extends
SchemaQueryScanNode {
scope.serialize(stream);
ReadWriteIOUtils.write(isPrefixPath, stream);
SchemaFilter.serialize(schemaFilter, stream);
+ ReadWriteIOUtils.write(includeSystemDatabase, stream);
ReadWriteIOUtils.write(templateMap.size(), stream);
for (Template template : templateMap.values()) {
template.serialize(stream);
@@ -124,6 +140,7 @@ 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);
int templateNum = ReadWriteIOUtils.readInt(buffer);
Map<Integer, Template> templateMap = new HashMap<>();
@@ -136,7 +153,7 @@ 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);
}
@Override
@@ -153,11 +170,12 @@ 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;
}
@Override
public int hashCode() {
- return Objects.hash(super.hashCode(), schemaFilter, templateMap);
+ return Objects.hash(super.hashCode(), schemaFilter, templateMap,
includeSystemDatabase);
}
}
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 5a5abed1aa0..d905c8eca2c 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
@@ -85,6 +85,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/statement/metadata/CountStatement.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/CountStatement.java
index 529a8660dfb..6ea44f6c113 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
@@ -19,9 +19,17 @@
package org.apache.iotdb.db.queryengine.plan.statement.metadata;
+import org.apache.iotdb.common.rpc.thrift.TSStatus;
+import org.apache.iotdb.commons.auth.entity.PrivilegeType;
+import org.apache.iotdb.commons.conf.IoTDBConstant;
import org.apache.iotdb.commons.path.PartialPath;
+import org.apache.iotdb.commons.path.PathPatternTree;
+import org.apache.iotdb.commons.schema.SchemaConstant;
+import org.apache.iotdb.db.auth.AuthorityChecker;
import org.apache.iotdb.db.queryengine.plan.statement.StatementType;
+import org.apache.iotdb.rpc.TSStatusCode;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -34,6 +42,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 +61,76 @@ public class CountStatement extends ShowStatement {
public List<PartialPath> getPaths() {
return Collections.singletonList(pathPattern);
}
+
+ @Override
+ public TSStatus checkPermissionBeforeProcess(String userName) {
+ if (AuthorityChecker.SUPER_USER.equals(userName)) {
+ setCanSeeSystemDB(true);
+ return AuthorityChecker.SUCCEED;
+ }
+ TSStatus explicitInternalDatabaseStatus =
checkExplicitInternalDatabase(userName);
+ if (explicitInternalDatabaseStatus != null) {
+ return explicitInternalDatabaseStatus;
+ }
+ setCanSeeSystemDB(userName);
+ TSStatus status = super.checkPermissionBeforeProcess(userName);
+ if (status.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
+ appendInternalDatabaseAuthorityScope();
+ }
+ return status;
+ }
+
+ public boolean isCanSeeSystemDB() {
+ return canSeeSystemDB;
+ }
+
+ public void setCanSeeSystemDB(boolean canSeeSystemDB) {
+ this.canSeeSystemDB = canSeeSystemDB;
+ }
+
+ protected void setCanSeeSystemDB(String userName) {
+ setCanSeeSystemDB(
+ AuthorityChecker.checkSystemPermission(userName,
PrivilegeType.MAINTAIN.ordinal()));
+ }
+
+ protected TSStatus checkExplicitInternalDatabase(String userName) {
+ if (!isExplicitSystemDatabasePath()) {
+ return null;
+ }
+ if (!AuthorityChecker.checkSystemPermission(userName,
PrivilegeType.MAINTAIN.ordinal())) {
+ return AuthorityChecker.getTSStatus(false, PrivilegeType.MAINTAIN);
+ }
+ setCanSeeSystemDB(true);
+ authorityScope = createAuthorityScope(pathPattern);
+ return AuthorityChecker.SUCCEED;
+ }
+
+ protected void appendInternalDatabaseAuthorityScope() {
+ if (!canSeeSystemDB ||
SchemaConstant.ALL_MATCH_SCOPE.equals(authorityScope)) {
+ return;
+ }
+ authorityScope.appendPathPattern(createInternalDatabasePathPattern());
+ authorityScope.constructTree();
+ }
+
+ private boolean isExplicitSystemDatabasePath() {
+ String[] nodes = pathPattern.getNodes();
+ return nodes.length >= 2
+ && SchemaConstant.ROOT.equals(nodes[0])
+ && SchemaConstant.SYSTEM_DATABASE.equals(SchemaConstant.ROOT + "." +
nodes[1]);
+ }
+
+ private PartialPath createInternalDatabasePathPattern() {
+ String[] databaseNodes = SchemaConstant.SYSTEM_DATABASE.split("\\.");
+ String[] pathPatternNodes = Arrays.copyOf(databaseNodes,
databaseNodes.length + 1);
+ pathPatternNodes[databaseNodes.length] =
IoTDBConstant.MULTI_LEVEL_PATH_WILDCARD;
+ return new PartialPath(pathPatternNodes);
+ }
+
+ private PathPatternTree createAuthorityScope(PartialPath pathPattern) {
+ PathPatternTree authorityScope = new PathPatternTree();
+ authorityScope.appendPathPattern(pathPattern);
+ authorityScope.constructTree();
+ return authorityScope;
+ }
}
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/CountTimeSeriesStatement.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/CountTimeSeriesStatement.java
index c0910185421..870c0cf8cb8 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/CountTimeSeriesStatement.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/CountTimeSeriesStatement.java
@@ -62,22 +62,27 @@ public class CountTimeSeriesStatement extends
CountStatement {
@Override
public TSStatus checkPermissionBeforeProcess(String userName) {
- if (hasTimeCondition()) {
- try {
- if (!AuthorityChecker.SUPER_USER.equals(userName)) {
- this.authorityScope =
- PathPatternTreeUtils.intersectWithFullPathPrefixTree(
- AuthorityChecker.getAuthorizedPathTree(
- userName, PrivilegeType.READ_SCHEMA.ordinal()),
- AuthorityChecker.getAuthorizedPathTree(
- userName, PrivilegeType.READ_DATA.ordinal()));
- }
- } catch (AuthException e) {
- return new TSStatus(e.getCode().getStatusCode());
+ if (!hasTimeCondition()) {
+ return super.checkPermissionBeforeProcess(userName);
+ }
+ try {
+ if (AuthorityChecker.SUPER_USER.equals(userName)) {
+ setCanSeeSystemDB(true);
+ return new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode());
}
+ TSStatus explicitInternalDatabaseStatus =
checkExplicitInternalDatabase(userName);
+ if (explicitInternalDatabaseStatus != null) {
+ return explicitInternalDatabaseStatus;
+ }
+ setCanSeeSystemDB(userName);
+ this.authorityScope =
+ PathPatternTreeUtils.intersectWithFullPathPrefixTree(
+ AuthorityChecker.getAuthorizedPathTree(userName,
PrivilegeType.READ_SCHEMA.ordinal()),
+ AuthorityChecker.getAuthorizedPathTree(userName,
PrivilegeType.READ_DATA.ordinal()));
+ appendInternalDatabaseAuthorityScope();
return new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode());
- } else {
- return super.checkPermissionBeforeProcess(userName);
+ } catch (AuthException e) {
+ return new TSStatus(e.getCode().getStatusCode());
}
}
diff --git
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/auth/AuthorityCheckerTest.java
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/auth/AuthorityCheckerTest.java
index ca730c377b7..2861059808a 100644
---
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/auth/AuthorityCheckerTest.java
+++
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/auth/AuthorityCheckerTest.java
@@ -20,18 +20,36 @@
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.conf.CommonConfig;
import org.apache.iotdb.commons.conf.CommonDescriptor;
import org.apache.iotdb.commons.exception.IllegalPathException;
import org.apache.iotdb.commons.path.MeasurementPath;
+import org.apache.iotdb.commons.path.PartialPath;
+import
org.apache.iotdb.db.queryengine.plan.statement.metadata.CountLevelTimeSeriesStatement;
+import
org.apache.iotdb.db.queryengine.plan.statement.metadata.CountTimeSeriesStatement;
+import org.apache.iotdb.rpc.TSStatusCode;
+import org.junit.After;
import org.junit.Assert;
+import org.junit.Before;
import org.junit.Test;
import java.util.Arrays;
+import java.util.Collections;
public class AuthorityCheckerTest {
+ @Before
+ public void setup() {
+ AuthorityChecker.getAuthorityFetcher().getAuthorCache().invalidAllCache();
+ }
+
+ @After
+ public void teardown() {
+ AuthorityChecker.getAuthorityFetcher().getAuthorCache().invalidAllCache();
+ }
+
@Test
public void testLogReduce() throws IllegalPathException {
final CommonConfig config = CommonDescriptor.getInstance().getConfig();
@@ -48,4 +66,60 @@ public class AuthorityCheckerTest {
.getMessage());
config.setPathLogMaxSize(oldSize);
}
+
+ @Test
+ public void testCountTimeSeriesExplicitSystemDatabasePermission() throws
Exception {
+ User user = new User("user1", "password");
+
AuthorityChecker.getAuthorityFetcher().getAuthorCache().putUserCache(user.getName(),
user);
+
+ CountTimeSeriesStatement systemStatement =
+ new CountTimeSeriesStatement(new PartialPath("root.__system.**"));
+ Assert.assertEquals(
+ TSStatusCode.NO_PERMISSION.getStatusCode(),
+
systemStatement.checkPermissionBeforeProcess(user.getName()).getCode());
+
+ user.addSysPrivilege(PrivilegeType.MAINTAIN.ordinal());
+ systemStatement = new CountTimeSeriesStatement(new
PartialPath("root.__system.**"));
+ Assert.assertEquals(
+ TSStatusCode.SUCCESS_STATUS.getStatusCode(),
+
systemStatement.checkPermissionBeforeProcess(user.getName()).getCode());
+ Assert.assertEquals(
+ Collections.singletonList(new PartialPath("root.__system.**")),
+ systemStatement.getAuthorityScope().getAllPathPatterns());
+ Assert.assertTrue(systemStatement.isCanSeeSystemDB());
+
+ CountLevelTimeSeriesStatement systemLevelStatement =
+ new CountLevelTimeSeriesStatement(new PartialPath("root.__system.**"),
1);
+ Assert.assertEquals(
+ TSStatusCode.SUCCESS_STATUS.getStatusCode(),
+
systemLevelStatement.checkPermissionBeforeProcess(user.getName()).getCode());
+ Assert.assertEquals(
+ Collections.singletonList(new PartialPath("root.__system.**")),
+ systemLevelStatement.getAuthorityScope().getAllPathPatterns());
+ Assert.assertTrue(systemLevelStatement.isCanSeeSystemDB());
+ }
+
+ @Test
+ public void testCountTimeSeriesImplicitSystemDatabasePermission() throws
Exception {
+ User user = new User("user2", "password");
+
AuthorityChecker.getAuthorityFetcher().getAuthorCache().putUserCache(user.getName(),
user);
+
+ CountTimeSeriesStatement statement = new CountTimeSeriesStatement(new
PartialPath("root.**"));
+ Assert.assertEquals(
+ TSStatusCode.SUCCESS_STATUS.getStatusCode(),
+ statement.checkPermissionBeforeProcess(user.getName()).getCode());
+ Assert.assertFalse(statement.isCanSeeSystemDB());
+
+ user.addSysPrivilege(PrivilegeType.MAINTAIN.ordinal());
+ statement = new CountTimeSeriesStatement(new PartialPath("root.**"));
+ Assert.assertEquals(
+ TSStatusCode.SUCCESS_STATUS.getStatusCode(),
+ statement.checkPermissionBeforeProcess(user.getName()).getCode());
+ Assert.assertTrue(statement.isCanSeeSystemDB());
+ Assert.assertTrue(
+ statement
+ .getAuthorityScope()
+ .getAllPathPatterns()
+ .contains(new PartialPath("root.__system.**")));
+ }
}
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
index b7becf649c9..84acab189f4 100644
---
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
@@ -37,14 +37,15 @@ import static org.junit.Assert.assertTrue;
public class TimeSeriesSchemaSourceTest {
@Test
- public void testCountSourceSkipsImplicitInternalDatabases() throws Exception
{
+ public void testCountSourceSkipsUnauthorizedInternalDatabases() throws
Exception {
final ISchemaSource<ITimeSeriesSchemaInfo> countSource =
SchemaSourceFactory.getTimeSeriesSchemaCountSource(
new PartialPath("root.**"),
false,
null,
Collections.emptyMap(),
- SchemaConstant.ALL_MATCH_SCOPE);
+ SchemaConstant.ALL_MATCH_SCOPE,
+ false);
assertTrue(
countSource.shouldSkipSchemaRegion(mockSchemaRegion(SchemaConstant.SYSTEM_DATABASE)));
@@ -52,27 +53,30 @@ public class TimeSeriesSchemaSourceTest {
}
@Test
- public void testCountSourceKeepsExplicitInternalDatabaseQueries() throws
Exception {
+ public void testCountSourceKeepsAuthorizedInternalDatabases() throws
Exception {
final ISchemaSource<ITimeSeriesSchemaInfo> systemCountSource =
SchemaSourceFactory.getTimeSeriesSchemaCountSource(
- new PartialPath("root.__system.**"),
+ new PartialPath("root.**"),
false,
null,
Collections.emptyMap(),
- SchemaConstant.ALL_MATCH_SCOPE);
+ SchemaConstant.ALL_MATCH_SCOPE,
+ true);
assertFalse(
systemCountSource.shouldSkipSchemaRegion(mockSchemaRegion(SchemaConstant.SYSTEM_DATABASE)));
}
@Test
- public void testCountSourceSkipsWildcardSecondNodeForInternalDatabases()
throws Exception {
+ public void
testCountSourceSkipsUnauthorizedInternalDatabasesWithWildcardSecondNode()
+ throws Exception {
final ISchemaSource<ITimeSeriesSchemaInfo> countSource =
SchemaSourceFactory.getTimeSeriesSchemaCountSource(
new PartialPath("root.*.**"),
false,
null,
Collections.emptyMap(),
- SchemaConstant.ALL_MATCH_SCOPE);
+ SchemaConstant.ALL_MATCH_SCOPE,
+ false);
assertTrue(
countSource.shouldSkipSchemaRegion(mockSchemaRegion(SchemaConstant.SYSTEM_DATABASE)));
@@ -80,14 +84,15 @@ public class TimeSeriesSchemaSourceTest {
}
@Test
- public void testCountSourceKeepsExactInternalDatabaseQueries() throws
Exception {
+ public void testCountSourceKeepsExactInternalDatabaseQueriesWithPrivilege()
throws Exception {
final ISchemaSource<ITimeSeriesSchemaInfo> systemCountSource =
SchemaSourceFactory.getTimeSeriesSchemaCountSource(
new PartialPath("root.__system"),
false,
null,
Collections.emptyMap(),
- SchemaConstant.ALL_MATCH_SCOPE);
+ SchemaConstant.ALL_MATCH_SCOPE,
+ true);
assertFalse(
systemCountSource.shouldSkipSchemaRegion(mockSchemaRegion(SchemaConstant.SYSTEM_DATABASE)));
}
@@ -116,7 +121,8 @@ public class TimeSeriesSchemaSourceTest {
false,
null,
Collections.emptyMap(),
- SchemaConstant.ALL_MATCH_SCOPE);
+ SchemaConstant.ALL_MATCH_SCOPE,
+ false);
final ISchemaRegion schemaRegion = mockSchemaRegion("root.sg");
final ISchemaRegionStatistics schemaRegionStatistics =
Mockito.mock(ISchemaRegionStatistics.class);
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 7a5eccd87a5..fba26ceea80 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
@@ -25,6 +25,7 @@ import org.apache.iotdb.commons.path.MeasurementPath;
import org.apache.iotdb.commons.path.PartialPath;
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;
@@ -37,10 +38,15 @@ import
org.apache.iotdb.db.queryengine.plan.planner.plan.node.source.TimeseriesR
import org.apache.tsfile.file.metadata.PlainDeviceID;
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 {
@@ -146,4 +152,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 2b2d169cafa..ed9b57a5b9d 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
@@ -287,4 +287,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,
+
TSFileDescriptor.getInstance().getConfig().getValueEncoder(TSDataType.INT32),
+ "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 0139371e26b..fb78ea46a2b 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,8 @@ public class SchemaCountNodeSerdeTest {
10,
null,
Collections.emptyMap(),
- SchemaConstant.ALL_MATCH_SCOPE);
+ SchemaConstant.ALL_MATCH_SCOPE,
+ true);
IdentitySinkNode sinkNode =
new IdentitySinkNode(
new PlanNodeId("sink"),
@@ -122,7 +123,8 @@ public class SchemaCountNodeSerdeTest {
true,
null,
Collections.emptyMap(),
- SchemaConstant.ALL_MATCH_SCOPE);
+ SchemaConstant.ALL_MATCH_SCOPE,
+ true);
IdentitySinkNode sinkNode =
new IdentitySinkNode(
new PlanNodeId("sink"),