This is an automated email from the ASF dual-hosted git repository. jackietien pushed a commit to branch DefaultOrderByTime in repository https://gitbox.apache.org/repos/asf/iotdb.git
commit b9c3e1c6c99c2379a268e64690f5f8e1abe2ee0a Author: JackieTien97 <[email protected]> AuthorDate: Thu May 15 15:10:43 2025 +0800 Make input defaultly order by timecol asc --- .../relational/analyzer/StatementAnalyzer.java | 94 +++++++++++++++++++++- .../function/tvf/ForecastTableFunction.java | 2 +- .../sql/ast/TableFunctionTableArgument.java | 6 +- 3 files changed, 97 insertions(+), 5 deletions(-) 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 df9fa7052e4..ef93fe1f5d8 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 @@ -38,6 +38,8 @@ import org.apache.iotdb.db.queryengine.plan.relational.analyzer.tablefunction.Ar import org.apache.iotdb.db.queryengine.plan.relational.analyzer.tablefunction.ArgumentsAnalysis; import org.apache.iotdb.db.queryengine.plan.relational.analyzer.tablefunction.TableArgumentAnalysis; import org.apache.iotdb.db.queryengine.plan.relational.analyzer.tablefunction.TableFunctionInvocationAnalysis; +import org.apache.iotdb.db.queryengine.plan.relational.function.TableBuiltinTableFunction; +import org.apache.iotdb.db.queryengine.plan.relational.function.tvf.ForecastTableFunction; import org.apache.iotdb.db.queryengine.plan.relational.metadata.ColumnSchema; import org.apache.iotdb.db.queryengine.plan.relational.metadata.Metadata; import org.apache.iotdb.db.queryengine.plan.relational.metadata.QualifiedObjectName; @@ -157,6 +159,7 @@ import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.SortItem; import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.StartPipe; import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Statement; import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.StopPipe; +import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.StringLiteral; import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.SubqueryExpression; import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.SymbolReference; import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Table; @@ -4056,7 +4059,8 @@ public class StatementAnalyzer { @Override public Scope visitTableFunctionInvocation(TableFunctionInvocation node, Optional<Scope> scope) { - TableFunction function = metadata.getTableFunction(node.getName().toString()); + String functionName = node.getName().toString(); + TableFunction function = metadata.getTableFunction(functionName); Node errorLocation = node; if (!node.getArguments().isEmpty()) { errorLocation = node.getArguments().get(0); @@ -4064,7 +4068,11 @@ public class StatementAnalyzer { ArgumentsAnalysis argumentsAnalysis = analyzeArguments( - function.getArgumentsSpecifications(), node.getArguments(), scope, errorLocation); + function.getArgumentsSpecifications(), + node.getArguments(), + scope, + errorLocation, + functionName); TableFunctionAnalysis functionAnalysis; try { @@ -4210,7 +4218,8 @@ public class StatementAnalyzer { List<ParameterSpecification> parameterSpecifications, List<TableFunctionArgument> arguments, Optional<Scope> scope, - Node errorLocation) { + Node errorLocation, + String functionName) { if (parameterSpecifications.size() < arguments.size()) { throw new SemanticException( String.format( @@ -4246,6 +4255,11 @@ public class StatementAnalyzer { "Duplicate argument specification for name: " + parameterSpecification.getName()); } } + + // append order by time asc for built-in forecast tvf if user doesn't specify order by + // clause + tryUpdateOrderByForForecastByName(functionName, arguments, argumentSpecificationsByName); + Set<String> uniqueArgumentNames = new HashSet<>(); Set<String> specifiedArgumentNames = ImmutableSet.copyOf(argumentSpecificationsByName.keySet()); @@ -4277,6 +4291,9 @@ public class StatementAnalyzer { analyzeDefault(parameterSpecification, errorLocation)); } } else { + // append order by time asc for built-in forecast tvf if user doesn't specify order by + // clause + tryUpdateOrderByForForecastByPosition(functionName, arguments, parameterSpecifications); for (int i = 0; i < arguments.size(); i++) { TableFunctionArgument argument = arguments.get(i); ParameterSpecification parameterSpecification = parameterSpecifications.get(i); @@ -4296,6 +4313,77 @@ public class StatementAnalyzer { return new ArgumentsAnalysis(passedArguments.buildOrThrow(), tableArgumentAnalyses.build()); } + // append order by time asc for built-in forecast tvf if user doesn't specify order by clause + private void tryUpdateOrderByForForecastByName( + String functionName, + List<TableFunctionArgument> arguments, + Map<String, ParameterSpecification> argumentSpecificationsByName) { + if (TableBuiltinTableFunction.FORECAST.getFunctionName().equalsIgnoreCase(functionName)) { + String timeColumn = + (String) + argumentSpecificationsByName + .get(ForecastTableFunction.TIMECOL_PARAMETER_NAME) + .getDefaultValue() + .get(); + for (TableFunctionArgument argument : arguments) { + if (ForecastTableFunction.TIMECOL_PARAMETER_NAME.equalsIgnoreCase( + argument.getName().get().getValue())) { + if (argument.getValue() instanceof StringLiteral) { + timeColumn = ((StringLiteral) argument.getValue()).getValue(); + } + } + } + tryUpdateOrderByForForecast(arguments, timeColumn); + } + } + + // append order by time asc for built-in forecast tvf if user doesn't specify order by clause + private void tryUpdateOrderByForForecastByPosition( + String functionName, + List<TableFunctionArgument> arguments, + List<ParameterSpecification> parameterSpecifications) { + if (TableBuiltinTableFunction.FORECAST.getFunctionName().equalsIgnoreCase(functionName)) { + int position = -1; + String timeColumn = null; + for (int i = 0, size = parameterSpecifications.size(); i < size; i++) { + if (ForecastTableFunction.TIMECOL_PARAMETER_NAME.equalsIgnoreCase( + parameterSpecifications.get(i).getName())) { + position = i; + timeColumn = (String) parameterSpecifications.get(i).getDefaultValue().get(); + break; + } + } + if (position == -1) { + throw new IllegalStateException( + "ForecastTableFunction must contain ForecastTableFunction.TIMECOL_PARAMETER_NAME"); + } + if (position < arguments.size() + && arguments.get(position).getValue() instanceof StringLiteral) { + timeColumn = ((StringLiteral) arguments.get(position).getValue()).getValue(); + } + tryUpdateOrderByForForecast(arguments, timeColumn); + } + } + + // append order by time asc for built-in forecast tvf if user doesn't specify order by clause + private void tryUpdateOrderByForForecast( + List<TableFunctionArgument> arguments, String timeColumn) { + for (TableFunctionArgument argument : arguments) { + if (argument.getValue() instanceof TableFunctionTableArgument) { + TableFunctionTableArgument input = (TableFunctionTableArgument) argument.getValue(); + if (!input.getOrderBy().isPresent()) { + input.updateOrderBy( + new OrderBy( + Collections.singletonList( + new SortItem( + new Identifier(null, timeColumn), + SortItem.Ordering.ASCENDING, + SortItem.NullOrdering.FIRST)))); + } + } + } + } + private ArgumentAnalysis analyzeArgument( ParameterSpecification parameterSpecification, TableFunctionArgument argument, diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/function/tvf/ForecastTableFunction.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/function/tvf/ForecastTableFunction.java index 9086e6f5edd..a04cb1c3ad3 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/function/tvf/ForecastTableFunction.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/function/tvf/ForecastTableFunction.java @@ -166,7 +166,7 @@ public class ForecastTableFunction implements TableFunction { private static final long DEFAULT_OUTPUT_START_TIME = Long.MIN_VALUE; private static final String OUTPUT_INTERVAL = "OUTPUT_INTERVAL"; private static final long DEFAULT_OUTPUT_INTERVAL = 0L; - private static final String TIMECOL_PARAMETER_NAME = "TIMECOL"; + public static final String TIMECOL_PARAMETER_NAME = "TIMECOL"; private static final String DEFAULT_TIME_COL = "time"; private static final String KEEP_INPUT_PARAMETER_NAME = "KEEP_INPUT"; private static final Boolean DEFAULT_KEEP_INPUT = Boolean.FALSE; diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/TableFunctionTableArgument.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/TableFunctionTableArgument.java index 8c0addef1d8..c6f1ee88d0c 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/TableFunctionTableArgument.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/TableFunctionTableArgument.java @@ -32,7 +32,7 @@ import static org.apache.iotdb.db.queryengine.plan.relational.sql.util.Expressio public class TableFunctionTableArgument extends Node { private final Relation table; private final Optional<List<Expression>> partitionBy; // it is allowed to partition by empty list - private final Optional<OrderBy> orderBy; + private Optional<OrderBy> orderBy; public TableFunctionTableArgument( NodeLocation location, @@ -57,6 +57,10 @@ public class TableFunctionTableArgument extends Node { return orderBy; } + public void updateOrderBy(OrderBy orderBy) { + this.orderBy = Optional.of(orderBy); + } + @Override public <R, C> R accept(AstVisitor<R, C> visitor, C context) { return visitor.visitTableArgument(this, context);
