Skip to content

Commit d405afa

Browse files
authored
fix object functions & add tests for object type & fix some bugs (#16829)
1 parent 7249a52 commit d405afa

File tree

34 files changed

+1283
-123
lines changed

34 files changed

+1283
-123
lines changed
Lines changed: 296 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,296 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.apache.iotdb.relational.it.query.object;
21+
22+
import org.apache.iotdb.isession.ITableSession;
23+
import org.apache.iotdb.isession.SessionDataSet;
24+
import org.apache.iotdb.it.env.EnvFactory;
25+
import org.apache.iotdb.it.framework.IoTDBTestRunner;
26+
import org.apache.iotdb.itbase.category.TableClusterIT;
27+
import org.apache.iotdb.itbase.category.TableLocalStandaloneIT;
28+
import org.apache.iotdb.itbase.env.BaseEnv;
29+
import org.apache.iotdb.rpc.IoTDBConnectionException;
30+
import org.apache.iotdb.rpc.StatementExecutionException;
31+
32+
import org.apache.tsfile.utils.Binary;
33+
import org.junit.AfterClass;
34+
import org.junit.Assert;
35+
import org.junit.BeforeClass;
36+
import org.junit.Test;
37+
import org.junit.experimental.categories.Category;
38+
import org.junit.runner.RunWith;
39+
40+
import java.sql.Connection;
41+
import java.sql.Statement;
42+
import java.time.LocalDate;
43+
44+
@RunWith(IoTDBTestRunner.class)
45+
@Category({TableLocalStandaloneIT.class, TableClusterIT.class})
46+
public class IoTDBObjectQueryIT2 {
47+
48+
private static final String DATABASE_NAME = "test";
49+
50+
@BeforeClass
51+
public static void setUp() throws Exception {
52+
EnvFactory.getEnv().getConfig().getCommonConfig().setDataReplicationFactor(1);
53+
EnvFactory.getEnv().initClusterEnvironment();
54+
try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
55+
Statement statement = connection.createStatement()) {
56+
statement.execute("CREATE DATABASE " + DATABASE_NAME);
57+
statement.execute("USE " + DATABASE_NAME);
58+
statement.execute(
59+
"CREATE TABLE table1(device STRING TAG, s4 DATE FIELD, s5 TIMESTAMP FIELD, s6 BLOB FIELD, s7 STRING FIELD, s8 OBJECT FIELD, s9 OBJECT FIELD)");
60+
for (int i = 1; i <= 10; i++) {
61+
for (int j = 0; j < 10; j++) {
62+
statement.execute(
63+
String.format(
64+
"insert into table1(time, device, s4, s5, s6, s7, s8) "
65+
+ "values(%d, '%s', '%s', %d, %s, '%s', %s)",
66+
j,
67+
"d" + i,
68+
LocalDate.of(2024, 5, i % 31 + 1),
69+
j,
70+
"X'cafebabe'",
71+
j,
72+
"to_object(true, 0, X'cafebabe')"));
73+
}
74+
}
75+
}
76+
}
77+
78+
@AfterClass
79+
public static void tearDown() {
80+
EnvFactory.getEnv().cleanClusterEnvironment();
81+
}
82+
83+
@Test
84+
public void testObjectLength() throws IoTDBConnectionException, StatementExecutionException {
85+
try (ITableSession session = EnvFactory.getEnv().getTableSessionConnection()) {
86+
session.executeNonQueryStatement("USE " + DATABASE_NAME);
87+
SessionDataSet sessionDataSet =
88+
session.executeQueryStatement("select length(s8) from table1 limit 1");
89+
SessionDataSet.DataIterator iterator = sessionDataSet.iterator();
90+
while (iterator.next()) {
91+
long length = iterator.getLong(1);
92+
Assert.assertEquals(4, length);
93+
}
94+
}
95+
}
96+
97+
@Test
98+
public void testReadObject() throws IoTDBConnectionException, StatementExecutionException {
99+
try (ITableSession session = EnvFactory.getEnv().getTableSessionConnection()) {
100+
session.executeNonQueryStatement("USE " + DATABASE_NAME);
101+
SessionDataSet sessionDataSet =
102+
session.executeQueryStatement("select read_object(s8) from table1 where device = 'd2'");
103+
SessionDataSet.DataIterator iterator = sessionDataSet.iterator();
104+
byte[] expected = new byte[] {(byte) 0xCA, (byte) 0xFE, (byte) 0xBA, (byte) 0xBE};
105+
while (iterator.next()) {
106+
Binary blob = iterator.getBlob(1);
107+
Assert.assertArrayEquals(expected, blob.getValues());
108+
}
109+
110+
sessionDataSet =
111+
session.executeQueryStatement(
112+
"select read_object(s8, 1) from table1 where device = 'd3'");
113+
iterator = sessionDataSet.iterator();
114+
expected = new byte[] {(byte) 0xFE, (byte) 0xBA, (byte) 0xBE};
115+
while (iterator.next()) {
116+
Binary blob = iterator.getBlob(1);
117+
Assert.assertArrayEquals(expected, blob.getValues());
118+
}
119+
120+
sessionDataSet =
121+
session.executeQueryStatement(
122+
"select read_object(s8, 1, 2) from table1 where device = 'd1'");
123+
iterator = sessionDataSet.iterator();
124+
expected = new byte[] {(byte) 0xFE, (byte) 0xBA};
125+
while (iterator.next()) {
126+
Binary blob = iterator.getBlob(1);
127+
Assert.assertArrayEquals(expected, blob.getValues());
128+
}
129+
130+
sessionDataSet =
131+
session.executeQueryStatement(
132+
"select read_object(s8, 1, 1000) from table1 where device = 'd1'");
133+
iterator = sessionDataSet.iterator();
134+
expected = new byte[] {(byte) 0xFE, (byte) 0xBA, (byte) 0xBE};
135+
while (iterator.next()) {
136+
Binary blob = iterator.getBlob(1);
137+
Assert.assertArrayEquals(expected, blob.getValues());
138+
}
139+
140+
sessionDataSet =
141+
session.executeQueryStatement(
142+
"select count(*) from table1 where device = 'd1' and s6 = read_object(s8)");
143+
iterator = sessionDataSet.iterator();
144+
while (iterator.next()) {
145+
long count = iterator.getLong(1);
146+
Assert.assertEquals(10, count);
147+
}
148+
149+
// read_object are not pushed down. Read remote files
150+
sessionDataSet =
151+
session.executeQueryStatement(
152+
"select read_object(t1_s8) from (select t1.s8 as t1_s8, t2.s8 as t2_s8 from table1 as t1 inner join table1 as t2 using(time))");
153+
iterator = sessionDataSet.iterator();
154+
expected = new byte[] {(byte) 0xCA, (byte) 0xFE, (byte) 0xBA, (byte) 0xBE};
155+
while (iterator.next()) {
156+
Binary blob = iterator.getBlob(1);
157+
Assert.assertArrayEquals(expected, blob.getValues());
158+
}
159+
}
160+
}
161+
162+
@Test
163+
public void testFunctionAndClauses()
164+
throws IoTDBConnectionException, StatementExecutionException {
165+
try (ITableSession session = EnvFactory.getEnv().getTableSessionConnection()) {
166+
session.executeNonQueryStatement("USE " + DATABASE_NAME);
167+
168+
SessionDataSet sessionDataSet =
169+
session.executeQueryStatement(
170+
"select length(s8) from table1 where device = 'd2' and s8 is not null limit 1");
171+
SessionDataSet.DataIterator iterator = sessionDataSet.iterator();
172+
while (iterator.next()) {
173+
Assert.assertEquals(4, iterator.getLong(1));
174+
}
175+
sessionDataSet =
176+
session.executeQueryStatement(
177+
"select count(s8), first(s8), last(s8), first_by(s8, time), last_by(s8, time) from table1 where device = 'd1' and cast(s8 as string) = '(Object) 4 B' and try_cast(s8 as string) = '(Object) 4 B'");
178+
iterator = sessionDataSet.iterator();
179+
while (iterator.next()) {
180+
Assert.assertEquals(10, iterator.getLong(1));
181+
Assert.assertEquals("(Object) 4 B", iterator.getString(2));
182+
Assert.assertEquals("(Object) 4 B", iterator.getString(3));
183+
Assert.assertEquals("(Object) 4 B", iterator.getString(4));
184+
Assert.assertEquals("(Object) 4 B", iterator.getString(5));
185+
}
186+
187+
sessionDataSet = session.executeQueryStatement("select coalesce(s9, s8) from table1");
188+
iterator = sessionDataSet.iterator();
189+
while (iterator.next()) {
190+
Assert.assertEquals("(Object) 4 B", iterator.getString(1));
191+
}
192+
193+
// MATCH_RECOGNIZE
194+
Assert.assertThrows(
195+
StatementExecutionException.class,
196+
() ->
197+
session.executeNonQueryStatement(
198+
"select m.cnt from table1 match_recognize (order by s8 measures RPR_LAST(time) as cnt one row per match pattern (B+) define B as B.s6 = prev(B.s6)) as m"));
199+
Assert.assertThrows(
200+
StatementExecutionException.class,
201+
() ->
202+
session.executeNonQueryStatement(
203+
"select m.cnt from table1 match_recognize (partition by s8 measures RPR_LAST(time) as cnt one row per match pattern (B+) define B as B.s6 = prev(B.s6)) as m"));
204+
205+
sessionDataSet =
206+
session.executeQueryStatement(
207+
"select m.value from table1 match_recognize(partition by s6 measures prev(s8) as value one row per match pattern (B+) define B as B.s6=prev(B.s6)) as m");
208+
iterator = sessionDataSet.iterator();
209+
while (iterator.next()) {
210+
Assert.assertEquals("(Object) 4 B", iterator.getString(1));
211+
}
212+
213+
// WHERE
214+
session.executeQueryStatement(
215+
"select time, s8 from table1 where device = 'd10' and s8 is not null");
216+
iterator = sessionDataSet.iterator();
217+
while (iterator.next()) {
218+
Assert.assertEquals("(Object) 4 B", iterator.getString(2));
219+
}
220+
221+
// GROUP BY
222+
Assert.assertThrows(
223+
StatementExecutionException.class,
224+
() -> session.executeNonQueryStatement("select count(*) from table1 group by s8"));
225+
226+
// ORDER BY
227+
Assert.assertThrows(
228+
StatementExecutionException.class,
229+
() -> session.executeNonQueryStatement("select count(*) from table1 order by s8"));
230+
231+
// FILL
232+
Assert.assertThrows(
233+
StatementExecutionException.class,
234+
() ->
235+
session.executeNonQueryStatement(
236+
"select time, s8 from table1 where device = 'd10' fill method linear"));
237+
session.executeQueryStatement(
238+
"select time, s8 from table1 where device = 'd10' fill method previous");
239+
iterator = sessionDataSet.iterator();
240+
while (iterator.next()) {
241+
Assert.assertEquals("(Object) 4 B", iterator.getString(2));
242+
}
243+
244+
// HAVING
245+
session.executeQueryStatement(
246+
"select device, count(s8) from table1 group by device having count(s8) > 0");
247+
iterator = sessionDataSet.iterator();
248+
while (iterator.next()) {
249+
long count = iterator.getLong(2);
250+
Assert.assertEquals(10, count);
251+
}
252+
253+
// WINDOW
254+
Assert.assertThrows(
255+
StatementExecutionException.class,
256+
() ->
257+
session.executeNonQueryStatement(
258+
"select *, nth_value(s8,2) over(partition by s8) from table1"));
259+
Assert.assertThrows(
260+
StatementExecutionException.class,
261+
() ->
262+
session.executeNonQueryStatement(
263+
"select *, nth_value(s8,2) over(order by s8) from table1"));
264+
session.executeNonQueryStatement(
265+
"select *, nth_value(s8,2) over(partition by device) from table1");
266+
session.executeNonQueryStatement(
267+
"select *, lead(s8) over(partition by device order by time) from table1");
268+
session.executeNonQueryStatement(
269+
"select *, first_value(s8) over(partition by device) from table1");
270+
session.executeNonQueryStatement(
271+
"select *, last_value(s8) over(partition by device) from table1");
272+
session.executeNonQueryStatement(
273+
"select *, lag(s8) over(partition by device order by time) from table1");
274+
275+
// Table-value function
276+
Assert.assertThrows(
277+
StatementExecutionException.class,
278+
() ->
279+
session.executeNonQueryStatement(
280+
"select * from session(data => table1 partition by s8, timecol => 'time', gap => 1ms)"));
281+
Assert.assertThrows(
282+
StatementExecutionException.class,
283+
() ->
284+
session.executeNonQueryStatement(
285+
"select * from session(data => table1 order by s8, timecol => 'time', gap => 1ms)"));
286+
sessionDataSet =
287+
session.executeQueryStatement(
288+
"select * from hop(data => table1, timecol => 'time', slide => 1ms, size => 2ms)");
289+
iterator = sessionDataSet.iterator();
290+
while (iterator.next()) {
291+
String str = iterator.getString("s8");
292+
Assert.assertEquals("(Object) 4 B", str);
293+
}
294+
}
295+
}
296+
}

