From ced44bba1967a79330fa71bfd653cd2ffe8f49c0 Mon Sep 17 00:00:00 2001 From: Weihao Li <60659567+Wei-hao-Li@users.noreply.github.com> Date: Thu, 29 Jan 2026 17:44:02 +0800 Subject: [PATCH] Fix timeseries alias display in last for TreeModel (#17109) (cherry picked from commit 5f641b262c33b160e6231adfe955342e8e3ca108) Signed-off-by: Weihao Li <18110526956@163.com> # Conflicts: # integration-test/src/test/java/org/apache/iotdb/db/it/aligned/IoTDBAlignedLastQueryIT.java # iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/process/last/AlignedUpdateViewPathLastCacheOperator.java # iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeVisitor.java # iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/LogicalPlanBuilder.java # iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/OperatorTreeGenerator.java # iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanGraphPrinter.java # iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/process/last/LastQueryNode.java # iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/source/LastQueryScanNode.java # iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/distribution/LastQueryTest.java # iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/logical/DataQueryLogicalPlannerTest.java # iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/node/source/LastQueryScanNodeSerdeTest.java --- .../it/aligned/IoTDBAlignedLastQueryIT.java | 114 ++++++++++++ .../db/it/last/IoTDBLastQueryAlias2IT.java | 60 +++++++ .../db/it/last/IoTDBLastQueryAliasIT.java | 164 ++++++++++++++++++ ...lignedUpdateViewPathLastCacheOperator.java | 25 ++- .../process/last/UpdateLastCacheOperator.java | 2 +- .../last/UpdateViewPathLastCacheOperator.java | 2 +- .../plan/analyze/AnalyzeVisitor.java | 6 +- .../plan/planner/LogicalPlanBuilder.java | 47 ++++- .../plan/planner/OperatorTreeGenerator.java | 23 ++- .../planner/plan/node/PlanGraphPrinter.java | 7 +- .../plan/node/process/last/LastQueryNode.java | 11 +- .../plan/node/source/LastQueryScanNode.java | 99 +++++++---- .../planner/distribution/LastQueryTest.java | 9 +- .../logical/DataQueryLogicalPlannerTest.java | 11 +- .../source/LastQueryScanNodeSerdeTest.java | 2 + 15 files changed, 517 insertions(+), 65 deletions(-) create mode 100644 integration-test/src/test/java/org/apache/iotdb/db/it/last/IoTDBLastQueryAlias2IT.java create mode 100644 integration-test/src/test/java/org/apache/iotdb/db/it/last/IoTDBLastQueryAliasIT.java diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/aligned/IoTDBAlignedLastQueryIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/aligned/IoTDBAlignedLastQueryIT.java index a32572d47788a..214a2c31806f4 100644 --- a/integration-test/src/test/java/org/apache/iotdb/db/it/aligned/IoTDBAlignedLastQueryIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/db/it/aligned/IoTDBAlignedLastQueryIT.java @@ -340,4 +340,118 @@ public void cacheHitTest() { selectSomeAlignedLastWithTimeFilterTest(); selectSomeAlignedAndNonAlignedLastWithTimeFilterTest(); } + + @Test + public void testLastAlias() { + String[] sqls = + new String[] { + "create aligned timeseries root.ln_1.tb_6141(fengjituichu_BOOLEAN BOOLEAN encoding=RLE,`chushuiNH4-N_DOUBLE` DOUBLE encoding=GORILLA,mochanshuizhuangtai_BOOLEAN BOOLEAN encoding=RLE,11_TEXT TEXT encoding=PLAIN,chanshuijianxieyunxingshijianshezhi_DOUBLE DOUBLE encoding=GORILLA,wenben_TEXT TEXT encoding=PLAIN, fengjitouru_BOOLEAN BOOLEAN encoding=RLE,meiju_INT32 INT32 encoding=RLE,chushuiTP_DOUBLE DOUBLE encoding=GORILLA,shuiguanliusu_DOUBLE DOUBLE encoding=GORILLA,CO2_DOUBLE DOUBLE encoding=GORILLA,`kaiguanliang-yunxing_BOOLEAN` BOOLEAN encoding=RLE,gongnengma_DOUBLE DOUBLE encoding=GORILLA);", + "alter timeseries root.ln_1.tb_6141.fengjituichu_BOOLEAN upsert alias=fengjituichu;", + "alter timeseries root.ln_1.tb_6141.shuiguanliusu_DOUBLE upsert alias=shuiguanliusu;", + "alter timeseries root.ln_1.tb_6141.CO2_DOUBLE upsert alias=CO2;", + "alter timeseries root.ln_1.tb_6141.fengjitouru_BOOLEAN upsert alias=fengjitouru;", + "alter timeseries root.ln_1.tb_6141.chanshuijianxieyunxingshijianshezhi_DOUBLE upsert alias=chanshuijianxieyunxingshijianshezhi;", + "alter timeseries root.ln_1.tb_6141.mochanshuizhuangtai_BOOLEAN upsert alias=mochanshuizhuangtai;", + "alter timeseries root.ln_1.tb_6141.meiju_INT32 upsert alias=meiju;", + "alter timeseries root.ln_1.tb_6141.chushuiTP_DOUBLE upsert alias=chushuiTP;", + "alter timeseries root.ln_1.tb_6141.wenben_TEXT upsert alias=wenben;", + "alter timeseries root.ln_1.tb_6141.`chushuiNH4-N_DOUBLE` upsert alias=`chushuiNH4-N`;", + "alter timeseries root.ln_1.tb_6141.gongnengma_DOUBLE upsert alias=gongnengma;", + "alter timeseries root.ln_1.tb_6141.11_TEXT upsert alias=`11`;", + "alter timeseries root.ln_1.tb_6141.`kaiguanliang-yunxing_BOOLEAN` upsert alias=`kaiguanliang-yunxing`;", + "insert into root.ln_1.tb_6141(time,chanshuijianxieyunxingshijianshezhi_DOUBLE) aligned values(1679365910000,10.0);", + "insert into root.ln_1.tb_6141(time,chushuiTP_DOUBLE) aligned values(1679365910000,15.0);", + "insert into root.ln_1.tb_6141(time,gongnengma_DOUBLE) aligned values(1679477545000,2.0);", + "insert into root.ln_1.tb_6141(time,wenben_TEXT) aligned values(1675995566000,52);", + "insert into root.ln_1.tb_6141(time,meiju_INT32) aligned values(1675995566000,2);", + "insert into root.ln_1.tb_6141(time,shuiguanliusu_DOUBLE) aligned values(1679365910000,15.0);", + "insert into root.ln_1.tb_6141(time,mochanshuizhuangtai_BOOLEAN) aligned values(1677033625000,true);", + "insert into root.ln_1.tb_6141(time,fengjitouru_BOOLEAN) aligned values(1675995566000,true);", + "insert into root.ln_1.tb_6141(time,fengjituichu_BOOLEAN) aligned values(1675995566000,false);", + "insert into root.ln_1.tb_6141(time,11_TEXT) aligned values(1679365910000,13);", + "insert into root.ln_1.tb_6141(time,CO2_DOUBLE) aligned values(1679365910000,12.0);", + "insert into root.ln_1.tb_6141(time,`chushuiNH4-N_DOUBLE`) aligned values(1679365910000,12.0);", + "insert into root.ln_1.tb_6141(time,`kaiguanliang-yunxing_BOOLEAN`) aligned values(1675995566000,false);", + }; + + try (Connection connection = EnvFactory.getEnv().getConnection(); + Statement statement = connection.createStatement()) { + + // create aligned and non-aligned time series + for (String sql : sqls) { + statement.addBatch(sql); + } + statement.executeBatch(); + } catch (Exception e) { + e.printStackTrace(); + fail(e.getMessage()); + } + + Set retSet = + new HashSet<>( + Arrays.asList( + "1679477545000,root.ln_1.tb_6141.gongnengma,2.0,DOUBLE", + "1675995566000,root.ln_1.tb_6141.wenben,52,TEXT")); + + try (Connection connection = EnvFactory.getEnv().getConnection(); + Statement statement = connection.createStatement()) { + + try (ResultSet resultSet = + statement.executeQuery( + "select last gongnengma,wenben from root.ln_1.tb_6141 order by timeseries asc;")) { + int cnt = 0; + while (resultSet.next()) { + String ans = + resultSet.getString(TIMESTAMP_STR) + + "," + + resultSet.getString(TIMESERIES_STR) + + "," + + resultSet.getString(VALUE_STR) + + "," + + resultSet.getString(DATA_TYPE_STR); + assertTrue(ans, retSet.contains(ans)); + cnt++; + } + assertEquals(retSet.size(), cnt); + } + + } catch (SQLException e) { + e.printStackTrace(); + fail(e.getMessage()); + } + + retSet = + new HashSet<>( + Arrays.asList( + "1679477545000,root.ln_1.tb_6141.gongnengma,2.0,DOUBLE", + "1677033625000,root.ln_1.tb_6141.mochanshuizhuangtai,true,BOOLEAN", + "1675995566000,root.ln_1.tb_6141.wenben,52,TEXT")); + + try (Connection connection = EnvFactory.getEnv().getConnection(); + Statement statement = connection.createStatement()) { + + try (ResultSet resultSet = + statement.executeQuery( + "select last gongnengma,mochanshuizhuangtai,wenben from root.ln_1.tb_6141 order by timeseries asc;")) { + int cnt = 0; + while (resultSet.next()) { + String ans = + resultSet.getString(TIMESTAMP_STR) + + "," + + resultSet.getString(TIMESERIES_STR) + + "," + + resultSet.getString(VALUE_STR) + + "," + + resultSet.getString(DATA_TYPE_STR); + assertTrue(ans, retSet.contains(ans)); + cnt++; + } + assertEquals(retSet.size(), cnt); + } + + } catch (SQLException e) { + e.printStackTrace(); + fail(e.getMessage()); + } + } } diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/last/IoTDBLastQueryAlias2IT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/last/IoTDBLastQueryAlias2IT.java new file mode 100644 index 0000000000000..6e8f2753fa87a --- /dev/null +++ b/integration-test/src/test/java/org/apache/iotdb/db/it/last/IoTDBLastQueryAlias2IT.java @@ -0,0 +1,60 @@ +/* + * 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.it.last; + +import org.apache.iotdb.it.env.EnvFactory; +import org.apache.iotdb.it.framework.IoTDBTestRunner; +import org.apache.iotdb.itbase.category.ClusterIT; +import org.apache.iotdb.itbase.category.LocalStandaloneIT; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.experimental.categories.Category; +import org.junit.runner.RunWith; + +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; + +import static org.apache.iotdb.db.it.utils.TestUtils.prepareData; +import static org.junit.Assert.fail; + +@RunWith(IoTDBTestRunner.class) +@Category({LocalStandaloneIT.class, ClusterIT.class}) +public class IoTDBLastQueryAlias2IT extends IoTDBLastQueryAliasIT { + @BeforeClass + public static void setUp() throws Exception { + // with lastCache + EnvFactory.getEnv().getConfig().getCommonConfig().setEnableLastCache(true); + EnvFactory.getEnv().initClusterEnvironment(); + try (Connection connection = EnvFactory.getEnv().getConnection(); + Statement statement = connection.createStatement()) { + prepareData(SQLs); + } catch (SQLException e) { + e.printStackTrace(); + fail(e.getMessage()); + } + } + + @AfterClass + public static void tearDown() throws Exception { + EnvFactory.getEnv().cleanClusterEnvironment(); + } +} diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/last/IoTDBLastQueryAliasIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/last/IoTDBLastQueryAliasIT.java new file mode 100644 index 0000000000000..4772804f38480 --- /dev/null +++ b/integration-test/src/test/java/org/apache/iotdb/db/it/last/IoTDBLastQueryAliasIT.java @@ -0,0 +1,164 @@ +/* + * 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.it.last; + +import org.apache.iotdb.it.env.EnvFactory; +import org.apache.iotdb.it.framework.IoTDBTestRunner; +import org.apache.iotdb.itbase.category.ClusterIT; +import org.apache.iotdb.itbase.category.LocalStandaloneIT; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runner.RunWith; + +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; + +import static org.apache.iotdb.db.it.utils.TestUtils.prepareData; +import static org.apache.iotdb.db.it.utils.TestUtils.resultSetEqualTest; +import static org.apache.iotdb.itbase.constant.TestConstant.DATA_TYPE_STR; +import static org.apache.iotdb.itbase.constant.TestConstant.TIMESERIES_STR; +import static org.apache.iotdb.itbase.constant.TestConstant.TIMESTAMP_STR; +import static org.apache.iotdb.itbase.constant.TestConstant.VALUE_STR; +import static org.junit.Assert.fail; + +@RunWith(IoTDBTestRunner.class) +@Category({LocalStandaloneIT.class, ClusterIT.class}) +public class IoTDBLastQueryAliasIT { + protected static final String[] SQLs = + new String[] { + "create timeseries root.test.d1.s1(alias3) with dataType= int32", + "create timeseries root.test.d1.s2(alias2) with dataType= int32", + "create timeseries root.test.d1.s3(alias1) with dataType= int32", + "insert into root.test.d1(timestamp,s1,s2,s3) values(1,1,2,3)", + "create aligned timeseries root.test.d2 (s1 (alias3) int32,s2 (alias2) int32,s3 (alias1) int32)", + "insert into root.test.d2(timestamp,s1,s2,s3) values(2,2,3,4)", + }; + + @BeforeClass + public static void setUp() throws Exception { + // without lastCache + EnvFactory.getEnv().getConfig().getCommonConfig().setEnableLastCache(false); + EnvFactory.getEnv().initClusterEnvironment(); + try (Connection connection = EnvFactory.getEnv().getConnection(); + Statement statement = connection.createStatement()) { + prepareData(SQLs); + } catch (SQLException e) { + e.printStackTrace(); + fail(e.getMessage()); + } + } + + @AfterClass + public static void tearDown() throws Exception { + EnvFactory.getEnv().cleanClusterEnvironment(); + } + + @Test + public void nonAlignedTest() { + String[] expectedHeader = + new String[] {TIMESTAMP_STR, TIMESERIES_STR, VALUE_STR, DATA_TYPE_STR}; + + String[] retArray = + new String[] { + "1,root.test.d1.alias3,1,INT32,", + }; + resultSetEqualTest("select last alias3 from root.test.d1", expectedHeader, retArray); + + retArray = + new String[] { + "1,root.test.d1.alias3,1,INT32,", + "1,root.test.d1.alias2,2,INT32,", + "1,root.test.d1.alias1,3,INT32,", + }; + resultSetEqualTest( + "select last alias3,alias2,alias1 from root.test.d1", expectedHeader, retArray); + resultSetEqualTest( + "select last alias3,alias2,alias1 from root.test.d1", expectedHeader, retArray); + + retArray = + new String[] { + "1,root.test.d1.alias1,3,INT32,", + "1,root.test.d1.alias2,2,INT32,", + "1,root.test.d1.alias3,1,INT32,", + }; + resultSetEqualTest( + "select last alias3,alias2,alias1 from root.test.d1 order by timeseries", + expectedHeader, + retArray); + resultSetEqualTest( + "select last alias3,alias2,alias1 from root.test.d1 order by timeseries", + expectedHeader, + retArray); + } + + @Test + public void alignedTest() { + String[] expectedHeader = + new String[] {TIMESTAMP_STR, TIMESERIES_STR, VALUE_STR, DATA_TYPE_STR}; + String[] retArray = + new String[] { + "2,root.test.d2.alias3,2,INT32,", + "2,root.test.d2.alias2,3,INT32,", + "2,root.test.d2.alias1,4,INT32,", + }; + resultSetEqualTest( + "select last alias3,alias2,alias1 from root.test.d2", expectedHeader, retArray); + resultSetEqualTest( + "select last alias3,alias2,alias1 from root.test.d2", expectedHeader, retArray); + + retArray = + new String[] { + "2,root.test.d2.alias1,4,INT32,", + "2,root.test.d2.alias2,3,INT32,", + "2,root.test.d2.alias3,2,INT32,", + }; + resultSetEqualTest( + "select last alias3,alias2,alias1 from root.test.d2 order by timeseries", + expectedHeader, + retArray); + resultSetEqualTest( + "select last alias3,alias2,alias1 from root.test.d2 order by timeseries", + expectedHeader, + retArray); + } + + @Test + public void mixedTest() { + String[] expectedHeader = + new String[] {TIMESTAMP_STR, TIMESERIES_STR, VALUE_STR, DATA_TYPE_STR}; + String[] retArray = + new String[] { + "1,root.test.d1.alias1,3,INT32,", + "1,root.test.d1.alias2,2,INT32,", + "1,root.test.d1.alias3,1,INT32,", + "2,root.test.d2.alias1,4,INT32,", + "2,root.test.d2.alias2,3,INT32,", + "2,root.test.d2.alias3,2,INT32,", + }; + resultSetEqualTest( + "select last alias3,alias2,alias1 from root.test.* order by timeseries", + expectedHeader, + retArray); + } +} diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/process/last/AlignedUpdateViewPathLastCacheOperator.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/process/last/AlignedUpdateViewPathLastCacheOperator.java index 3fc9f0412bc29..5d5afbedb5bc2 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/process/last/AlignedUpdateViewPathLastCacheOperator.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/process/last/AlignedUpdateViewPathLastCacheOperator.java @@ -28,11 +28,15 @@ import org.apache.tsfile.utils.RamUsageEstimator; import org.apache.tsfile.utils.TsPrimitiveType; +import java.util.List; + import static com.google.common.base.Preconditions.checkArgument; public class AlignedUpdateViewPathLastCacheOperator extends AlignedUpdateLastCacheOperator { - - private final String outputViewPath; + // Now not only a view path will be set here, but also the measurement path with alias will be set + // .e.g last query path: root.test.d1(s1(alias1), s2), outputPaths: [root.test.d1.alias1, null] + private final List outputPaths; + private int outputPathIndex = 0; public AlignedUpdateViewPathLastCacheOperator( OperatorContext operatorContext, @@ -41,7 +45,7 @@ public AlignedUpdateViewPathLastCacheOperator( DataNodeSchemaCache dataNodeSchemaCache, boolean needUpdateCache, boolean needUpdateNullEntry, - String outputViewPath, + List outputPaths, boolean deviceInMultiRegion) { super( operatorContext, @@ -51,19 +55,26 @@ public AlignedUpdateViewPathLastCacheOperator( needUpdateCache, needUpdateNullEntry, deviceInMultiRegion); - checkArgument(seriesPath.getMeasurementList().size() == 1); - this.outputViewPath = outputViewPath; + checkArgument(outputPaths != null, "outputPaths shouldn't be null"); + this.outputPaths = outputPaths; } @Override protected void appendLastValueToTsBlockBuilder( long lastTime, TsPrimitiveType lastValue, MeasurementPath measurementPath, String type) { + String outputPath = outputPaths.get(outputPathIndex); LastQueryUtil.appendLastValue( - tsBlockBuilder, lastTime, outputViewPath, lastValue.getStringValue(), type); + tsBlockBuilder, + lastTime, + outputPath == null ? measurementPath.getFullPath() : outputPath, + lastValue.getStringValue(), + type); + outputPathIndex++; } @Override public long ramBytesUsed() { - return super.ramBytesUsed() + RamUsageEstimator.sizeOf(outputViewPath); + return super.ramBytesUsed() + + outputPaths.stream().mapToLong(path -> RamUsageEstimator.sizeOf(path)).sum(); } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/process/last/UpdateLastCacheOperator.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/process/last/UpdateLastCacheOperator.java index d55f1d9fd4e8e..3e8a92ded26c2 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/process/last/UpdateLastCacheOperator.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/process/last/UpdateLastCacheOperator.java @@ -40,7 +40,7 @@ public class UpdateLastCacheOperator extends AbstractUpdateLastCacheOperator { // fullPath for queried time series // It should be exact PartialPath, neither MeasurementPath nor AlignedPath, because lastCache only // accept PartialPath - private final MeasurementPath fullPath; + protected final MeasurementPath fullPath; // type for queried time series protected final String dataType; diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/process/last/UpdateViewPathLastCacheOperator.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/process/last/UpdateViewPathLastCacheOperator.java index dcc83bddfbd7a..d3ed5b2a7b127 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/process/last/UpdateViewPathLastCacheOperator.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/process/last/UpdateViewPathLastCacheOperator.java @@ -29,7 +29,7 @@ import org.apache.tsfile.utils.TsPrimitiveType; public class UpdateViewPathLastCacheOperator extends UpdateLastCacheOperator { - + // Now not only a view path will be set here, but also the measurement path with alias will be set private final String outputViewPath; public UpdateViewPathLastCacheOperator( 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 e79fe9e3f4063..a28ca79c9567b 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 @@ -657,7 +657,11 @@ private Analysis analyzeLastSourceAndDataPartition( timeseriesOrdering != null ? new TreeMap<>(timeseriesOrdering.getStringComparator()) : new LinkedHashMap<>()) - .put(outputPath.getMeasurement(), timeSeriesOperand); + .put( + outputPath.isMeasurementAliasExists() + ? outputPath.getMeasurementAlias() + : outputPath.getMeasurement(), + timeSeriesOperand); } else { lastQueryNonWritableViewSourceExpressionMap = lastQueryNonWritableViewSourceExpressionMap == null 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 1d206b03ca1f0..81afda469c370 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 @@ -252,10 +252,24 @@ public LogicalPlanBuilder planLast(Analysis analysis, Ordering timeseriesOrderin for (Expression sourceExpression : measurementToExpressionsOfDevice.values()) { MeasurementPath selectedPath = (MeasurementPath) ((TimeSeriesOperand) sourceExpression).getPath(); - String outputViewPath = - sourceExpression.isViewExpression() - ? sourceExpression.getViewPath().getFullPath() - : null; + + String outputPath; + TSDataType outputViewPathType = null; + // the path is view, use the view path as the output path + if (sourceExpression.isViewExpression()) { + outputPath = sourceExpression.getViewPath().getFullPath(); + outputViewPathType = selectedPath.getSeriesType(); + } else { + outputPath = selectedPath.getFullPath(); + } + // the path has alias, use alias as the output path + if (selectedPath.isMeasurementAliasExists()) { + outputPath = + selectedPath + .getDevicePath() + .concatAsMeasurementPath(selectedPath.getMeasurementAlias()) + .toString(); + } PartialPath devicePath = selectedPath.getDevicePath(); // For expression with view path, we do not use the deviceId in Map.Entry because it is a @@ -267,7 +281,8 @@ public LogicalPlanBuilder planLast(Analysis analysis, Ordering timeseriesOrderin devicePath, selectedPath.isUnderAlignedEntity(), Collections.singletonList(selectedPath.getMeasurementSchema()), - outputViewPath); + Collections.singletonList(outputPath), + outputViewPathType != null); this.context.reserveMemoryForFrontEnd(memCost); } } else { @@ -275,12 +290,31 @@ public LogicalPlanBuilder planLast(Analysis analysis, Ordering timeseriesOrderin List measurementSchemas = new ArrayList<>(measurementToExpressionsOfDevice.size()); PartialPath devicePath = null; + List outputPaths = null; + int i = 0; for (Expression sourceExpression : measurementToExpressionsOfDevice.values()) { MeasurementPath selectedPath = (MeasurementPath) ((TimeSeriesOperand) sourceExpression).getPath(); aligned = selectedPath.isUnderAlignedEntity(); devicePath = devicePath == null ? selectedPath.getDevicePath() : devicePath; measurementSchemas.add(selectedPath.getMeasurementSchema()); + + // series has alias and use alias to SELECT + if (selectedPath.isMeasurementAliasExists()) { + if (outputPaths == null) { + // fill null as default value + outputPaths = + new ArrayList<>( + Collections.nCopies(measurementToExpressionsOfDevice.size(), null)); + } + outputPaths.set( + i, + selectedPath + .getDevicePath() + .concatAsMeasurementPath(selectedPath.getMeasurementAlias()) + .toString()); + } + i++; } // DeviceId is needed in the distribution plan stage devicePath.setIDeviceID(deviceId); @@ -290,7 +324,8 @@ public LogicalPlanBuilder planLast(Analysis analysis, Ordering timeseriesOrderin devicePath, aligned, measurementSchemas, - null); + outputPaths, + false); this.context.reserveMemoryForFrontEnd(memCost); } } 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 8aad87866b8f0..e0aeacb7f56b0 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 @@ -2789,7 +2789,7 @@ private UpdateLastCacheOperator createUpdateLastCacheOperator( fullPath); } - return Objects.isNull(node.getOutputViewPath()) + return Objects.isNull(node.getOutputPaths()) ? new UpdateLastCacheOperator( operatorContext, lastQueryScan, @@ -2806,11 +2806,11 @@ private UpdateLastCacheOperator createUpdateLastCacheOperator( DATA_NODE_SCHEMA_CACHE, context.isNeedUpdateLastCache(), context.isNeedUpdateNullEntry(), - node.getOutputViewPath()); + node.getOutputPaths().get(idx)); } private AlignedUpdateLastCacheOperator createAlignedUpdateLastCacheOperator( - final String outputViewPath, + final List outputPaths, final PlanNodeId planNodeId, final AlignedPath unCachedPath, final LocalExecutionPlanContext context, @@ -2846,7 +2846,7 @@ private AlignedUpdateLastCacheOperator createAlignedUpdateLastCacheOperator( } } - return Objects.isNull(outputViewPath) + return Objects.isNull(outputPaths) ? new AlignedUpdateLastCacheOperator( operatorContext, lastQueryScan, @@ -2862,7 +2862,7 @@ private AlignedUpdateLastCacheOperator createAlignedUpdateLastCacheOperator( DATA_NODE_SCHEMA_CACHE, context.isNeedUpdateLastCache(), context.isNeedUpdateNullEntry(), - outputViewPath, + outputPaths, deviceInMultiRegion); } @@ -2964,6 +2964,7 @@ public Operator visitLastQueryScan(LastQueryScanNode node, LocalExecutionPlanCon updateFilterUsingTTL( context.getGlobalTimeFilter(), DataNodeTTLCache.getInstance().getTTL(devicePath.getNodes())); + boolean hasOutputPath = node.getOutputPaths() != null; for (int i = 0; i < idxOfMeasurementSchemas.size(); i++) { IMeasurementSchema measurementSchema = node.getMeasurementSchema(i); final PartialPath measurementPath = @@ -2994,8 +2995,9 @@ public Operator visitLastQueryScan(LastQueryScanNode node, LocalExecutionPlanCon unCachedMeasurementIndexes.add(i); } } else { // cached last value is satisfied, put it into LastCacheScanOperator - if (node.getOutputViewPath() != null) { - context.addCachedLastValue(timeValuePair, node.getOutputViewPath()); + String outputPath = hasOutputPath ? node.getOutputPaths().get(i) : null; + if (outputPath != null) { + context.addCachedLastValue(timeValuePair, node.getOutputPaths().get(i)); } else { context.addCachedLastValue(timeValuePair, measurementPath.getFullPath()); } @@ -3006,12 +3008,17 @@ public Operator visitLastQueryScan(LastQueryScanNode node, LocalExecutionPlanCon } if (node.isAligned()) { AlignedPath unCachedPath = new AlignedPath(node.getDevicePath()); + // select output paths for uncached measurements + List newOutputPaths = hasOutputPath ? new ArrayList<>() : null; for (int i : unCachedMeasurementIndexes) { IMeasurementSchema measurementSchema = node.getMeasurementSchema(i); unCachedPath.addMeasurement(measurementSchema.getMeasurementId(), measurementSchema); + if (hasOutputPath) { + newOutputPaths.add(node.getOutputPaths().get(i)); + } } return createAlignedUpdateLastCacheOperator( - node.getOutputViewPath(), + newOutputPaths, node.getPlanNodeId(), unCachedPath, context, diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanGraphPrinter.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanGraphPrinter.java index b8fefee7201a4..5a03015d7812a 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanGraphPrinter.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanGraphPrinter.java @@ -68,7 +68,6 @@ import org.apache.commons.lang3.Validate; import org.apache.tsfile.utils.Pair; -import org.eclipse.jetty.util.StringUtil; import java.util.ArrayList; import java.util.HashMap; @@ -520,8 +519,10 @@ public List visitLastQueryScan(LastQueryScanNode node, GraphContext cont boxValue.add( String.format( "Series: %s%s", node.getDevicePath().getIDeviceID(), node.getMeasurementSchemas())); - if (StringUtil.isNotBlank(node.getOutputViewPath())) { - boxValue.add(String.format("ViewPath: %s", node.getOutputViewPath())); + + List outputPaths = node.getOutputPaths(); + if (outputPaths != null) { + boxValue.add(String.format("OutputPaths: %s", outputPaths)); } boxValue.add(printRegion(node.getRegionReplicaSet())); return render(node, boxValue, context); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/process/last/LastQueryNode.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/process/last/LastQueryNode.java index 4ce3f29750cc5..32af69eb47613 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/process/last/LastQueryNode.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/process/last/LastQueryNode.java @@ -89,7 +89,8 @@ public long addDeviceLastQueryScanNode( PartialPath devicePath, boolean aligned, List measurementSchemas, - String outputViewPath) { + List outputPaths, + boolean isOutputPathForView) { List idxList = new ArrayList<>(measurementSchemas.size()); for (IMeasurementSchema measurementSchema : measurementSchemas) { int idx = @@ -103,7 +104,13 @@ public long addDeviceLastQueryScanNode( } LastQueryScanNode scanNode = new LastQueryScanNode( - id, devicePath, aligned, idxList, outputViewPath, globalMeasurementSchemaList); + id, + devicePath, + aligned, + idxList, + outputPaths, + isOutputPathForView, + globalMeasurementSchemaList); children.add(scanNode); return scanNode.ramBytesUsed(); } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/source/LastQueryScanNode.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/source/LastQueryScanNode.java index a16aeb779f4a2..1969357a7ac8d 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/source/LastQueryScanNode.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/source/LastQueryScanNode.java @@ -34,7 +34,6 @@ import org.apache.tsfile.utils.RamUsageEstimator; import org.apache.tsfile.utils.ReadWriteIOUtils; import org.apache.tsfile.write.schema.IMeasurementSchema; -import org.eclipse.jetty.util.StringUtil; import java.io.DataOutputStream; import java.io.IOException; @@ -63,7 +62,10 @@ public class LastQueryScanNode extends LastSeriesSourceNode { // It will be set when the current Node is added to the child by the upper LastQueryNode. private List globalMeasurementSchemaList; - private final String outputViewPath; + // Store alias of paths or viewPath in this field. + private final List outputPaths; + // Indicate if there is viewPath stored in outputPaths. + private final boolean isOutputPathForView; // The id of DataRegion where the node will run private TRegionReplicaSet regionReplicaSet; @@ -74,14 +76,16 @@ public LastQueryScanNode( PartialPath devicePath, boolean aligned, List indexOfMeasurementSchemas, - String outputViewPath, + List outputPaths, + boolean isOutputPathForView, List globalMeasurementSchemaList) { super(id, new AtomicInteger(1)); this.aligned = aligned; this.devicePath = devicePath; this.indexOfMeasurementSchemas = indexOfMeasurementSchemas; - this.outputViewPath = outputViewPath; + this.outputPaths = outputPaths; this.globalMeasurementSchemaList = globalMeasurementSchemaList; + this.isOutputPathForView = isOutputPathForView; } public LastQueryScanNode( @@ -90,14 +94,16 @@ public LastQueryScanNode( boolean aligned, List indexOfMeasurementSchemas, AtomicInteger dataNodeSeriesScanNum, - String outputViewPath) { + List outputPaths, + boolean isOutputPathForView) { this( id, devicePath, aligned, indexOfMeasurementSchemas, dataNodeSeriesScanNum, - outputViewPath, + outputPaths, + isOutputPathForView, null); } @@ -107,13 +113,15 @@ public LastQueryScanNode( boolean aligned, List indexOfMeasurementSchemas, AtomicInteger dataNodeSeriesScanNum, - String outputViewPath, + List outputPaths, + boolean isOutputPathForView, List globalMeasurementSchemaList) { super(id, dataNodeSeriesScanNum); this.aligned = aligned; this.devicePath = devicePath; this.indexOfMeasurementSchemas = indexOfMeasurementSchemas; - this.outputViewPath = outputViewPath; + this.outputPaths = outputPaths; + this.isOutputPathForView = isOutputPathForView; this.globalMeasurementSchemaList = globalMeasurementSchemaList; } @@ -123,7 +131,8 @@ public LastQueryScanNode( boolean aligned, List indexOfMeasurementSchemas, AtomicInteger dataNodeSeriesScanNum, - String outputViewPath, + List outputPaths, + boolean isOutputPathForView, TRegionReplicaSet regionReplicaSet, boolean deviceInMultiRegion, List globalMeasurementSchemaList) { @@ -131,7 +140,8 @@ public LastQueryScanNode( this.devicePath = devicePath; this.aligned = aligned; this.indexOfMeasurementSchemas = indexOfMeasurementSchemas; - this.outputViewPath = outputViewPath; + this.outputPaths = outputPaths; + this.isOutputPathForView = isOutputPathForView; this.regionReplicaSet = regionReplicaSet; this.deviceInMultiRegion = deviceInMultiRegion; this.globalMeasurementSchemaList = globalMeasurementSchemaList; @@ -158,14 +168,21 @@ public boolean isAligned() { return this.aligned; } - public String getOutputViewPath() { - return outputViewPath; + public List getOutputPaths() { + return outputPaths; + } + + public boolean isOutputPathForView() { + return isOutputPathForView; } public String getOutputSymbolForSort() { - if (outputViewPath != null) { - return outputViewPath; + if (outputPaths != null && outputPaths.size() == 1) { + return outputPaths.get(0); } + // If outputPaths is null or size > 1, it means there is no view and no alias, just return the + // device name is ok, + // because the measurements have been sorted in AnalyzeVisitor if needed. return devicePath.toString(); } @@ -195,7 +212,8 @@ public PlanNode clone() { aligned, indexOfMeasurementSchemas, getDataNodeSeriesScanNum(), - outputViewPath, + outputPaths, + isOutputPathForView, regionReplicaSet, deviceInMultiRegion, globalMeasurementSchemaList); @@ -225,7 +243,7 @@ public boolean equals(Object o) { return Objects.equals(devicePath, that.devicePath) && Objects.equals(aligned, that.aligned) && Objects.equals(indexOfMeasurementSchemas, that.indexOfMeasurementSchemas) - && Objects.equals(outputViewPath, that.outputViewPath) + && Objects.equals(outputPaths, that.outputPaths) && Objects.equals(regionReplicaSet, that.regionReplicaSet); } @@ -236,20 +254,21 @@ public int hashCode() { devicePath, aligned, indexOfMeasurementSchemas, - outputViewPath, + outputPaths, regionReplicaSet); } @Override public String toString() { - if (StringUtil.isNotBlank(outputViewPath)) { + + if (outputPaths != null) { return String.format( - "LastQueryScanNode-%s:[Device: %s, Aligned: %s, Measurements: %s, ViewPath: %s, DataRegion: %s]", + "LastQueryScanNode-%s:[Device: %s, Aligned: %s, Measurements: %s, OutputPaths: %s, DataRegion: %s]", this.getPlanNodeId(), this.getDevicePath(), this.aligned, this.getMeasurementSchemas(), - this.getOutputViewPath(), + this.getOutputPaths(), PlanNodeUtil.printRegionReplicaSet(getRegionReplicaSet())); } else { return String.format( @@ -272,10 +291,15 @@ protected void serializeAttributes(ByteBuffer byteBuffer) { ReadWriteIOUtils.write(measurementSchema, byteBuffer); } ReadWriteIOUtils.write(getDataNodeSeriesScanNum().get(), byteBuffer); - ReadWriteIOUtils.write(outputViewPath == null, byteBuffer); - if (outputViewPath != null) { - ReadWriteIOUtils.write(outputViewPath, byteBuffer); + ReadWriteIOUtils.write(outputPaths == null, byteBuffer); + if (outputPaths != null) { + int size = outputPaths.size(); + ReadWriteIOUtils.write(size, byteBuffer); + for (int i = 0; i < size; i++) { + ReadWriteIOUtils.write(outputPaths.get(i), byteBuffer); + } } + ReadWriteIOUtils.write(isOutputPathForView, byteBuffer); ReadWriteIOUtils.write(deviceInMultiRegion, byteBuffer); } @@ -289,10 +313,15 @@ protected void serializeAttributes(DataOutputStream stream) throws IOException { ReadWriteIOUtils.write(measurementSchema, stream); } ReadWriteIOUtils.write(getDataNodeSeriesScanNum().get(), stream); - ReadWriteIOUtils.write(outputViewPath == null, stream); - if (outputViewPath != null) { - ReadWriteIOUtils.write(outputViewPath, stream); + ReadWriteIOUtils.write(outputPaths == null, stream); + if (outputPaths != null) { + int size = outputPaths.size(); + ReadWriteIOUtils.write(size, stream); + for (int i = 0; i < size; i++) { + ReadWriteIOUtils.write(outputPaths.get(i), stream); + } } + ReadWriteIOUtils.write(isOutputPathForView, stream); ReadWriteIOUtils.write(deviceInMultiRegion, stream); } @@ -307,7 +336,16 @@ public static LastQueryScanNode deserialize(ByteBuffer byteBuffer) { int dataNodeSeriesScanNum = ReadWriteIOUtils.readInt(byteBuffer); boolean isNull = ReadWriteIOUtils.readBool(byteBuffer); - String outputPathSymbol = isNull ? null : ReadWriteIOUtils.readString(byteBuffer); + List outputPaths = null; + if (!isNull) { + int size = ReadWriteIOUtils.readInt(byteBuffer); + outputPaths = new ArrayList<>(size); + while (size > 0) { + outputPaths.add(ReadWriteIOUtils.readString(byteBuffer)); + size--; + } + } + boolean isOutputPathForView = ReadWriteIOUtils.readBool(byteBuffer); boolean deviceInMultiRegion = ReadWriteIOUtils.readBool(byteBuffer); PlanNodeId planNodeId = PlanNodeId.deserialize(byteBuffer); return new LastQueryScanNode( @@ -316,7 +354,8 @@ public static LastQueryScanNode deserialize(ByteBuffer byteBuffer) { aligned, measurementSchemas, new AtomicInteger(dataNodeSeriesScanNum), - outputPathSymbol, + outputPaths, + isOutputPathForView, null, deviceInMultiRegion, null); @@ -369,6 +408,8 @@ public long ramBytesUsed() { // The memory of each String has been calculated before + MemoryEstimationHelper.getEstimatedSizeOfCopiedPartialPath(devicePath) + MemoryEstimationHelper.getEstimatedSizeOfIntegerArrayList(indexOfMeasurementSchemas) - + RamUsageEstimator.sizeOf(outputViewPath); + + (outputPaths == null + ? 0L + : outputPaths.stream().mapToLong(path -> RamUsageEstimator.sizeOf(path)).sum()); } } diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/distribution/LastQueryTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/distribution/LastQueryTest.java index 2a30129bbd578..930ba4bcc7d20 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/distribution/LastQueryTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/distribution/LastQueryTest.java @@ -59,13 +59,15 @@ public void testSortLastQueryScanNode() throws IllegalPathException { new MeasurementSchema("s3", TSDataType.INT32), new MeasurementSchema("s1", TSDataType.BOOLEAN), new MeasurementSchema("s2", TSDataType.INT32)), - null); + null, + false); lastQueryNode.addDeviceLastQueryScanNode( new PlanNodeId("test_last_query_scan2"), new PartialPath("root.test.d0"), false, Collections.singletonList(new MeasurementSchema("s0", TSDataType.BOOLEAN)), - null); + null, + false); Analysis analysis = Util.constructAnalysis(); SourceRewriter sourceRewriter = new SourceRewriter(analysis); @@ -255,7 +257,8 @@ private LogicalQueryPlan constructLastQuery(List paths, MPPQueryContext devicePath, selectPath.isUnderAlignedEntity(), Collections.singletonList(selectPath.getMeasurementSchema()), - null); + null, + false); } return new LogicalQueryPlan(context, root); diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/logical/DataQueryLogicalPlannerTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/logical/DataQueryLogicalPlannerTest.java index 2e51898a1f4bf..3ca25ab5ff86e 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/logical/DataQueryLogicalPlannerTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/logical/DataQueryLogicalPlannerTest.java @@ -88,7 +88,8 @@ public void testLastQuery() { d1s1Path.getDevicePath(), d1s1Path.isUnderAlignedEntity(), measurementSchemas, - null); + null, + false); measurementSchemas = Arrays.asList( @@ -101,11 +102,12 @@ public void testLastQuery() { d2s1Path.getDevicePath(), d2s1Path.isUnderAlignedEntity(), measurementSchemas, - null); + null, + false); AlignedPath aPath = (AlignedPath) schemaMap.get("root.sg.d2.a"); lastQueryNode.addDeviceLastQueryScanNode( - queryId.genPlanNodeId(), aPath.getDevicePath(), true, aPath.getSchemaList(), null); + queryId.genPlanNodeId(), aPath.getDevicePath(), true, aPath.getSchemaList(), null, false); PlanNode actualPlan = parseSQLToPlanNode(sql); Assert.assertEquals(actualPlan, lastQueryNode); @@ -131,7 +133,8 @@ public void testLastQuerySortWithLimit() { s3Path.getDevicePath(), s3Path.isUnderAlignedEntity(), measurementSchemas, - null); + null, + false); SortNode sortNode = new SortNode( diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/node/source/LastQueryScanNodeSerdeTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/node/source/LastQueryScanNodeSerdeTest.java index 270411f3f51d8..3a0d8952e2d04 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/node/source/LastQueryScanNodeSerdeTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/node/source/LastQueryScanNodeSerdeTest.java @@ -44,6 +44,7 @@ public void test() throws IllegalPathException { true, Arrays.asList(0, 1), null, + false, Arrays.asList( new MeasurementSchema("s1", TSDataType.INT32), new MeasurementSchema("s0", TSDataType.BOOLEAN))); @@ -59,6 +60,7 @@ public void test() throws IllegalPathException { false, Arrays.asList(0, 1), null, + false, Arrays.asList( new MeasurementSchema("s1", TSDataType.INT32), new MeasurementSchema("s0", TSDataType.BOOLEAN)));