Skip to content

Commit 003f9b6

Browse files
authored
Support User Defined time column name (#17102)
1 parent 48ac5db commit 003f9b6

47 files changed

Lines changed: 1832 additions & 335 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

integration-test/src/main/java/org/apache/iotdb/it/utils/TsFileTableGenerator.java

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import java.io.File;
3838
import java.io.IOException;
3939
import java.time.LocalDate;
40+
import java.util.ArrayList;
4041
import java.util.HashMap;
4142
import java.util.List;
4243
import java.util.Map;
@@ -81,15 +82,30 @@ public void registerTable(
8182
public void generateData(final String tableName, final int number, final long timeGap)
8283
throws IOException, WriteProcessException {
8384
final List<IMeasurementSchema> schemas = table2MeasurementSchema.get(tableName);
85+
final List<ColumnCategory> columnCategoryList = table2ColumnCategory.get(tableName);
86+
int timeIndex = -1;
87+
for (int i = 0; i < columnCategoryList.size(); ++i) {
88+
if (columnCategoryList.get(i) == ColumnCategory.TIME) {
89+
timeIndex = i;
90+
break;
91+
}
92+
}
93+
final List<IMeasurementSchema> schemaWithoutTime = new ArrayList<>(schemas);
94+
final List<ColumnCategory> columnCategoriesWithoutTime = new ArrayList<>(columnCategoryList);
95+
if (timeIndex > -1) {
96+
schemaWithoutTime.remove(timeIndex);
97+
columnCategoriesWithoutTime.remove(timeIndex);
98+
}
8499
final List<String> columnNameList =
85-
schemas.stream().map(IMeasurementSchema::getMeasurementName).collect(Collectors.toList());
100+
schemaWithoutTime.stream()
101+
.map(IMeasurementSchema::getMeasurementName)
102+
.collect(Collectors.toList());
86103
final List<TSDataType> dataTypeList =
87-
schemas.stream().map(IMeasurementSchema::getType).collect(Collectors.toList());
88-
final List<ColumnCategory> columnCategoryList = table2ColumnCategory.get(tableName);
104+
schemaWithoutTime.stream().map(IMeasurementSchema::getType).collect(Collectors.toList());
89105
final TreeSet<Long> timeSet = table2TimeSet.get(tableName);
90-
final Tablet tablet = new Tablet(tableName, columnNameList, dataTypeList, columnCategoryList);
91-
final Object[] values = tablet.getValues();
92-
final long sensorNum = schemas.size();
106+
final Tablet tablet =
107+
new Tablet(tableName, columnNameList, dataTypeList, columnCategoriesWithoutTime);
108+
final long sensorNum = schemaWithoutTime.size();
93109
long startTime = timeSet.isEmpty() ? 0L : timeSet.last();
94110

95111
for (long r = 0; r < number; r++) {
@@ -98,7 +114,7 @@ public void generateData(final String tableName, final int number, final long ti
98114
tablet.addTimestamp(row, startTime);
99115
timeSet.add(startTime);
100116
for (int i = 0; i < sensorNum; i++) {
101-
generateDataPoint(tablet, i, row, schemas.get(i));
117+
generateDataPoint(tablet, i, row, schemaWithoutTime.get(i));
102118
}
103119
// write
104120
if (tablet.getRowSize() == tablet.getMaxRowNumber()) {

integration-test/src/test/java/org/apache/iotdb/db/it/query/IoTDBAggregationFirstByIT.java

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,27 @@
1818
*/
1919
package org.apache.iotdb.db.it.query;
2020

21+
import org.apache.iotdb.isession.SessionConfig;
2122
import org.apache.iotdb.it.env.EnvFactory;
2223
import org.apache.iotdb.it.framework.IoTDBTestRunner;
2324
import org.apache.iotdb.itbase.category.TableClusterIT;
2425
import org.apache.iotdb.itbase.category.TableLocalStandaloneIT;
26+
import org.apache.iotdb.itbase.env.BaseEnv;
2527

2628
import org.junit.AfterClass;
2729
import org.junit.BeforeClass;
2830
import org.junit.Test;
2931
import org.junit.experimental.categories.Category;
3032
import org.junit.runner.RunWith;
3133

34+
import java.sql.Connection;
35+
import java.sql.SQLException;
36+
import java.sql.Statement;
37+
3238
import static org.apache.iotdb.db.it.utils.TestUtils.prepareTableData;
3339
import static org.apache.iotdb.db.it.utils.TestUtils.tableResultSetEqualTest;
40+
import static org.junit.Assert.assertEquals;
41+
import static org.junit.Assert.fail;
3442

3543
@RunWith(IoTDBTestRunner.class)
3644
@Category({TableLocalStandaloneIT.class, TableClusterIT.class})
@@ -103,25 +111,83 @@ public static void tearDown() throws Exception {
103111
EnvFactory.getEnv().cleanClusterEnvironment();
104112
}
105113

114+
@Test
115+
public void TestPriority() {
116+
String[] expectedHeader = {"_col0", "_col1", "_col2", "_col3", "_col4", "_col5"};
117+
String[] retArray = {"1,1,1.0,1.0,true,1s,"};
118+
tableResultSetEqualTest(
119+
"select "
120+
+ "first_by(s_int, y_criteria), "
121+
+ "first_by(s_long, y_criteria), "
122+
+ "first_by(s_float, y_criteria), "
123+
+ "first_by(s_double, y_criteria), "
124+
+ "first_by(s_bool, y_criteria), "
125+
+ "first_by(s_string, y_criteria) "
126+
+ "from table_a "
127+
+ "where table_a.device='d1'",
128+
expectedHeader,
129+
retArray,
130+
DATABASE_NAME);
131+
}
132+
133+
@Test
134+
public void testNoTimeStamp() {
135+
136+
String sql =
137+
"select "
138+
+ "first_by(s_int, y_criteria)"
139+
+ " from ("
140+
+ " select "
141+
+ " s_int,"
142+
+ " s_long,"
143+
+ " s_float,"
144+
+ " y_criteria"
145+
+ " from table_a"
146+
+ ") AS t";
147+
try (Connection connection =
148+
EnvFactory.getEnv()
149+
.getConnection(
150+
SessionConfig.DEFAULT_USER,
151+
SessionConfig.DEFAULT_PASSWORD,
152+
BaseEnv.TABLE_SQL_DIALECT)) {
153+
connection.setClientInfo("time_zone", "+00:00");
154+
try (Statement statement = connection.createStatement()) {
155+
statement.execute("use " + DATABASE_NAME);
156+
statement.executeQuery(sql);
157+
}
158+
fail("Missing valid time column, the query should fail");
159+
} catch (SQLException e) {
160+
assertEquals(
161+
"701: Missing valid time column. The table must contain either a column with the TIME category or at least one TIMESTAMP column.",
162+
e.getMessage());
163+
}
164+
}
165+
106166
@Test
107167
public void testFirstBy_d1_NoNulls() {
108168
String[] expectedHeader = {"_col0", "_col1", "_col2", "_col3", "_col4", "_col5"};
109169
String[] retArray = {"5,5,5.0,5.0,false,5s,"};
110170
runTest("d1", expectedHeader, retArray);
171+
runTest2("d1", expectedHeader, retArray);
172+
runTest3("d1", expectedHeader, retArray);
111173
}
112174

113175
@Test
114176
public void testFirstBy_d2_ForwardTracking() {
115177
String[] expectedHeader = {"_col0", "_col1", "_col2", "_col3", "_col4", "_col5"};
116178
String[] retArray = {"10,10,10.0,10.0,true,10s,"};
117179
runTest("d2", expectedHeader, retArray);
180+
runTest2("d2", expectedHeader, retArray);
181+
runTest3("d2", expectedHeader, retArray);
118182
}
119183

120184
@Test
121185
public void testFirstBy_d3_TargetNull() {
122186
String[] expectedHeader = {"_col0", "_col1", "_col2", "_col3", "_col4", "_col5"};
123187
String[] retArray = {"5,5,null,null,null,null,"};
124188
runTest("d3", expectedHeader, retArray);
189+
runTest2("d3", expectedHeader, retArray);
190+
runTest3("d3", expectedHeader, retArray);
125191
}
126192

127193
@Test
@@ -130,6 +196,8 @@ public void testFirstBy_d4_AllNullCriteria() {
130196
// Expected: No valid s2 found.
131197
String[] retArray = {"null,null,null,null,null,null,"};
132198
runTest("d4", expectedHeader, retArray);
199+
runTest2("d4", expectedHeader, retArray);
200+
runTest3("d4", expectedHeader, retArray);
133201
}
134202

135203
@Test
@@ -138,6 +206,8 @@ public void testFirstBy_d5_AllTimeNull() {
138206
// Expected: The row with y_criteria=NULL is skipped. The row with y_criteria=50 is picked.
139207
String[] retArray = {"50,50,50.0,50.0,false,50s,"};
140208
runTest("d5", expectedHeader, retArray);
209+
runTest2("d5", expectedHeader, retArray);
210+
runTest3("d5", expectedHeader, retArray);
141211
}
142212

143213
private void runTest(String deviceId, String[] expectedHeader, String[] retArray) {
@@ -159,4 +229,43 @@ private void runTest(String deviceId, String[] expectedHeader, String[] retArray
159229
retArray,
160230
DATABASE_NAME);
161231
}
232+
233+
private void runTest2(String deviceId, String[] expectedHeader, String[] retArray) {
234+
tableResultSetEqualTest(
235+
"select "
236+
+ "first_by(s_int, y_criteria), "
237+
+ "first_by(s_long, y_criteria), "
238+
+ "first_by(s_float, y_criteria), "
239+
+ "first_by(s_double, y_criteria), "
240+
+ "first_by(s_bool, y_criteria), "
241+
+ "first_by(s_string, y_criteria) "
242+
+ "from "
243+
+ "(select s_int, s_long, s_float, s_double, s_bool, s_string, y_criteria, time_type "
244+
+ "from table_a left join table_b on table_a.time=table_b.time "
245+
+ "where table_a.device='"
246+
+ deviceId
247+
+ "') ",
248+
expectedHeader,
249+
retArray,
250+
DATABASE_NAME);
251+
}
252+
253+
/** Test 3: Raw table query with explicit time_type column, 3 arguments */
254+
private void runTest3(String deviceId, String[] expectedHeader, String[] retArray) {
255+
tableResultSetEqualTest(
256+
"select "
257+
+ "first_by(s_int, y_criteria, time_type), "
258+
+ "first_by(s_long, y_criteria, time_type), "
259+
+ "first_by(s_float, y_criteria, time_type), "
260+
+ "first_by(s_double, y_criteria, time_type), "
261+
+ "first_by(s_bool, y_criteria, time_type), "
262+
+ "first_by(s_string, y_criteria, time_type) "
263+
+ "from table_a "
264+
+ "where table_a.device='"
265+
+ deviceId
266+
+ "'",
267+
expectedHeader,
268+
retArray,
269+
DATABASE_NAME);
270+
}
162271
}

integration-test/src/test/java/org/apache/iotdb/db/it/query/IoTDBAggregationFirstByInGroupIT.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ public void testGroupedFirstByAggregation() {
117117
"p5,50,50,50.0,50.0,false,50s,"
118118
};
119119

120+
// 1. eliminate the identity of time column
120121
tableResultSetEqualTest(
121122
"select "
122123
+ "partition, "
@@ -135,5 +136,42 @@ public void testGroupedFirstByAggregation() {
135136
expectedHeader,
136137
retArray,
137138
DATABASE_NAME);
139+
140+
// 2. lack of the third argument, supply with timestamp column
141+
tableResultSetEqualTest(
142+
"select "
143+
+ "partition, "
144+
+ "first_by(s_int, y_criteria), "
145+
+ "first_by(s_long, y_criteria), "
146+
+ "first_by(s_float, y_criteria), "
147+
+ "first_by(s_double, y_criteria), "
148+
+ "first_by(s_bool, y_criteria), "
149+
+ "first_by(s_string, y_criteria) "
150+
+ "from "
151+
// SubQuery: Rename time_type to 'ts' to avoid ambiguity with physical 'time'
152+
+ "(select s_int, s_long, s_float, s_double, s_bool, s_string, y_criteria, partition, time_type "
153+
+ "from table_a left join table_b on table_a.time=table_b.time) "
154+
+ "group by partition "
155+
+ "order by partition",
156+
expectedHeader,
157+
retArray,
158+
DATABASE_NAME);
159+
160+
// 3. base table query with column that with timestamp datatype
161+
tableResultSetEqualTest(
162+
"select "
163+
+ "partition, "
164+
+ "first_by(s_int, y_criteria, time_type), "
165+
+ "first_by(s_long, y_criteria, time_type), "
166+
+ "first_by(s_float, y_criteria, time_type), "
167+
+ "first_by(s_double, y_criteria, time_type), "
168+
+ "first_by(s_bool, y_criteria, time_type), "
169+
+ "first_by(s_string, y_criteria, time_type) "
170+
+ "from table_a "
171+
+ "group by partition "
172+
+ "order by partition",
173+
expectedHeader,
174+
retArray,
175+
DATABASE_NAME);
138176
}
139177
}

0 commit comments

Comments
 (0)