This is an automated email from the ASF dual-hosted git repository.

jackietien pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iotdb.git


The following commit(s) were added to refs/heads/master by this push:
     new 34795100682 Add ScalarArgumentChecker and auto-built pass through 
index for TVF
34795100682 is described below

commit 34795100682c05d36492e17775143afab1b7e715
Author: Chen YZ <[email protected]>
AuthorDate: Wed Apr 23 15:44:33 2025 +0800

    Add ScalarArgumentChecker and auto-built pass through index for TVF
---
 .../org/apache/iotdb/udf/table/RepeatExample.java  |  4 +-
 .../udf/example/relational/MySelectColumn.java     | 69 ++++++++--------------
 .../relational/it/db/it/IoTDBWindowTVFIT.java      | 23 +++++++-
 .../db/it/udf/IoTDBUserDefinedTableFunctionIT.java | 16 +++++
 .../table/argument/ScalarArgumentChecker.java      | 32 ++++++++++
 .../processor/TableFunctionDataProcessor.java      | 12 ++--
 .../ScalarParameterSpecification.java              | 23 +++++++-
 .../process/function/TableFunctionOperator.java    | 18 +++++-
 .../plan/planner/TableOperatorGenerator.java       |  3 +
 .../relational/analyzer/StatementAnalyzer.java     |  8 +++
 .../iotdb/db/queryengine/plan/function/Repeat.java |  4 +-
 .../relational/tvf/CapacityTableFunction.java      |  5 +-
 .../relational/tvf/CumulateTableFunction.java      | 13 +++-
 .../builtin/relational/tvf/HOPTableFunction.java   | 13 +++-
 .../relational/tvf/SessionTableFunction.java       |  5 +-
 .../relational/tvf/TumbleTableFunction.java        |  7 ++-
 .../relational/tvf/VariationTableFunction.java     |  5 +-
 17 files changed, 191 insertions(+), 69 deletions(-)

