diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBLoadTsFileIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBLoadTsFileIT.java index 928c7875b19ab..19a4214bed2f1 100644 --- a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBLoadTsFileIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBLoadTsFileIT.java @@ -1058,6 +1058,59 @@ public void testLoadLocally() throws Exception { } } + @Test + public void testLoadWithSameMeasurementNameDifferentDevice() throws Exception { + final String device = "root.sg.test_0.device_1"; + MeasurementSchema measurement = + new MeasurementSchema("temperature", TSDataType.DOUBLE, TSEncoding.GORILLA); + + final long writtenPoint1; + try (final TsFileGenerator generator = + new TsFileGenerator(new File(tmpDir, "same-measurement-1.tsfile"))) { + generator.registerTimeseries(device, Collections.singletonList(measurement)); + generator.generateData(device, 1000, PARTITION_INTERVAL, false); + writtenPoint1 = generator.getTotalNumber(); + } + + measurement = new MeasurementSchema("temperature", TSDataType.DOUBLE, TSEncoding.PLAIN); + final long writtenPoint2; + try (final TsFileGenerator generator = + new TsFileGenerator(new File(tmpDir, "same-measurement-2.tsfile"))) { + generator.registerTimeseries(device, Collections.singletonList(measurement)); + generator.generateData(device, 2000, PARTITION_INTERVAL / 10000, false); + writtenPoint2 = generator.getTotalNumber(); + } + + try (final Connection connection = EnvFactory.getEnv().getConnection(); + final Statement statement = connection.createStatement()) { + + statement.execute(String.format("load \"%s\" sglevel=2", tmpDir.getAbsolutePath())); + + try (final ResultSet resultSet = statement.executeQuery("select count(**) from root.sg.**")) { + if (resultSet.next()) { + final long sg1Count = resultSet.getLong("count(root.sg.test_0.device_1.temperature)"); + Assert.assertEquals(writtenPoint1 + writtenPoint2, sg1Count); + } else { + Assert.fail("This ResultSet is empty."); + } + } + + try (final ResultSet resultSet = statement.executeQuery("show timeseries root.sg.**")) { + int count = 0; + Set expectedPaths = new HashSet<>(); + expectedPaths.add(device + "." + measurement.getMeasurementName()); + while (resultSet.next()) { + String path = resultSet.getString(ColumnHeaderConstant.TIMESERIES); + Assert.assertTrue("Unexpected timeseries path: " + path, expectedPaths.contains(path)); + expectedPaths.remove(path); + count++; + } + Assert.assertEquals(1, count); + Assert.assertTrue("Not all expected timeseries found", expectedPaths.isEmpty()); + } + } + } + @Test @Ignore("Load with conversion is currently banned") public void testLoadWithConvertOnTypeMismatchForTreeModel() throws Exception { 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 c174bd7942b81..29d4f1be07b9e 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 @@ -252,17 +252,41 @@ private void handleException(Exception e, String statementString) throws Semanti } private void makeSureNoDuplicatedMeasurementsInDevices() throws LoadAnalyzeException { + boolean hasDuplicates = false; + final Map> deduplicatedDevice2TimeSeries = new HashMap<>(); + for (final Map.Entry> entry : schemaCache.getDevice2TimeSeries().entrySet()) { final IDeviceID device = entry.getKey(); final Map measurement2Schema = new HashMap<>(); + boolean deviceHasDuplicates = false; + for (final MeasurementSchema timeseriesSchema : entry.getValue()) { final String measurement = timeseriesSchema.getMeasurementName(); - if (measurement2Schema.containsKey(measurement)) { - throw new LoadAnalyzeException( - String.format("Duplicated measurements %s in device %s.", measurement, device)); + final MeasurementSchema existingSchema = measurement2Schema.get(measurement); + + if (existingSchema != null) { + if (existingSchema.getType() != timeseriesSchema.getType()) { + throw new LoadAnalyzeException( + String.format("Duplicated measurements %s in device %s.", measurement, device)); + } + deviceHasDuplicates = true; + hasDuplicates = true; + } else { + measurement2Schema.put(measurement, timeseriesSchema); } - measurement2Schema.put(measurement, timeseriesSchema); + } + + if (deviceHasDuplicates) { + deduplicatedDevice2TimeSeries.put(device, new HashSet<>(measurement2Schema.values())); + } + } + + if (hasDuplicates) { + Map> device2TimeSeries = schemaCache.getDevice2TimeSeries(); + for (final Map.Entry> entry : + deduplicatedDevice2TimeSeries.entrySet()) { + device2TimeSeries.put(entry.getKey(), new HashSet<>(entry.getValue())); } } }