This is an automated email from the ASF dual-hosted git repository.
jt2594838 pushed a commit to branch remove_swtich_type
in repository https://gitbox.apache.org/repos/asf/iotdb.git
The following commit(s) were added to refs/heads/remove_swtich_type by this
push:
new a6aacb1e643 multiple refactors
a6aacb1e643 is described below
commit a6aacb1e643c7ade28ac62784dd388d8cd3d2b92
Author: Tian Jiang <[email protected]>
AuthorDate: Tue Sep 8 11:22:28 2026 +0800
multiple refactors
---
.../java/org/apache/iotdb/udf/api/access/Row.java | 7 +-
.../org/apache/iotdb/udf/api/utils/RowImpl.java | 2 +-
...ializableRowRecordListBackedMultiColumnRow.java | 2 +-
.../dag/adapter/RowGetDoubleTest.java | 98 ++++++++++++++++++++++
.../iotdb/commons/udf/utils/MasterRepairUtil.java | 32 ++-----
.../commons/udf/utils/MasterRepairUtilTest.java | 94 +++++++++++++++++++++
6 files changed, 207 insertions(+), 28 deletions(-)
diff --git
a/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/access/Row.java
b/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/access/Row.java
index e2dc13a39ab..c1b466786cd 100644
--- a/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/access/Row.java
+++ b/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/access/Row.java
@@ -68,10 +68,11 @@ public interface Row {
float getFloat(int columnIndex) throws IOException;
/**
- * Returns the double value at the specified column in this row.
+ * Returns the numeric value at the specified column in this row as a double.
*
- * <p>Users need to ensure that the data type of the specified column is
{@code
- * TSDataType.DOUBLE}.
+ * <p>Users need to ensure that the data type of the specified column is
{@code TSDataType.INT32},
+ * {@code TSDataType.INT64}, {@code TSDataType.FLOAT}, or {@code
TSDataType.DOUBLE}, and that the
+ * value is not null. INT64 values may lose precision when converted to
double.
*
* @param columnIndex index of the specified column
* @return the double value at the specified column in this row
diff --git
a/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/utils/RowImpl.java
b/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/utils/RowImpl.java
index 10b7dc7417d..4033ff9ac76 100644
---
a/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/utils/RowImpl.java
+++
b/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/utils/RowImpl.java
@@ -73,7 +73,7 @@ public class RowImpl implements Row {
if (columnIndex >= size()) {
throw new IndexOutOfBoundsException(UdfApiMessages.INDEX_OUT_OF_BOUND);
}
- return (double) rowRecord[columnIndex];
+ return ((Number) rowRecord[columnIndex]).doubleValue();
}
@Override
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/transformation/dag/adapter/ElasticSerializableRowRecordListBackedMultiColumnRow.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/transformation/dag/adapter/ElasticSerializableRowRecordListBackedMultiColumnRow.java
index 6f42b95a6ac..e2f16d6f748 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/transformation/dag/adapter/ElasticSerializableRowRecordListBackedMultiColumnRow.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/transformation/dag/adapter/ElasticSerializableRowRecordListBackedMultiColumnRow.java
@@ -62,7 +62,7 @@ public class
ElasticSerializableRowRecordListBackedMultiColumnRow implements Row
@Override
public double getDouble(int columnIndex) {
- return (double) rowRecord[columnIndex];
+ return ((Number) rowRecord[columnIndex]).doubleValue();
}
@Override
diff --git
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/transformation/dag/adapter/RowGetDoubleTest.java
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/transformation/dag/adapter/RowGetDoubleTest.java
new file mode 100644
index 00000000000..26d88281257
--- /dev/null
+++
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/transformation/dag/adapter/RowGetDoubleTest.java
@@ -0,0 +1,98 @@
+/*
+ * 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.db.queryengine.transformation.dag.adapter;
+
+import org.apache.iotdb.udf.api.access.Row;
+import org.apache.iotdb.udf.api.utils.RowImpl;
+
+import org.apache.tsfile.enums.TSDataType;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+
+public class RowGetDoubleTest {
+
+ @Test
+ public void testNumericConversion() throws IOException {
+ // Both Object[] implementations must widen all four numeric types,
including large longs.
+ for (Row row :
+ createRows(
+ new TSDataType[] {
+ TSDataType.INT32, TSDataType.INT64, TSDataType.FLOAT,
TSDataType.DOUBLE
+ },
+ new Object[] {Integer.MIN_VALUE, Long.MAX_VALUE, 0.1f, -1.25d,
123L})) {
+ assertEquals((double) Integer.MIN_VALUE, row.getDouble(0), 0d);
+ assertEquals((double) Long.MAX_VALUE, row.getDouble(1), 0d);
+ assertEquals((double) 0.1f, row.getDouble(2), 0d);
+ assertEquals(-1.25d, row.getDouble(3), 0d);
+ assertEquals(123L, row.getTime());
+ assertEquals(4, row.size());
+ }
+ }
+
+ @Test
+ public void testSpecialFloatingPointValues() throws IOException {
+ // Widening must preserve NaN, infinities, and the sign of zero.
+ for (Row row :
+ createRows(
+ new TSDataType[] {
+ TSDataType.FLOAT, TSDataType.FLOAT, TSDataType.DOUBLE,
TSDataType.DOUBLE
+ },
+ new Object[] {
+ Float.NaN, Float.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY,
-0.0d, 123L
+ })) {
+ assertTrue(Double.isNaN(row.getDouble(0)));
+ assertEquals(Double.POSITIVE_INFINITY, row.getDouble(1), 0d);
+ assertEquals(Double.NEGATIVE_INFINITY, row.getDouble(2), 0d);
+ assertEquals(Double.doubleToLongBits(-0.0d),
Double.doubleToLongBits(row.getDouble(3)));
+ }
+ }
+
+ @Test
+ public void testInvalidReads() throws IOException {
+ // Null, nonnumeric values, and invalid array indices retain their failure
behavior.
+ for (Row row :
+ createRows(
+ new TSDataType[] {TSDataType.DOUBLE, TSDataType.BOOLEAN},
+ new Object[] {null, true, 123L})) {
+ assertTrue(row.isNull(0));
+ assertThrows(NullPointerException.class, () -> row.getDouble(0));
+ assertThrows(ClassCastException.class, () -> row.getDouble(1));
+ assertThrows(IndexOutOfBoundsException.class, () -> row.getDouble(-1));
+ assertThrows(IndexOutOfBoundsException.class, () -> row.getDouble(3));
+ }
+ }
+
+ private List<Row> createRows(TSDataType[] types, Object[] values) {
+ // RowImpl includes the trailing timestamp in its schema; the adapter does
not.
+ TSDataType[] typesWithTime = Arrays.copyOf(types, types.length + 1);
+ typesWithTime[types.length] = TSDataType.TIMESTAMP;
+ RowImpl row = new RowImpl(typesWithTime);
+ row.setRowRecord(values);
+ return Arrays.asList(
+ row, new
ElasticSerializableRowRecordListBackedMultiColumnRow(types).setRowRecord(values));
+ }
+}
diff --git
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/udf/utils/MasterRepairUtil.java
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/udf/utils/MasterRepairUtil.java
index 79d5381f45d..5a9fe141fe1 100644
---
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/udf/utils/MasterRepairUtil.java
+++
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/udf/utils/MasterRepairUtil.java
@@ -20,13 +20,18 @@ package org.apache.iotdb.commons.udf.utils;
import org.apache.iotdb.commons.i18n.CommonMessages;
import org.apache.iotdb.udf.api.access.Row;
+import org.apache.iotdb.udf.api.type.Type;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.EnumSet;
+import java.util.Set;
public class MasterRepairUtil {
+ private static final Set<Type> NUMERIC_TYPES =
+ EnumSet.of(Type.INT32, Type.INT64, Type.FLOAT, Type.DOUBLE);
private final ArrayList<ArrayList<Double>> td = new ArrayList<>();
private final ArrayList<ArrayList<Double>> tdCleaned = new ArrayList<>();
private final ArrayList<ArrayList<Double>> md = new ArrayList<>();
@@ -90,34 +95,15 @@ public class MasterRepairUtil {
}
public static double getValueAsDouble(Row row, int index) throws Exception {
- double ans;
try {
- switch (row.getDataType(index)) {
- case INT32:
- ans = row.getInt(index);
- break;
- case INT64:
- ans = row.getLong(index);
- break;
- case FLOAT:
- ans = row.getFloat(index);
- break;
- case DOUBLE:
- ans = row.getDouble(index);
- break;
- case DATE:
- case BLOB:
- case STRING:
- case TIMESTAMP:
- case BOOLEAN:
- case TEXT:
- default:
- throw new Exception(CommonMessages.VALUE_NOT_NUMERIC);
+ // DATE and TIMESTAMP have numeric storage but are not repairable
numeric measurements.
+ if (!NUMERIC_TYPES.contains(row.getDataType(index))) {
+ throw new Exception(CommonMessages.VALUE_NOT_NUMERIC);
}
+ return row.getDouble(index);
} catch (IOException e) {
throw new Exception(CommonMessages.FAIL_TO_GET_DATA_TYPE_IN_ROW +
row.getTime(), e);
}
- return ans;
}
public void buildKDTree() {
diff --git
a/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/udf/utils/MasterRepairUtilTest.java
b/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/udf/utils/MasterRepairUtilTest.java
new file mode 100644
index 00000000000..45e8eeefe48
--- /dev/null
+++
b/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/udf/utils/MasterRepairUtilTest.java
@@ -0,0 +1,94 @@
+/*
+ * 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.commons.udf.utils;
+
+import org.apache.iotdb.commons.i18n.CommonMessages;
+import org.apache.iotdb.udf.api.access.Row;
+import org.apache.iotdb.udf.api.type.Type;
+import org.apache.iotdb.udf.api.utils.RowImpl;
+
+import org.apache.tsfile.enums.TSDataType;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.EnumSet;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertThrows;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class MasterRepairUtilTest {
+
+ @Test
+ public void testNumericValues() throws Exception {
+ // Use real boxed values to catch casts to Double and exercise nonzero
column indices.
+ RowImpl row =
+ new RowImpl(
+ new TSDataType[] {
+ TSDataType.INT32,
+ TSDataType.INT64,
+ TSDataType.FLOAT,
+ TSDataType.DOUBLE,
+ TSDataType.TIMESTAMP
+ });
+ row.setRowRecord(new Object[] {-42, Long.MAX_VALUE, 0.1f, -1.25d, 123L});
+
+ assertEquals(-42d, MasterRepairUtil.getValueAsDouble(row, 0), 0d);
+ assertEquals((double) Long.MAX_VALUE,
MasterRepairUtil.getValueAsDouble(row, 1), 0d);
+ assertEquals((double) 0.1f, MasterRepairUtil.getValueAsDouble(row, 2), 0d);
+ assertEquals(-1.25d, MasterRepairUtil.getValueAsDouble(row, 3), 0d);
+ }
+
+ @Test
+ public void testRejectNonNumericTypes() throws Exception {
+ // In particular, DATE and TIMESTAMP must not become valid repair
measurements.
+ for (Type type :
+ EnumSet.complementOf(EnumSet.of(Type.INT32, Type.INT64, Type.FLOAT,
Type.DOUBLE))) {
+ Row row = mock(Row.class);
+ when(row.getDataType(1)).thenReturn(type);
+
+ Exception exception =
+ assertThrows(Exception.class, () ->
MasterRepairUtil.getValueAsDouble(row, 1));
+
+ assertEquals(CommonMessages.VALUE_NOT_NUMERIC, exception.getMessage());
+ verify(row, never()).getDouble(1);
+ }
+ }
+
+ @Test
+ public void testWrapIOException() throws Exception {
+ // A failed value read must retain the original cause and row timestamp in
the message.
+ Row row = mock(Row.class);
+ IOException cause = new IOException("test read failure");
+ when(row.getDataType(1)).thenReturn(Type.INT32);
+ when(row.getDouble(1)).thenThrow(cause);
+ when(row.getTime()).thenReturn(123L);
+
+ Exception exception =
+ assertThrows(Exception.class, () ->
MasterRepairUtil.getValueAsDouble(row, 1));
+
+ assertSame(cause, exception.getCause());
+ assertEquals(CommonMessages.FAIL_TO_GET_DATA_TYPE_IN_ROW + 123L,
exception.getMessage());
+ }
+}