This is an automated email from the ASF dual-hosted git repository. jackietien pushed a commit to branch force_ci/object_type in repository https://gitbox.apache.org/repos/asf/iotdb.git
commit 7a62fadd265bd1a87960bebb75d54e3ee6b220a5 Author: JackieTien97 <[email protected]> AuthorDate: Wed Nov 26 20:26:20 2025 +0800 Add IT for session and jdbc query --- .../iotdb/itbase/runtime/ClusterTestResultSet.java | 16 +- .../it/query/object/IoTDBObjectQueryIT.java | 186 +++++++++++++++++++++ .../org/apache/iotdb/jdbc/IoTDBJDBCResultSet.java | 2 +- .../relational/ColumnTransformerBuilder.java | 7 +- 4 files changed, 202 insertions(+), 9 deletions(-) diff --git a/integration-test/src/main/java/org/apache/iotdb/itbase/runtime/ClusterTestResultSet.java b/integration-test/src/main/java/org/apache/iotdb/itbase/runtime/ClusterTestResultSet.java index e98ff7e7c14..64c18db11a8 100644 --- a/integration-test/src/main/java/org/apache/iotdb/itbase/runtime/ClusterTestResultSet.java +++ b/integration-test/src/main/java/org/apache/iotdb/itbase/runtime/ClusterTestResultSet.java @@ -781,8 +781,12 @@ public class ClusterTestResultSet implements ResultSet { } @Override - public Blob getBlob(int columnIndex) { - throw new UnsupportedOperationException(); + public Blob getBlob(int columnIndex) throws SQLException { + RequestDelegate<Blob> delegate = createLocalRequestDelegate(); + for (ResultSet rs : resultSets) { + delegate.addRequest(() -> rs.getBlob(columnIndex)); + } + return delegate.requestAllAndCompare(); } @Override @@ -806,8 +810,12 @@ public class ClusterTestResultSet implements ResultSet { } @Override - public Blob getBlob(String columnLabel) { - throw new UnsupportedOperationException(); + public Blob getBlob(String columnLabel) throws SQLException { + RequestDelegate<Blob> delegate = createLocalRequestDelegate(); + for (ResultSet rs : resultSets) { + delegate.addRequest(() -> rs.getBlob(columnLabel)); + } + return delegate.requestAllAndCompare(); } @Override diff --git a/integration-test/src/test/java/org/apache/iotdb/relational/it/query/object/IoTDBObjectQueryIT.java b/integration-test/src/test/java/org/apache/iotdb/relational/it/query/object/IoTDBObjectQueryIT.java new file mode 100644 index 00000000000..4fad2d2696b --- /dev/null +++ b/integration-test/src/test/java/org/apache/iotdb/relational/it/query/object/IoTDBObjectQueryIT.java @@ -0,0 +1,186 @@ +/* + * 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.relational.it.query.object; + +import org.apache.iotdb.isession.ITableSession; +import org.apache.iotdb.isession.SessionConfig; +import org.apache.iotdb.isession.SessionDataSet; +import org.apache.iotdb.it.env.EnvFactory; +import org.apache.iotdb.it.framework.IoTDBTestRunner; +import org.apache.iotdb.itbase.category.TableClusterIT; +import org.apache.iotdb.itbase.category.TableLocalStandaloneIT; +import org.apache.iotdb.itbase.env.BaseEnv; +import org.apache.iotdb.rpc.IoTDBConnectionException; +import org.apache.iotdb.rpc.StatementExecutionException; + +import org.apache.tsfile.enums.TSDataType; +import org.apache.tsfile.read.common.Field; +import org.apache.tsfile.read.common.RowRecord; +import org.apache.tsfile.utils.Binary; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runner.RunWith; + +import java.sql.Blob; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +import static org.apache.iotdb.db.it.utils.TestUtils.prepareTableData; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +@RunWith(IoTDBTestRunner.class) +@Category({TableLocalStandaloneIT.class, TableClusterIT.class}) +public class IoTDBObjectQueryIT { + + private static final String DATABASE_NAME = "test_db"; + + private static final String TIME_ZONE = "+00:00"; + + private static final String[] createSqls = + new String[] { + "CREATE DATABASE " + DATABASE_NAME, + "USE " + DATABASE_NAME, + "CREATE TABLE t1(device_id STRING TAG, o1 OBJECT, b1 BLOB, s1 STRING)", + "INSERT INTO t1(time, device_id, b1, o1, s1) VALUES(1, 'd1', X'cafebabe01', to_object(true, 0, X'cafebabe01'), 'cafebabe01')", + "INSERT INTO t1(time, device_id, b1, o1, s1) VALUES(2, 'd1', X'cafebabe0202', to_object(true, 0, X'cafebabe02'), 'cafebabe02')", + "INSERT INTO t1(time, device_id, b1, o1, s1) VALUES(3, 'd1', X'cafebabe0303', to_object(true, 0, X'cafebabe03'), 'cafebabe03')", + "INSERT INTO t1(time, device_id, b1, o1, s1) VALUES(4, 'd1', X'cafebabe04', to_object(true, 0, X'cafebabe04'), 'cafebabe04')", + "INSERT INTO t1(time, device_id, b1, o1, s1) VALUES(1, 'd2', X'cafebade01', to_object(true, 0, X'cafebade01'), 'cafebade01')", + "INSERT INTO t1(time, device_id, b1, o1, s1) VALUES(2, 'd2', X'cafebade0202', to_object(true, 0, X'cafebade02'), 'cafebade02')", + "INSERT INTO t1(time, device_id, b1, o1, s1) VALUES(3, 'd2', X'cafebade0302', to_object(true, 0, X'cafebade03'), 'cafebade03')", + "INSERT INTO t1(time, device_id, b1, o1, s1) VALUES(4, 'd2', X'cafebade04', to_object(true, 0, X'cafebade04'), 'cafebade04')", + "FLUSH", + }; + + @BeforeClass + public static void classSetUp() { + EnvFactory.getEnv().initClusterEnvironment(); + prepareTableData(createSqls); + } + + @AfterClass + public static void classTearDown() { + EnvFactory.getEnv().cleanClusterEnvironment(); + } + + @Test + public void jdbcTest() { + try (Connection connection = + EnvFactory.getEnv() + .getConnection( + SessionConfig.DEFAULT_USER, + SessionConfig.DEFAULT_PASSWORD, + BaseEnv.TABLE_SQL_DIALECT)) { + connection.setClientInfo("time_zone", TIME_ZONE); + try (Statement statement = connection.createStatement()) { + statement.execute("use " + DATABASE_NAME); + try (ResultSet resultSet = + statement.executeQuery( + "SELECT time, b1, o1, s1 FROM t1 WHERE device_id = 'd1' ORDER BY time")) { + int cnt = 0; + while (resultSet.next()) { + cnt++; + Blob blob = resultSet.getBlob(3); + byte[] bytes = resultSet.getBytes("o1"); + assertArrayEquals(blob.getBytes(1, (int) blob.length()), bytes); + assertTrue(new String(bytes).endsWith(String.format("%d.bin", cnt))); + String s = resultSet.getString(3); + assertEquals("(Object) 5 B", s); + } + assertEquals(4, cnt); + } + + try (ResultSet resultSet = + statement.executeQuery( + "SELECT time, b1, READ_OBJECT(o1), s1 FROM t1 WHERE device_id = 'd2' AND READ_OBJECT(o1)=b1 ORDER BY time")) { + int cnt = 0; + String[] ans = {"0xcafebade01", "0xcafebade04"}; + while (resultSet.next()) { + String s = resultSet.getString(3); + assertEquals(ans[cnt], s); + cnt++; + } + assertEquals(2, cnt); + } + } + } catch (SQLException e) { + e.printStackTrace(); + fail(e.getMessage()); + } + } + + @Test + public void sessionTest() { + try (ITableSession session = EnvFactory.getEnv().getTableSessionConnection()) { + session.executeNonQueryStatement("USE " + DATABASE_NAME); + + // SessionDataSet + try (SessionDataSet dataSet = + session.executeQueryStatement( + "SELECT time, b1, o1, s1 FROM t1 WHERE device_id = 'd1' ORDER BY time")) { + int cnt = 0; + while (dataSet.hasNext()) { + cnt++; + RowRecord rowRecord = dataSet.next(); + Field field = rowRecord.getField(2); + String s = field.getStringValue(); + assertEquals("(Object) 5 B", s); + Object blob = field.getObjectValue(TSDataType.OBJECT); + assertTrue(blob instanceof Binary); + assertTrue( + new String(((Binary) blob).getValues()).endsWith(String.format("%d.bin", cnt))); + + Binary binary = field.getBinaryV(); + assertArrayEquals(binary.getValues(), ((Binary) blob).getValues()); + assertTrue(new String(binary.getValues()).endsWith(String.format("%d.bin", cnt))); + } + assertEquals(4, cnt); + } + + // SessionDataSet.DataIterator + try (SessionDataSet dataSet = + session.executeQueryStatement( + "SELECT time, b1, o1, s1 FROM t1 WHERE device_id = 'd2' ORDER BY time")) { + SessionDataSet.DataIterator iterator = dataSet.iterator(); + int cnt = 0; + while (iterator.next()) { + cnt++; + Object o = iterator.getObject(3); + assertTrue(o instanceof String); + assertEquals("(Object) 5 B", o); + String s = iterator.getString("o1"); + assertEquals("(Object) 5 B", s); + Binary blob = iterator.getBlob(3); + assertTrue(new String(blob.getValues()).endsWith(String.format("%d.bin", cnt))); + } + assertEquals(4, cnt); + } + } catch (IoTDBConnectionException | StatementExecutionException e) { + fail(e.getMessage()); + } + } +} diff --git a/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBJDBCResultSet.java b/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBJDBCResultSet.java index 77ae98d4887..ff00e3b35df 100644 --- a/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBJDBCResultSet.java +++ b/iotdb-client/jdbc/src/main/java/org/apache/iotdb/jdbc/IoTDBJDBCResultSet.java @@ -380,7 +380,7 @@ public class IoTDBJDBCResultSet implements ResultSet { return null; } - if (dataType.equals(TSDataType.BLOB)) { + if (dataType.equals(TSDataType.BLOB) || dataType.equals(TSDataType.OBJECT)) { Binary binary = ioTDBRpcDataSet.getBinary(columnName); return binary == null ? null : binary.getValues(); } else { diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/relational/ColumnTransformerBuilder.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/relational/ColumnTransformerBuilder.java index 0378c80f042..8f2c82d6f1c 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/relational/ColumnTransformerBuilder.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/relational/ColumnTransformerBuilder.java @@ -243,7 +243,6 @@ import static org.apache.tsfile.read.common.type.DoubleType.DOUBLE; import static org.apache.tsfile.read.common.type.FloatType.FLOAT; import static org.apache.tsfile.read.common.type.IntType.INT32; import static org.apache.tsfile.read.common.type.LongType.INT64; -import static org.apache.tsfile.read.common.type.ObjectType.OBJECT; import static org.apache.tsfile.read.common.type.StringType.STRING; public class ColumnTransformerBuilder @@ -1456,10 +1455,10 @@ public class ColumnTransformerBuilder .equalsIgnoreCase(functionName)) { ColumnTransformer first = this.process(children.get(0), context); if (children.size() == 1) { - return new ReadObjectColumnTransformer(OBJECT, first, context.fragmentInstanceContext); + return new ReadObjectColumnTransformer(BLOB, first, context.fragmentInstanceContext); } else if (children.size() == 2) { return new ReadObjectColumnTransformer( - OBJECT, + BLOB, ((LongLiteral) children.get(1)).getParsedValue(), first, context.fragmentInstanceContext); @@ -1468,7 +1467,7 @@ public class ColumnTransformerBuilder long length = ((LongLiteral) children.get(2)).getParsedValue(); checkArgument(offset >= 0 && length >= 0); return new ReadObjectColumnTransformer( - OBJECT, + BLOB, ((LongLiteral) children.get(1)).getParsedValue(), ((LongLiteral) children.get(2)).getParsedValue(), first,
