This is an automated email from the ASF dual-hosted git repository. Wei-hao-Li pushed a commit to branch fix-date in repository https://gitbox.apache.org/repos/asf/iotdb.git
commit aedc429243b0217cadd65a1557b83207a2328f3f Author: Weihao Li <[email protected]> AuthorDate: Wed May 20 10:00:01 2026 +0800 fix Signed-off-by: Weihao Li <[email protected]> --- .../recent/IoTDBPruneFillGroupPreviousFlatIT.java | 125 +++++++++++++++++++++ .../planner/iterative/rule/PruneFillColumns.java | 19 +++- 2 files changed, 143 insertions(+), 1 deletion(-) diff --git a/integration-test/src/test/java/org/apache/iotdb/relational/it/query/recent/IoTDBPruneFillGroupPreviousFlatIT.java b/integration-test/src/test/java/org/apache/iotdb/relational/it/query/recent/IoTDBPruneFillGroupPreviousFlatIT.java new file mode 100644 index 00000000000..dd419f5c3de --- /dev/null +++ b/integration-test/src/test/java/org/apache/iotdb/relational/it/query/recent/IoTDBPruneFillGroupPreviousFlatIT.java @@ -0,0 +1,125 @@ +/* + * 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.relational.it.query.recent; + +import org.apache.iotdb.it.env.EnvFactory; +import org.apache.iotdb.it.framework.IoTDBTestRunner; +import org.apache.iotdb.itbase.category.TableClusterIT; +import org.apache.iotdb.itbase.category.TableLocalStandaloneIT; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runner.RunWith; + +import static org.apache.iotdb.db.it.utils.TestUtils.prepareTableData; +import static org.apache.iotdb.db.it.utils.TestUtils.tableResultSetEqualTest; + +@RunWith(IoTDBTestRunner.class) +@Category({TableLocalStandaloneIT.class, TableClusterIT.class}) +public class IoTDBPruneFillGroupPreviousFlatIT { + + private static final String DATABASE_NAME = "test"; + + private static final String[] createSqls = + new String[] { + "CREATE DATABASE " + DATABASE_NAME, + "USE " + DATABASE_NAME, + "CREATE TABLE m1(device_id STRING TAG, s1 INT64 FIELD)", + "INSERT INTO m1(time, device_id, s1) values(2024-09-24T06:15:46.565+00:00, 'd1', 2)", + "INSERT INTO m1(time, device_id, s1) values(2024-09-24T07:16:15.297+00:00, 'd1', 10)", + "INSERT INTO m1(time, device_id, s1) values(2024-09-24T08:16:21.907+00:00, 'd2', 20)", + }; + + private static final String FLAT_PREVIOUS_FILL_SQL = + "SELECT date_bin_gapfill(1h, time) AS h, device_id, avg(s1) AS v " + + "FROM m1 " + + "WHERE time >= 2024-09-24T04:00:00.000+00:00 AND time < 2024-09-24T12:00:00.00+00:00 " + + "GROUP BY 1, 2 " + + "FILL METHOD PREVIOUS TIME_COLUMN 1 FILL_GROUP 2 " + + "ORDER BY 1, 2"; + + private static final String NESTED_OMIT_DEVICE_SQL = + "SELECT h AS tm, sum(v) AS sv " + + "FROM ( " + + " SELECT date_bin_gapfill(1h, time) AS h, device_id, avg(s1) AS v " + + " FROM m1 " + + " WHERE time >= 2024-09-24T04:00:00.000+00:00 AND time < 2024-09-24T12:00:00.00+00:00 " + + " GROUP BY 1, 2 " + + " FILL METHOD PREVIOUS TIME_COLUMN 1 FILL_GROUP 2 " + + ") t " + + "GROUP BY h ORDER BY h"; + + @BeforeClass + public static void setUp() { + EnvFactory.getEnv().getConfig().getCommonConfig().setSortBufferSize(128 * 1024); + EnvFactory.getEnv().getConfig().getCommonConfig().setEnableCrossSpaceCompaction(false); + EnvFactory.getEnv().initClusterEnvironment(); + prepareTableData(createSqls); + } + + @AfterClass + public static void tearDown() { + EnvFactory.getEnv().cleanClusterEnvironment(); + } + + @Test + public void flatPreviousFill() { + String[] header = new String[] {"h", "device_id", "v"}; + String[] rows = + new String[] { + "2024-09-24T04:00:00.000Z,d1,null,", + "2024-09-24T04:00:00.000Z,d2,null,", + "2024-09-24T05:00:00.000Z,d1,null,", + "2024-09-24T05:00:00.000Z,d2,null,", + "2024-09-24T06:00:00.000Z,d1,2.0,", + "2024-09-24T06:00:00.000Z,d2,null,", + "2024-09-24T07:00:00.000Z,d1,10.0,", + "2024-09-24T07:00:00.000Z,d2,null,", + "2024-09-24T08:00:00.000Z,d1,10.0,", + "2024-09-24T08:00:00.000Z,d2,20.0,", + "2024-09-24T09:00:00.000Z,d1,10.0,", + "2024-09-24T09:00:00.000Z,d2,20.0,", + "2024-09-24T10:00:00.000Z,d1,10.0,", + "2024-09-24T10:00:00.000Z,d2,20.0,", + "2024-09-24T11:00:00.000Z,d1,10.0,", + "2024-09-24T11:00:00.000Z,d2,20.0,", + }; + tableResultSetEqualTest(FLAT_PREVIOUS_FILL_SQL, header, rows, DATABASE_NAME); + } + + @Test + public void nestedOmitTag() { + String[] header = new String[] {"tm", "sv"}; + String[] rows = + new String[] { + "2024-09-24T04:00:00.000Z,null,", + "2024-09-24T05:00:00.000Z,null,", + "2024-09-24T06:00:00.000Z,2.0,", + "2024-09-24T07:00:00.000Z,10.0,", + "2024-09-24T08:00:00.000Z,30.0,", + "2024-09-24T09:00:00.000Z,30.0,", + "2024-09-24T10:00:00.000Z,30.0,", + "2024-09-24T11:00:00.000Z,30.0,", + }; + tableResultSetEqualTest(NESTED_OMIT_DEVICE_SQL, header, rows, DATABASE_NAME); + } +} diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/iterative/rule/PruneFillColumns.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/iterative/rule/PruneFillColumns.java index 7c82fcdeaab..d93953c695b 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/iterative/rule/PruneFillColumns.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/iterative/rule/PruneFillColumns.java @@ -22,6 +22,10 @@ package org.apache.iotdb.db.queryengine.plan.relational.planner.iterative.rule; import org.apache.iotdb.commons.queryengine.plan.planner.plan.node.PlanNode; import org.apache.iotdb.commons.queryengine.plan.relational.planner.Symbol; import org.apache.iotdb.commons.queryengine.plan.relational.planner.node.FillNode; +import org.apache.iotdb.commons.queryengine.plan.relational.planner.node.LinearFillNode; +import org.apache.iotdb.commons.queryengine.plan.relational.planner.node.PreviousFillNode; + +import com.google.common.collect.ImmutableSet; import java.util.Optional; import java.util.Set; @@ -38,6 +42,19 @@ public class PruneFillColumns extends ProjectOffPushDownRule<FillNode> { @Override protected Optional<PlanNode> pushDownProjectOff( Context context, FillNode fillNode, Set<Symbol> referencedOutputs) { - return restrictChildOutputs(context.getIdAllocator(), fillNode, referencedOutputs); + // Like PruneGapFillColumns: TIME_COLUMN / helper and FILL_GROUP symbols must remain in the + // child's output even if no outer consumer references them (e.g. nested subquery pruning). + ImmutableSet.Builder<Symbol> referencedInputs = ImmutableSet.builder(); + referencedInputs.addAll(referencedOutputs); + if (fillNode instanceof PreviousFillNode) { + PreviousFillNode previousFillNode = (PreviousFillNode) fillNode; + previousFillNode.getHelperColumn().ifPresent(referencedInputs::add); + previousFillNode.getGroupingKeys().ifPresent(keys -> referencedInputs.addAll(keys)); + } else if (fillNode instanceof LinearFillNode) { + LinearFillNode linearFillNode = (LinearFillNode) fillNode; + referencedInputs.add(linearFillNode.getHelperColumn()); + linearFillNode.getGroupingKeys().ifPresent(keys -> referencedInputs.addAll(keys)); + } + return restrictChildOutputs(context.getIdAllocator(), fillNode, referencedInputs.build()); } }
