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 fe96a5573dd Perfect implicit time process in first, last, first_by,
last_by of TableModel
fe96a5573dd is described below
commit fe96a5573dde2fccb895d04a039ab786d39e3f4d
Author: Weihao Li <[email protected]>
AuthorDate: Fri Oct 17 16:42:45 2025 +0800
Perfect implicit time process in first, last, first_by, last_by of
TableModel
---
.../db/it/IoTDBMultiTAGsWithAttributesTableIT.java | 39 +++++++++++++++++++-
.../plan/relational/sql/parser/AstBuilder.java | 42 ++++++++++++++--------
2 files changed, 66 insertions(+), 15 deletions(-)
diff --git
a/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBMultiTAGsWithAttributesTableIT.java
b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBMultiTAGsWithAttributesTableIT.java
index 8dd8c8a343a..7b959696068 100644
---
a/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBMultiTAGsWithAttributesTableIT.java
+++
b/integration-test/src/test/java/org/apache/iotdb/relational/it/db/it/IoTDBMultiTAGsWithAttributesTableIT.java
@@ -167,6 +167,12 @@ public class IoTDBMultiTAGsWithAttributesTableIT {
"delete from table6 where time >= 1"
};
+ private static final String[] sql7 =
+ new String[] {
+ "create table t1(device_id STRING TAG, code STRING TAG, s1 float)",
+ "create table t2(device_id STRING TAG, s2 float)"
+ };
+
String[] expectedHeader;
String[] retArray;
static String sql;
@@ -191,7 +197,7 @@ public class IoTDBMultiTAGsWithAttributesTableIT {
private static void insertData() {
try (Connection connection = EnvFactory.getEnv().getTableConnection();
Statement statement = connection.createStatement()) {
- for (String[] sqlList : Arrays.asList(sql1, sql2, sql3, sql4, sql5,
sql6)) {
+ for (String[] sqlList : Arrays.asList(sql1, sql2, sql3, sql4, sql5,
sql6, sql7)) {
for (String sql : sqlList) {
statement.execute(sql);
}
@@ -2881,6 +2887,37 @@ public class IoTDBMultiTAGsWithAttributesTableIT {
DATABASE_NAME);
}
+ @Test
+ public void implicitTimeTest() {
+ expectedHeader = new String[] {"code", "_col1", "device_id", "_col3"};
+ retArray = new String[] {};
+ tableResultSetEqualTest(
+ "select t1.code,date_bin(15m, t2.time),t2.device_id,last(t2.s2) from
t1, t2 "
+ + "where t1.device_id = t2.device_id group by
t1.code,date_bin(15m, t2.time),t2.device_id",
+ expectedHeader,
+ retArray,
+ DATABASE_NAME);
+
+ tableResultSetEqualTest(
+ "select t1.code,date_bin(15m, t2.time),t2.device_id,last(t2.s2,
t2.time) from t1, t2 "
+ + "where t1.device_id = t2.device_id group by
t1.code,date_bin(15m, t2.time),t2.device_id",
+ expectedHeader,
+ retArray,
+ DATABASE_NAME);
+
+ tableAssertTestFail(
+ "select t1.code,date_bin(15m, t2.time),t2.device_id,last(t2.s2, time)
from t1, t2 "
+ + "where t1.device_id = t2.device_id group by
t1.code,date_bin(15m, t2.time),t2.device_id",
+ "Column 'time' is ambiguous",
+ DATABASE_NAME);
+
+ expectedHeader = new String[] {"_col0"};
+ retArray = new String[] {"null,"};
+ tableResultSetEqualTest("select last(1) from t1", expectedHeader,
retArray, DATABASE_NAME);
+
+ tableResultSetEqualTest("select last(1,time) from t1", expectedHeader,
retArray, DATABASE_NAME);
+ }
+
public static void repeatTest(
String sql, String[] expectedHeader, String[] retArray, String dbName,
int repeatTimes) {
for (int i = 0; i < repeatTimes; i++) {
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/AstBuilder.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/AstBuilder.java
index 431ed9d3d02..76107bfa30e 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/AstBuilder.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/AstBuilder.java
@@ -3340,30 +3340,20 @@ public class AstBuilder extends
RelationalSqlBaseVisitor<Node> {
if (name.toString().equalsIgnoreCase(FIRST_AGGREGATION)
|| name.toString().equalsIgnoreCase(LAST_AGGREGATION)) {
if (arguments.size() == 1) {
- arguments.add(
- new Identifier(
-
TimestampOperand.TIMESTAMP_EXPRESSION_STRING.toLowerCase(Locale.ENGLISH)));
+ appendTimeArgument(arguments);
} else if (arguments.size() == 2) {
check(
- arguments
- .get(1)
- .toString()
-
.equalsIgnoreCase(TimestampOperand.TIMESTAMP_EXPRESSION_STRING),
+ checkArgumentIsTime(arguments.get(1)),
"The second argument of 'first' or 'last' function must be 'time'",
ctx);
}
} else if (name.toString().equalsIgnoreCase(FIRST_BY_AGGREGATION)
|| name.toString().equalsIgnoreCase(LAST_BY_AGGREGATION)) {
if (arguments.size() == 2) {
- arguments.add(
- new Identifier(
-
TimestampOperand.TIMESTAMP_EXPRESSION_STRING.toLowerCase(Locale.ENGLISH)));
+ appendTimeArgument(arguments);
} else if (arguments.size() == 3) {
check(
- arguments
- .get(2)
- .toString()
-
.equalsIgnoreCase(TimestampOperand.TIMESTAMP_EXPRESSION_STRING),
+ checkArgumentIsTime(arguments.get(2)),
"The third argument of 'first_by' or 'last_by' function must be
'time'",
ctx);
}
@@ -3395,6 +3385,30 @@ public class AstBuilder extends
RelationalSqlBaseVisitor<Node> {
return new FunctionCall(getLocation(ctx), name, window, nulls, distinct,
mode, arguments);
}
+ private void appendTimeArgument(List<Expression> arguments) {
+ if (arguments.get(0) instanceof DereferenceExpression) {
+ arguments.add(
+ new DereferenceExpression(
+ ((DereferenceExpression) arguments.get(0)).getBase(),
+ new Identifier(
+
TimestampOperand.TIMESTAMP_EXPRESSION_STRING.toLowerCase(Locale.ENGLISH))));
+ } else {
+ arguments.add(
+ new
Identifier(TimestampOperand.TIMESTAMP_EXPRESSION_STRING.toLowerCase(Locale.ENGLISH)));
+ }
+ }
+
+ private boolean checkArgumentIsTime(Expression argument) {
+ if (argument instanceof DereferenceExpression) {
+ return ((DereferenceExpression) argument)
+ .getField()
+ .get()
+ .toString()
+ .equalsIgnoreCase(TimestampOperand.TIMESTAMP_EXPRESSION_STRING);
+ }
+ return
argument.toString().equalsIgnoreCase(TimestampOperand.TIMESTAMP_EXPRESSION_STRING);
+ }
+
@Override
public Node visitDateBinGapFill(RelationalSqlParser.DateBinGapFillContext
ctx) {
TimeDuration timeDuration =
DateTimeUtils.constructTimeDuration(ctx.timeDuration().getText());