diff --git 
a/example/udf/src/main/java/org/apache/iotdb/udf/table/RepeatExample.java 
b/example/udf/src/main/java/org/apache/iotdb/udf/table/RepeatExample.java
index bfae7bcd383..51918dd12b7 100644
--- a/example/udf/src/main/java/org/apache/iotdb/udf/table/RepeatExample.java
+++ b/example/udf/src/main/java/org/apache/iotdb/udf/table/RepeatExample.java
@@ -110,10 +110,10 @@ public class RepeatExample implements TableFunction {
 
           @Override
           public void finish(
-              List<ColumnBuilder> columnBuilders, ColumnBuilder 
passThroughIndexBuilder) {
+              List<ColumnBuilder> properColumnBuilders, ColumnBuilder 
passThroughIndexBuilder) {
             for (int i = 1; i < n; i++) {
               for (int j = 0; j < recordIndex; j++) {
-                columnBuilders.get(0).writeInt(i);
+                properColumnBuilders.get(0).writeInt(i);
                 passThroughIndexBuilder.writeLong(j);
               }
             }
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/function/Repeat.java
 
b/integration-test/src/main/java/org/apache/iotdb/db/query/udf/example/relational/MySelectColumn.java
similarity index 54%
copy from 
iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/function/Repeat.java
copy to 
integration-test/src/main/java/org/apache/iotdb/db/query/udf/example/relational/MySelectColumn.java
index 0682fd83d53..27409032702 100644
--- 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/function/Repeat.java
+++ 
b/integration-test/src/main/java/org/apache/iotdb/db/query/udf/example/relational/MySelectColumn.java
@@ -17,86 +17,69 @@
  * under the License.
  */
 
-package org.apache.iotdb.db.queryengine.plan.function;
+package org.apache.iotdb.db.query.udf.example.relational;
 
-import org.apache.iotdb.udf.api.exception.UDFArgumentNotValidException;
 import org.apache.iotdb.udf.api.exception.UDFException;
 import org.apache.iotdb.udf.api.relational.TableFunction;
-import org.apache.iotdb.udf.api.relational.access.Record;
 import org.apache.iotdb.udf.api.relational.table.TableFunctionAnalysis;
 import 
org.apache.iotdb.udf.api.relational.table.TableFunctionProcessorProvider;
 import org.apache.iotdb.udf.api.relational.table.argument.Argument;
 import org.apache.iotdb.udf.api.relational.table.argument.DescribedSchema;
 import org.apache.iotdb.udf.api.relational.table.argument.ScalarArgument;
+import org.apache.iotdb.udf.api.relational.table.argument.TableArgument;
 import 
org.apache.iotdb.udf.api.relational.table.processor.TableFunctionDataProcessor;
 import 
org.apache.iotdb.udf.api.relational.table.specification.ParameterSpecification;
 import 
org.apache.iotdb.udf.api.relational.table.specification.ScalarParameterSpecification;
 import 
org.apache.iotdb.udf.api.relational.table.specification.TableParameterSpecification;
 import org.apache.iotdb.udf.api.type.Type;
 
-import org.apache.tsfile.block.column.ColumnBuilder;
-
+import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 
-public class Repeat implements TableFunction {
+public class MySelectColumn implements TableFunction {
   private final String TBL_PARAM = "DATA";
-  private final String N_PARAM = "N";
+  private final String COL_PARAM = "SELECT";
 
   @Override
   public List<ParameterSpecification> getArgumentsSpecifications() {
     return Arrays.asList(
-        
TableParameterSpecification.builder().name(TBL_PARAM).passThroughColumns().build(),
-        
ScalarParameterSpecification.builder().name(N_PARAM).type(Type.INT32).build());
+        TableParameterSpecification.builder().name(TBL_PARAM).build(),
+        
ScalarParameterSpecification.builder().name(COL_PARAM).type(Type.STRING).build());
   }
 
   @Override
   public TableFunctionAnalysis analyze(Map<String, Argument> arguments) throws 
UDFException {
-
-    ScalarArgument count = (ScalarArgument) arguments.get("N");
-    if (count == null) {
-      throw new UDFArgumentNotValidException("count argument for function 
repeat() is missing");
-    } else if ((int) count.getValue() <= 0) {
-      throw new UDFArgumentNotValidException(
-          "count argument for function repeat() must be positive");
+    TableArgument tableArgument = (TableArgument) arguments.get(TBL_PARAM);
+    String selectColumn = (String) ((ScalarArgument) 
arguments.get(COL_PARAM)).getValue();
+    List<Integer> requiredColumns = new ArrayList<>();
+    DescribedSchema.Builder schemaBuilder = DescribedSchema.builder();
+    for (int i = 0; i < tableArgument.getFieldNames().size(); i++) {
+      Optional<String> fieldName = tableArgument.getFieldNames().get(i);
+      if (fieldName.isPresent() && 
fieldName.get().equalsIgnoreCase(selectColumn)) {
+        requiredColumns.add(i);
+        schemaBuilder.addField(fieldName, 
tableArgument.getFieldTypes().get(i));
+      }
     }
     return TableFunctionAnalysis.builder()
-        .properColumnSchema(DescribedSchema.builder().addField("repeat_index", 
Type.INT32).build())
-        .requiredColumns(
-            TBL_PARAM,
-            Collections.singletonList(0)) // per spec, function must require 
at least one column
+        .properColumnSchema(schemaBuilder.build())
+        .requiredColumns(TBL_PARAM, requiredColumns)
         .build();
   }
 
   @Override
   public TableFunctionProcessorProvider getProcessorProvider(Map<String, 
Argument> arguments) {
-    ScalarArgument count = (ScalarArgument) arguments.get("N");
     return new TableFunctionProcessorProvider() {
       @Override
       public TableFunctionDataProcessor getDataProcessor() {
-        return new TableFunctionDataProcessor() {
-          private final int n = (int) count.getValue();
-          private long recordIndex = 0;
-
-          @Override
-          public void process(
-              Record input,
-              List<ColumnBuilder> properColumnBuilders,
-              ColumnBuilder passThroughIndexBuilder) {
-            properColumnBuilders.get(0).writeInt(0);
-            passThroughIndexBuilder.writeLong(recordIndex++);
-          }
-
-          @Override
-          public void finish(
-              List<ColumnBuilder> columnBuilders, ColumnBuilder 
passThroughIndexBuilder) {
-            for (int i = 1; i < n; i++) {
-              for (int j = 0; j < recordIndex; j++) {
-                columnBuilders.get(0).writeInt(i);
-                passThroughIndexBuilder.writeLong(j);
-              }
+        return (input, properColumnBuilders, passThroughIndexBuilder) -> {
+          for (int i = 0; i < input.size(); i++) {
+            if (input.isNull(i)) {
+              properColumnBuilders.get(i).appendNull();
+            } else {
+              properColumnBuilders.get(i).writeObject(input.getObject(i));
             }
           }
         };
diff --git 
a/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBWindowTVFIT.java
 
b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBWindowTVFIT.java
index 68cd390f094..c947722f26d 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBWindowTVFIT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBWindowTVFIT.java
@@ -130,6 +130,14 @@ public class IoTDBWindowTVFIT {
         expectedHeader,
         retArray,
         DATABASE_NAME);
+    tableAssertTestFail(
+        "SELECT * FROM HOP(DATA => bid, TIMECOL => 'time', SLIDE => -300000, 
SIZE => 600000) ORDER BY stock_id, time",
+        "Invalid scalar argument SLIDE, should be a positive value",
+        DATABASE_NAME);
+    tableAssertTestFail(
+        "SELECT * FROM HOP(DATA => bid, TIMECOL => 'time', SLIDE => 300000, 
SIZE => -600000) ORDER BY stock_id, time",
+        "Invalid scalar argument SIZE, should be a positive value",
+        DATABASE_NAME);
   }
 
   @Test
@@ -274,6 +282,10 @@ public class IoTDBWindowTVFIT {
         expectedHeader,
         retArray,
         DATABASE_NAME);
+    tableAssertTestFail(
+        "SELECT * FROM TUMBLE(DATA => bid, TIMECOL => 'time', SIZE => 0m) 
ORDER BY stock_id, time",
+        "Invalid scalar argument SIZE, should be a positive value",
+        DATABASE_NAME);
   }
 
   @Test
@@ -325,10 +337,17 @@ public class IoTDBWindowTVFIT {
         DATABASE_NAME);
 
     // test UDFException
-    String errMsg = "Cumulative table function requires size must be an 
integral multiple of step.";
     tableAssertTestFail(
         "SELECT window_start, window_end, stock_id, sum(price) as sum FROM 
CUMULATE(DATA => bid, TIMECOL => 'time', STEP => 4m, SIZE => 10m) GROUP BY 
window_start, window_end, stock_id ORDER BY stock_id, window_start",
-        errMsg,
+        "Cumulative table function requires size must be an integral multiple 
of step.",
+        DATABASE_NAME);
+    tableAssertTestFail(
+        "SELECT * FROM CUMULATE(DATA => bid, TIMECOL => 'time', STEP => 0m, 
SIZE => 5m) ORDER BY stock_id, time",
+        "Invalid scalar argument STEP, should be a positive value",
+        DATABASE_NAME);
+    tableAssertTestFail(
+        "SELECT * FROM CUMULATE(DATA => bid, TIMECOL => 'time', STEP => 1m, 
SIZE => 0m) ORDER BY stock_id, time",
+        "Invalid scalar argument SIZE, should be a positive value",
         DATABASE_NAME);
   }
 }
diff --git 
a/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/udf/IoTDBUserDefinedTableFunctionIT.java
 
b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/udf/IoTDBUserDefinedTableFunctionIT.java
index 26f229c082f..7fe6648fe70 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/udf/IoTDBUserDefinedTableFunctionIT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/udf/IoTDBUserDefinedTableFunctionIT.java
@@ -242,6 +242,22 @@ public class IoTDBUserDefinedTableFunctionIT {
         DATABASE_NAME);
   }
 
+  @Test
+  public void testPassThroughPartitionColumn() {
+    SQLFunctionUtils.createUDF(
+        "MY_SELECT", 
"org.apache.iotdb.db.query.udf.example.relational.MySelectColumn");
+    String[] expectedHeader = new String[] {"s1", "device_id"};
+    String[] retArray =
+        new String[] {
+          "1,d0,", "null,d0,", "3,d0,", "4,d1,",
+        };
+    tableResultSetEqualTest(
+        "select * from MY_SELECT(vehicle PARTITION BY device_id, 's1') ORDER 
BY device_id",
+        expectedHeader,
+        retArray,
+        DATABASE_NAME);
+  }
+
   @Test
   public void testIllegalInput() {
     SQLFunctionUtils.createUDF(
diff --git 
a/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/relational/table/argument/ScalarArgumentChecker.java
 
b/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/relational/table/argument/ScalarArgumentChecker.java
new file mode 100644
index 00000000000..241ce5939bc
--- /dev/null
+++ 
b/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/relational/table/argument/ScalarArgumentChecker.java
@@ -0,0 +1,32 @@
+/*
+ * 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.udf.api.relational.table.argument;
+
+import java.util.function.Function;
+
+public class ScalarArgumentChecker {
+  public static Function<Object, String> POSITIVE_LONG_CHECKER =
+      (value) -> {
+        if (value instanceof Long && (Long) value > 0) {
+          return null;
+        }
+        return "should be a positive value";
+      };
+}
diff --git 
a/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/relational/table/processor/TableFunctionDataProcessor.java
 
b/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/relational/table/processor/TableFunctionDataProcessor.java
index c3cd5483b64..aa78e50f4d8 100644
--- 
a/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/relational/table/processor/TableFunctionDataProcessor.java
+++ 
b/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/relational/table/processor/TableFunctionDataProcessor.java
@@ -43,7 +43,8 @@ public interface TableFunctionDataProcessor {
    * @param properColumnBuilders A list of {@link ColumnBuilder} for each 
column in the output
    *     table.
    * @param passThroughIndexBuilder A {@link ColumnBuilder} for pass through 
columns. Index is
-   *     started from 0 of the whole partition.
+   *     started from 0 of the whole partition. It will be null if table 
argument is not declared
+   *     with PASS_THROUGH_COLUMNS.
    */
   void process(
       Record input,
@@ -54,11 +55,14 @@ public interface TableFunctionDataProcessor {
    * This method is called after all data is processed. It is used to finalize 
the output table and
    * close resource. All remaining data should be written to the 
columnBuilders.
    *
-   * @param columnBuilders A list of {@link ColumnBuilder} for each column in 
the output table.
+   * @param properColumnBuilders A list of {@link ColumnBuilder} for each 
column in the output
+   *     table.
    * @param passThroughIndexBuilder A {@link ColumnBuilder} for pass through 
columns. Index is
-   *     started from 0 of the whole partition.
+   *     started from 0 of the whole partition. It will be null if table 
argument is not declared
+   *     with PASS_THROUGH_COLUMNS.
    */
-  default void finish(List<ColumnBuilder> columnBuilders, ColumnBuilder 
passThroughIndexBuilder) {
+  default void finish(
+      List<ColumnBuilder> properColumnBuilders, ColumnBuilder 
passThroughIndexBuilder) {
     // do nothing
   }
 }
diff --git 
a/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/relational/table/specification/ScalarParameterSpecification.java
 
b/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/relational/table/specification/ScalarParameterSpecification.java
index 496d923b079..7333bd32601 100644
--- 
a/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/relational/table/specification/ScalarParameterSpecification.java
+++ 
b/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/relational/table/specification/ScalarParameterSpecification.java
@@ -21,13 +21,21 @@ package 
org.apache.iotdb.udf.api.relational.table.specification;
 
 import org.apache.iotdb.udf.api.type.Type;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Optional;
+import java.util.function.Function;
 
 public class ScalarParameterSpecification extends ParameterSpecification {
   private final Type type;
+  private final List<Function<Object, String>> checkers;
 
   private ScalarParameterSpecification(
-      String name, Type type, boolean required, Object defaultValue) {
+      String name,
+      Type type,
+      boolean required,
+      Object defaultValue,
+      List<Function<Object, String>> checkers) {
     super(name, required, Optional.ofNullable(defaultValue));
     this.type = type;
     if (defaultValue != null && !type.checkObjectType(defaultValue)) {
@@ -35,12 +43,17 @@ public class ScalarParameterSpecification extends 
ParameterSpecification {
           String.format(
               "default value %s does not match the declared type: %s", 
defaultValue, type));
     }
+    this.checkers = checkers;
   }
 
   public Type getType() {
     return type;
   }
 
+  public List<Function<Object, String>> getCheckers() {
+    return checkers;
+  }
+
   public static Builder builder() {
     return new Builder();
   }
@@ -50,6 +63,7 @@ public class ScalarParameterSpecification extends 
ParameterSpecification {
     private Type type;
     private boolean required = true;
     private Object defaultValue;
+    private List<Function<Object, String>> checkers = new ArrayList<>();
 
     private Builder() {}
 
@@ -63,6 +77,11 @@ public class ScalarParameterSpecification extends 
ParameterSpecification {
       return this;
     }
 
+    public Builder addChecker(Function<Object, String> checker) {
+      this.checkers.add(checker);
+      return this;
+    }
+
     public Builder defaultValue(Object defaultValue) {
       this.required = false;
       this.defaultValue = defaultValue;
@@ -70,7 +89,7 @@ public class ScalarParameterSpecification extends 
ParameterSpecification {
     }
 
     public ScalarParameterSpecification build() {
-      return new ScalarParameterSpecification(name, type, required, 
defaultValue);
+      return new ScalarParameterSpecification(name, type, required, 
defaultValue, checkers);
     }
   }
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/process/function/TableFunctionOperator.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/process/function/TableFunctionOperator.java
index a0a2073f7cf..4e9f7e436a5 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/process/function/TableFunctionOperator.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/process/function/TableFunctionOperator.java
@@ -38,6 +38,7 @@ import org.apache.tsfile.common.conf.TSFileDescriptor;
 import org.apache.tsfile.enums.TSDataType;
 import org.apache.tsfile.read.common.block.TsBlock;
 import org.apache.tsfile.read.common.block.TsBlockBuilder;
+import org.apache.tsfile.read.common.block.column.LongColumn;
 import org.apache.tsfile.read.common.block.column.LongColumnBuilder;
 import org.apache.tsfile.read.common.block.column.RunLengthEncodedColumn;
 import org.apache.tsfile.utils.RamUsageEstimator;
@@ -48,6 +49,7 @@ import java.util.Collections;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Optional;
 import java.util.Queue;
 
 import static 
org.apache.iotdb.db.queryengine.execution.operator.source.relational.TableScanOperator.TIME_COLUMN_TEMPLATE;
@@ -70,6 +72,7 @@ public class TableFunctionOperator implements ProcessOperator 
{
   private final boolean needPassThrough;
   private final PartitionCache partitionCache;
   private final boolean requireRecordSnapshot;
+  private final boolean isDeclaredAsPassThrough;
 
   private TableFunctionDataProcessor processor;
   private PartitionState partitionState;
@@ -87,6 +90,7 @@ public class TableFunctionOperator implements ProcessOperator 
{
       int properChannelCount,
       List<Integer> requiredChannels,
       List<Integer> passThroughChannels,
+      boolean isDeclaredAsPassThrough,
       List<Integer> partitionChannels,
       boolean requireRecordSnapshot) {
     this.operatorContext = operatorContext;
@@ -96,6 +100,7 @@ public class TableFunctionOperator implements 
ProcessOperator {
     this.partitionRecognizer =
         new PartitionRecognizer(
             partitionChannels, requiredChannels, passThroughChannels, 
inputDataTypes);
+    this.isDeclaredAsPassThrough = isDeclaredAsPassThrough;
     this.needPassThrough = properChannelCount != outputDataTypes.size();
     this.partitionState = null;
     this.properBlockBuilder = new TsBlockBuilder(outputDataTypes.subList(0, 
properChannelCount));
@@ -192,7 +197,7 @@ public class TableFunctionOperator implements 
ProcessOperator {
   }
 
   private ColumnBuilder getPassThroughIndexBuilder() {
-    return new LongColumnBuilder(null, 1);
+    return isDeclaredAsPassThrough ? new LongColumnBuilder(null, 1) : null;
   }
 
   private List<TsBlock> buildTsBlock(
@@ -201,7 +206,7 @@ public class TableFunctionOperator implements 
ProcessOperator {
     if (properChannelCount > 0) {
       // if there is proper column, use its position count
       positionCount = properColumnBuilders.get(0).getPositionCount();
-    } else if (needPassThrough) {
+    } else if (isDeclaredAsPassThrough) {
       // if there is no proper column, use pass through column's position count
       positionCount = passThroughIndexBuilder.getPositionCount();
     }
@@ -215,7 +220,14 @@ public class TableFunctionOperator implements 
ProcessOperator {
     if (needPassThrough) {
       // handle pass through column only if needed
       int builtCount = 0;
-      Column passThroughIndex = passThroughIndexBuilder.build();
+      Column passThroughIndex;
+      if (isDeclaredAsPassThrough) {
+        passThroughIndex = passThroughIndexBuilder.build();
+      } else {
+        passThroughIndex =
+            new RunLengthEncodedColumn(
+                new LongColumn(1, Optional.empty(), new long[] {0}), 
positionCount);
+      }
       for (Column[] passThroughColumns : 
partitionCache.getPassThroughResult(passThroughIndex)) {
         int subBlockPositionCount = passThroughColumns[0].getPositionCount();
         TsBlock subProperBlock = properBlock.getRegion(builtCount, 
subBlockPositionCount);
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/TableOperatorGenerator.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/TableOperatorGenerator.java
index ee6a13a006c..e98259a353a 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/TableOperatorGenerator.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/TableOperatorGenerator.java
@@ -2934,6 +2934,9 @@ public class TableOperatorGenerator extends 
PlanVisitor<Operator, LocalExecution
           properChannelCount,
           requiredChannels,
           passThroughChannels,
+          passThroughSpecification
+              
.map(TableFunctionNode.PassThroughSpecification::isDeclaredAsPassThrough)
+              .orElse(false),
           partitionChannels,
           node.isRequireRecordSnapshot());
     }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/StatementAnalyzer.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/StatementAnalyzer.java
index ec8279853bd..8c945bd72ab 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/StatementAnalyzer.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/StatementAnalyzer.java
@@ -4417,6 +4417,14 @@ public class StatementAnalyzer {
                   argumentSpecification.getType(), 
constantValue.getClass().getSimpleName()));
         }
       }
+      for (Function<Object, String> checker : 
argumentSpecification.getCheckers()) {
+        String errMsg = checker.apply(constantValue);
+        if (errMsg != null) {
+          throw new SemanticException(
+              String.format(
+                  "Invalid scalar argument %s, %s", 
argumentSpecification.getName(), errMsg));
+        }
+      }
       return new ArgumentAnalysis(
           new ScalarArgument(argumentSpecification.getType(), constantValue), 
Optional.empty());
     }
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/function/Repeat.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/function/Repeat.java
index 0682fd83d53..19a4fe3cecc 100644
--- 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/function/Repeat.java
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/function/Repeat.java
@@ -91,10 +91,10 @@ public class Repeat implements TableFunction {
 
           @Override
           public void finish(
-              List<ColumnBuilder> columnBuilders, ColumnBuilder 
passThroughIndexBuilder) {
+              List<ColumnBuilder> properColumnBuilders, ColumnBuilder 
passThroughIndexBuilder) {
             for (int i = 1; i < n; i++) {
               for (int j = 0; j < recordIndex; j++) {
-                columnBuilders.get(0).writeInt(i);
+                properColumnBuilders.get(0).writeInt(i);
                 passThroughIndexBuilder.writeLong(j);
               }
             }
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/relational/tvf/CapacityTableFunction.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/relational/tvf/CapacityTableFunction.java
index f5d84c37ada..380a19be1a7 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/relational/tvf/CapacityTableFunction.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/relational/tvf/CapacityTableFunction.java
@@ -103,8 +103,9 @@ public class CapacityTableFunction implements TableFunction 
{
     }
 
     @Override
-    public void finish(List<ColumnBuilder> columnBuilders, ColumnBuilder 
passThroughIndexBuilder) {
-      outputWindow(columnBuilders, passThroughIndexBuilder);
+    public void finish(
+        List<ColumnBuilder> properColumnBuilders, ColumnBuilder 
passThroughIndexBuilder) {
+      outputWindow(properColumnBuilders, passThroughIndexBuilder);
     }
 
     private void outputWindow(
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/relational/tvf/CumulateTableFunction.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/relational/tvf/CumulateTableFunction.java
index acb3e588f05..aee0481cd24 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/relational/tvf/CumulateTableFunction.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/relational/tvf/CumulateTableFunction.java
@@ -42,6 +42,7 @@ import java.util.List;
 import java.util.Map;
 
 import static 
org.apache.iotdb.commons.udf.builtin.relational.tvf.WindowTVFUtils.findColumnIndex;
+import static 
org.apache.iotdb.udf.api.relational.table.argument.ScalarArgumentChecker.POSITIVE_LONG_CHECKER;
 
 public class CumulateTableFunction implements TableFunction {
 
@@ -64,8 +65,16 @@ public class CumulateTableFunction implements TableFunction {
             .type(Type.STRING)
             .defaultValue("time")
             .build(),
-        
ScalarParameterSpecification.builder().name(SIZE_PARAMETER_NAME).type(Type.INT64).build(),
-        
ScalarParameterSpecification.builder().name(STEP_PARAMETER_NAME).type(Type.INT64).build(),
+        ScalarParameterSpecification.builder()
+            .name(SIZE_PARAMETER_NAME)
+            .type(Type.INT64)
+            .addChecker(POSITIVE_LONG_CHECKER)
+            .build(),
+        ScalarParameterSpecification.builder()
+            .name(STEP_PARAMETER_NAME)
+            .type(Type.INT64)
+            .addChecker(POSITIVE_LONG_CHECKER)
+            .build(),
         ScalarParameterSpecification.builder()
             .name(ORIGIN_PARAMETER_NAME)
             .type(Type.TIMESTAMP)
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/relational/tvf/HOPTableFunction.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/relational/tvf/HOPTableFunction.java
index b2178c5805a..f621d24e80b 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/relational/tvf/HOPTableFunction.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/relational/tvf/HOPTableFunction.java
@@ -41,6 +41,7 @@ import java.util.List;
 import java.util.Map;
 
 import static 
org.apache.iotdb.commons.udf.builtin.relational.tvf.WindowTVFUtils.findColumnIndex;
+import static 
org.apache.iotdb.udf.api.relational.table.argument.ScalarArgumentChecker.POSITIVE_LONG_CHECKER;
 
 public class HOPTableFunction implements TableFunction {
 
@@ -63,8 +64,16 @@ public class HOPTableFunction implements TableFunction {
             .type(Type.STRING)
             .defaultValue("time")
             .build(),
-        
ScalarParameterSpecification.builder().name(SIZE_PARAMETER_NAME).type(Type.INT64).build(),
-        
ScalarParameterSpecification.builder().name(SLIDE_PARAMETER_NAME).type(Type.INT64).build(),
+        ScalarParameterSpecification.builder()
+            .name(SIZE_PARAMETER_NAME)
+            .addChecker(POSITIVE_LONG_CHECKER)
+            .type(Type.INT64)
+            .build(),
+        ScalarParameterSpecification.builder()
+            .name(SLIDE_PARAMETER_NAME)
+            .addChecker(POSITIVE_LONG_CHECKER)
+            .type(Type.INT64)
+            .build(),
         ScalarParameterSpecification.builder()
             .name(ORIGIN_PARAMETER_NAME)
             .type(Type.TIMESTAMP)
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/relational/tvf/SessionTableFunction.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/relational/tvf/SessionTableFunction.java
index 9a7ec4577ab..ca679b82b1f 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/relational/tvf/SessionTableFunction.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/relational/tvf/SessionTableFunction.java
@@ -122,8 +122,9 @@ public class SessionTableFunction implements TableFunction {
     }
 
     @Override
-    public void finish(List<ColumnBuilder> columnBuilders, ColumnBuilder 
passThroughIndexBuilder) {
-      outputWindow(columnBuilders, passThroughIndexBuilder);
+    public void finish(
+        List<ColumnBuilder> properColumnBuilders, ColumnBuilder 
passThroughIndexBuilder) {
+      outputWindow(properColumnBuilders, passThroughIndexBuilder);
     }
 
     private void outputWindow(
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/relational/tvf/TumbleTableFunction.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/relational/tvf/TumbleTableFunction.java
index a239c694129..3c7ec080cef 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/relational/tvf/TumbleTableFunction.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/relational/tvf/TumbleTableFunction.java
@@ -42,6 +42,7 @@ import java.util.List;
 import java.util.Map;
 
 import static 
org.apache.iotdb.commons.udf.builtin.relational.tvf.WindowTVFUtils.findColumnIndex;
+import static 
org.apache.iotdb.udf.api.relational.table.argument.ScalarArgumentChecker.POSITIVE_LONG_CHECKER;
 
 public class TumbleTableFunction implements TableFunction {
   private static final String DATA_PARAMETER_NAME = "DATA";
@@ -62,7 +63,11 @@ public class TumbleTableFunction implements TableFunction {
             .type(Type.STRING)
             .defaultValue("time")
             .build(),
-        
ScalarParameterSpecification.builder().name(SIZE_PARAMETER_NAME).type(Type.INT64).build(),
+        ScalarParameterSpecification.builder()
+            .name(SIZE_PARAMETER_NAME)
+            .addChecker(POSITIVE_LONG_CHECKER)
+            .type(Type.INT64)
+            .build(),
         ScalarParameterSpecification.builder()
             .name(ORIGIN_PARAMETER_NAME)
             .type(Type.TIMESTAMP)
diff --git 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/relational/tvf/VariationTableFunction.java
 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/relational/tvf/VariationTableFunction.java
index 189ef0bc469..263ad5452f7 100644
--- 
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/relational/tvf/VariationTableFunction.java
+++ 
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/relational/tvf/VariationTableFunction.java
@@ -126,8 +126,9 @@ public class VariationTableFunction implements 
TableFunction {
     }
 
     @Override
-    public void finish(List<ColumnBuilder> columnBuilders, ColumnBuilder 
passThroughIndexBuilder) {
-      outputWindow(columnBuilders, passThroughIndexBuilder);
+    public void finish(
+        List<ColumnBuilder> properColumnBuilders, ColumnBuilder 
passThroughIndexBuilder) {
+      outputWindow(properColumnBuilders, passThroughIndexBuilder);
     }
 
     private void outputWindow(

Reply via email to