This is an automated email from the ASF dual-hosted git repository. JackieTien97 pushed a commit to branch rc/2.0.10 in repository https://gitbox.apache.org/repos/asf/iotdb.git
commit 178fb90a75b0554fccc9dd82b64aa741cfbb2986 Author: Caideyipi <[email protected]> AuthorDate: Tue Jun 16 17:15:35 2026 +0800 Fix tree model load type mismatch conversion (#17949) * Fix tree load type mismatch conversion * Fix load-and-alter expected count --- .../db/it/schema/IoTDBAlterTimeSeriesTypeIT.java | 4 +- .../load/TreeSchemaAutoCreatorAndVerifier.java | 17 +++--- .../plan/analyze/load/LoadTsFileAnalyzerTest.java | 64 ++++++++++++++++++++++ 3 files changed, 75 insertions(+), 10 deletions(-) diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBAlterTimeSeriesTypeIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBAlterTimeSeriesTypeIT.java index fcde3f61e37..713b926d1af 100644 --- a/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBAlterTimeSeriesTypeIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBAlterTimeSeriesTypeIT.java @@ -879,8 +879,8 @@ public class IoTDBAlterTimeSeriesTypeIT { session.executeQueryStatement("select count(s1) from " + database + ".load_and_alter"); RowRecord rec; rec = dataSet.next(); - // Before alter, DOUBLE TsFiles loaded directly are invisible under the existing INT32 schema. - assertEquals(9, rec.getFields().get(0).getLongV()); + // Before alter, DOUBLE TsFiles are converted to INT32 and visible under the existing schema. + assertEquals(15, rec.getFields().get(0).getLongV()); assertFalse(dataSet.hasNext()); } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/load/TreeSchemaAutoCreatorAndVerifier.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/load/TreeSchemaAutoCreatorAndVerifier.java index bfebb7db0d7..d4f4210727e 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/load/TreeSchemaAutoCreatorAndVerifier.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/load/TreeSchemaAutoCreatorAndVerifier.java @@ -483,14 +483,15 @@ public class TreeSchemaAutoCreatorAndVerifier { } // check datatype - if (LOGGER.isDebugEnabled() && !tsFileSchema.getType().equals(iotdbSchema.getType())) { - LOGGER.debug( - "Measurement {}{}{} datatype not match, TsFile: {}, IoTDB: {}", - device, - TsFileConstant.PATH_SEPARATOR, - iotdbSchema.getMeasurementName(), - tsFileSchema.getType(), - iotdbSchema.getType()); + if (!tsFileSchema.getType().equals(iotdbSchema.getType())) { + throw new LoadAnalyzeTypeMismatchException( + String.format( + "Data type mismatch for measurement %s%s%s, type in TsFile: %s, type in IoTDB: %s", + device, + TsFileConstant.PATH_SEPARATOR, + iotdbSchema.getMeasurementName(), + tsFileSchema.getType(), + iotdbSchema.getType())); } // check encoding diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/analyze/load/LoadTsFileAnalyzerTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/analyze/load/LoadTsFileAnalyzerTest.java index 01406b0fd06..c533b0043e9 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/analyze/load/LoadTsFileAnalyzerTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/analyze/load/LoadTsFileAnalyzerTest.java @@ -19,6 +19,7 @@ package org.apache.iotdb.db.queryengine.plan.analyze.load; +import org.apache.iotdb.commons.path.PartialPath; import org.apache.iotdb.commons.queryengine.plan.relational.metadata.ColumnSchema; import org.apache.iotdb.commons.schema.table.column.TsTableColumnCategory; import org.apache.iotdb.db.conf.IoTDBDescriptor; @@ -26,7 +27,10 @@ import org.apache.iotdb.db.exception.load.LoadAnalyzeTypeMismatchException; import org.apache.iotdb.db.exception.load.LoadRuntimeOutOfMemoryException; import org.apache.iotdb.db.queryengine.common.MPPQueryContext; import org.apache.iotdb.db.queryengine.common.QueryId; +import org.apache.iotdb.db.queryengine.common.schematree.ClusterSchemaTree; +import org.apache.iotdb.db.queryengine.common.schematree.ISchemaTree; import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.LoadTsFile; +import org.apache.iotdb.db.queryengine.plan.statement.crud.LoadTsFileStatement; import org.apache.iotdb.db.storageengine.dataregion.tsfile.TsFileResource; import org.apache.tsfile.enums.ColumnCategory; @@ -149,6 +153,51 @@ public class LoadTsFileAnalyzerTest { } } + @Test + public void testTreeSchemaVerifierShouldThrowMismatchWhenVerifyingDataType() throws Exception { + final File tsFile = new File("load-tree-type-mismatch.tsfile"); + if (tsFile.exists()) { + Assert.assertTrue(tsFile.delete()); + } + Assert.assertTrue(tsFile.createNewFile()); + + try (final LoadTsFileAnalyzer analyzer = + new LoadTsFileAnalyzer( + LoadTsFileStatement.createUnchecked(tsFile.getAbsolutePath()), + false, + new MPPQueryContext(new QueryId("load_tree_test")))) { + final TreeSchemaAutoCreatorAndVerifier verifier = + new TreeSchemaAutoCreatorAndVerifier(analyzer); + try { + final IDeviceID device = IDeviceID.Factory.DEFAULT_FACTORY.create("root.sg.d1"); + final LoadTsFileTreeSchemaCache schemaCache = getTreeSchemaCache(verifier); + schemaCache.addTimeSeries(device, new MeasurementSchema("s1", TSDataType.BOOLEAN)); + schemaCache.addIsAlignedCache(device, true, true); + + final ClusterSchemaTree schemaTree = new ClusterSchemaTree(); + schemaTree.appendSingleMeasurement( + new PartialPath("root.sg.d1.s1"), + new MeasurementSchema("s1", TSDataType.INT32), + null, + null, + null, + true); + + final InvocationTargetException exception = + Assert.assertThrows( + InvocationTargetException.class, + () -> getVerifyTreeSchemaMethod().invoke(verifier, schemaTree)); + Assert.assertTrue(exception.getCause() instanceof LoadAnalyzeTypeMismatchException); + } finally { + verifier.close(); + } + } finally { + if (tsFile.exists()) { + Assert.assertTrue(tsFile.delete()); + } + } + } + private void writeTableTsFileWithMixedDevices(final File tsFile) throws Exception { if (tsFile.exists()) { Assert.assertTrue(tsFile.delete()); @@ -203,6 +252,14 @@ public class LoadTsFileAnalyzerTest { tableSchemaCacheField.set(analyzer, schemaCache); } + private LoadTsFileTreeSchemaCache getTreeSchemaCache( + final TreeSchemaAutoCreatorAndVerifier verifier) throws Exception { + final Field schemaCacheField = + TreeSchemaAutoCreatorAndVerifier.class.getDeclaredField("schemaCache"); + schemaCacheField.setAccessible(true); + return (LoadTsFileTreeSchemaCache) schemaCacheField.get(verifier); + } + private LoadTsFileTableSchemaCache createTableSchemaCache(final boolean shouldVerifyDataType) throws LoadRuntimeOutOfMemoryException { return new LoadTsFileTableSchemaCache( @@ -219,6 +276,13 @@ public class LoadTsFileAnalyzerTest { return method; } + private Method getVerifyTreeSchemaMethod() throws NoSuchMethodException { + final Method method = + TreeSchemaAutoCreatorAndVerifier.class.getDeclaredMethod("verifySchema", ISchemaTree.class); + method.setAccessible(true); + return method; + } + private org.apache.iotdb.commons.queryengine.plan.relational.metadata.TableSchema createTableSchema(final TSDataType fieldType) { return new org.apache.iotdb.commons.queryengine.plan.relational.metadata.TableSchema(