integration-test/src/test/java/org/apache/iotdb/relational/it/query/old/builtinfunction/scalar/IoTDBScalarFunctionTableIT.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1370,56 +1370,56 @@ public void lengthTestFail() {
13701370
tableAssertTestFail(
13711371
"select s1,Length(s1,1) from lengthTable",
13721372
TSStatusCode.SEMANTIC_ERROR.getStatusCode()
1373-
+ ": Scalar function length only accepts one argument and it must be text, string, or blob data type.",
1373+
+ ": Scalar function length only accepts one argument and it must be text or string or blob or object data type.",
13741374
DATABASE_NAME);
13751375

13761376
// case 2: wrong data type
13771377
tableAssertTestFail(
13781378
"select s1,Length(s2) from lengthTable",
13791379
TSStatusCode.SEMANTIC_ERROR.getStatusCode()
1380-
+ ": Scalar function length only accepts one argument and it must be text, string, or blob data type.",
1380+
+ ": Scalar function length only accepts one argument and it must be text or string or blob or object data type.",
13811381
DATABASE_NAME);
13821382

13831383
// case 3: wrong data type
13841384
tableAssertTestFail(
13851385
"select s1,Length(s3) from lengthTable",
13861386
TSStatusCode.SEMANTIC_ERROR.getStatusCode()
1387-
+ ": Scalar function length only accepts one argument and it must be text, string, or blob data type.",
1387+
+ ": Scalar function length only accepts one argument and it must be text or string or blob or object data type.",
13881388
DATABASE_NAME);
13891389

13901390
// case 4: wrong data type
13911391
tableAssertTestFail(
13921392
"select s1,Length(s4) from lengthTable",
13931393
TSStatusCode.SEMANTIC_ERROR.getStatusCode()
1394-
+ ": Scalar function length only accepts one argument and it must be text, string, or blob data type.",
1394+
+ ": Scalar function length only accepts one argument and it must be text or string or blob or object data type.",
13951395
DATABASE_NAME);
13961396

13971397
// case 5: wrong data type
13981398
tableAssertTestFail(
13991399
"select s1,Length(s5) from lengthTable",
14001400
TSStatusCode.SEMANTIC_ERROR.getStatusCode()
1401-
+ ": Scalar function length only accepts one argument and it must be text, string, or blob data type.",
1401+
+ ": Scalar function length only accepts one argument and it must be text or string or blob or object data type.",
14021402
DATABASE_NAME);
14031403

14041404
// case 6: wrong data type
14051405
tableAssertTestFail(
14061406
"select s1,Length(s6) from lengthTable",
14071407
TSStatusCode.SEMANTIC_ERROR.getStatusCode()
1408-
+ ": Scalar function length only accepts one argument and it must be text, string, or blob data type.",
1408+
+ ": Scalar function length only accepts one argument and it must be text or string or blob or object data type.",
14091409
DATABASE_NAME);
14101410

14111411
// case 7: wrong data type
14121412
tableAssertTestFail(
14131413
"select s1,Length(s7) from lengthTable",
14141414
TSStatusCode.SEMANTIC_ERROR.getStatusCode()
1415-
+ ": Scalar function length only accepts one argument and it must be text, string, or blob data type.",
1415+
+ ": Scalar function length only accepts one argument and it must be text or string or blob or object data type.",
14161416
DATABASE_NAME);
14171417

14181418
// case 8: wrong data type
14191419
tableAssertTestFail(
14201420
"select s1,Length(s8) from lengthTable",
14211421
TSStatusCode.SEMANTIC_ERROR.getStatusCode()
1422-
+ ": Scalar function length only accepts one argument and it must be text, string, or blob data type.",
1422+
+ ": Scalar function length only accepts one argument and it must be text or string or blob or object data type.",
14231423
DATABASE_NAME);
14241424
}
14251425

integration-test/src/test/java/org/apache/iotdb/relational/it/query/recent/IoTDBLengthFunctionIT.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ public void testLengthOnBlob() {
107107
public void testLengthFunctionOnInvalidInputs() {
108108
String expectedErrorMessage =
109109
TSStatusCode.SEMANTIC_ERROR.getStatusCode()
110-
+ ": Scalar function length only accepts one argument and it must be text, string, or blob data type.";
110+
+ ": Scalar function length only accepts one argument and it must be text or string or blob or object data type.";
111111

112112
// Exception 1: Using LENGTH() on non-TEXT/BLOB/STRING types
113113
tableAssertTestFail("SELECT length(c_int) FROM table1", expectedErrorMessage, DATABASE_NAME);

0 commit comments

Comments
 (0)