From 509b40ed0106f617163be8ac91b62a310ee327b9 Mon Sep 17 00:00:00 2001 From: luoluoyuyu Date: Fri, 7 Aug 2026 11:02:11 +0800 Subject: [PATCH 1/7] fix: validate internal tsfile paths for files only --- .../plan/statement/crud/LoadTsFileStatement.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/crud/LoadTsFileStatement.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/crud/LoadTsFileStatement.java index 0b0dea763112..dbb5b1232511 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/crud/LoadTsFileStatement.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/crud/LoadTsFileStatement.java @@ -129,15 +129,15 @@ private static List processTsFile( throws FileNotFoundException { final Path[] internalDataDirCanonicalPaths = IoTDBDescriptor.getInstance().getConfig().getInternalDataDirCanonicalPaths(); - if (validateInternalDataDir) { - validateNotLoadingInternalTsFile(file, internalDataDirCanonicalPaths); - } if (validateSourcePath) { validateLoadSourcePath(file); } final List tsFiles = new ArrayList<>(); if (file.isFile()) { + if (validateInternalDataDir) { + validateNotLoadingInternalTsFile(file, internalDataDirCanonicalPaths); + } tsFiles.add(file); } else { if (file.listFiles() == null) { From c7557a762854ec890c760c07e6979b66f38e3fff Mon Sep 17 00:00:00 2001 From: luoluoyuyu Date: Fri, 7 Aug 2026 11:11:43 +0800 Subject: [PATCH 2/7] test: cover loading internal data directories --- .../crud/LoadTsFileStatementTest.java | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/statement/crud/LoadTsFileStatementTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/statement/crud/LoadTsFileStatementTest.java index fac3227f4b5e..a0674a30a527 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/statement/crud/LoadTsFileStatementTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/statement/crud/LoadTsFileStatementTest.java @@ -144,6 +144,55 @@ public void testLoadInternalTsFileIsRejectedWithoutLeakingPath() throws Exceptio } } + @Test + public void testLoadEmptyInternalDataDirDoesNotThrow() throws Exception { + final IoTDBConfig config = IoTDBDescriptor.getInstance().getConfig(); + final String[][] originalTierDataDirs = config.getTierDataDirs(); + final boolean originalCheckEnabled = config.isLoadTsFileSourcePathCheckEnabled(); + final Path dataNodeDir = Files.createTempDirectory("load-tsfile-datanode"); + final Path dataDir = Files.createDirectories(dataNodeDir.resolve("data")); + + try { + config.setTierDataDirs(new String[][] {{dataDir.toString()}}); + config.setLoadTsFileSourcePathCheckEnabled(false); + + final LoadTsFileStatement statement = new LoadTsFileStatement(dataDir.toString()); + Assert.assertTrue(statement.getTsFiles().isEmpty()); + } finally { + config.setTierDataDirs(originalTierDataDirs); + config.setLoadTsFileSourcePathCheckEnabled(originalCheckEnabled); + deleteRecursively(dataNodeDir); + } + } + + @Test + public void testLoadNonEmptyInternalDataDirIsRejected() throws Exception { + final IoTDBConfig config = IoTDBDescriptor.getInstance().getConfig(); + final String[][] originalTierDataDirs = config.getTierDataDirs(); + final boolean originalCheckEnabled = config.isLoadTsFileSourcePathCheckEnabled(); + final Path dataNodeDir = Files.createTempDirectory("load-tsfile-datanode"); + final Path dataDir = Files.createDirectories(dataNodeDir.resolve("data")); + Files.createFile(dataDir.resolve("a.tsfile")); + + try { + config.setTierDataDirs(new String[][] {{dataDir.toString()}}); + config.setLoadTsFileSourcePathCheckEnabled(false); + + try { + new LoadTsFileStatement(dataDir.toString()); + Assert.fail("Expected non-empty internal IoTDB data directory to be rejected."); + } catch (final FileNotFoundException e) { + Assert.assertEquals( + "Cannot load files because the specified directory contains IoTDB data.", + e.getMessage()); + } + } finally { + config.setTierDataDirs(originalTierDataDirs); + config.setLoadTsFileSourcePathCheckEnabled(originalCheckEnabled); + deleteRecursively(dataNodeDir); + } + } + @Test public void testLoadPipeReceiverTsFileOutsideDataDirIsAllowed() throws Exception { final IoTDBConfig config = IoTDBDescriptor.getInstance().getConfig(); From 5d8bfd9ee5065cd00023a94ed609a21d2728ff73 Mon Sep 17 00:00:00 2001 From: luoluoyuyu Date: Fri, 7 Aug 2026 11:13:33 +0800 Subject: [PATCH 3/7] test: cover empty and non-empty internal data directories --- .../plan/statement/crud/LoadTsFileStatement.java | 8 ++++++++ .../plan/statement/crud/LoadTsFileStatementTest.java | 10 +++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/crud/LoadTsFileStatement.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/crud/LoadTsFileStatement.java index dbb5b1232511..40faa2083cda 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/crud/LoadTsFileStatement.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/crud/LoadTsFileStatement.java @@ -151,6 +151,14 @@ private static List processTsFile( findAllTsFile( file, validateSourcePath, validateInternalDataDir, internalDataDirCanonicalPaths)); } + if (tsFiles.isEmpty()) { + throw new FileNotFoundException( + String.format( + DataNodeQueryMessages + .QUERY_EXCEPTION_CAN_NOT_FIND_S_ON_THIS_MACHINE_NOTICE_THAT_LOAD_CAN_ONLY_B7886C0E, + file.getPath())); + } + sortTsFiles(tsFiles); return tsFiles; } diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/statement/crud/LoadTsFileStatementTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/statement/crud/LoadTsFileStatementTest.java index a0674a30a527..1e7e2a3df40e 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/statement/crud/LoadTsFileStatementTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/statement/crud/LoadTsFileStatementTest.java @@ -145,7 +145,7 @@ public void testLoadInternalTsFileIsRejectedWithoutLeakingPath() throws Exceptio } @Test - public void testLoadEmptyInternalDataDirDoesNotThrow() throws Exception { + public void testLoadEmptyInternalDataDirIsRejected() throws Exception { final IoTDBConfig config = IoTDBDescriptor.getInstance().getConfig(); final String[][] originalTierDataDirs = config.getTierDataDirs(); final boolean originalCheckEnabled = config.isLoadTsFileSourcePathCheckEnabled(); @@ -156,8 +156,12 @@ public void testLoadEmptyInternalDataDirDoesNotThrow() throws Exception { config.setTierDataDirs(new String[][] {{dataDir.toString()}}); config.setLoadTsFileSourcePathCheckEnabled(false); - final LoadTsFileStatement statement = new LoadTsFileStatement(dataDir.toString()); - Assert.assertTrue(statement.getTsFiles().isEmpty()); + try { + new LoadTsFileStatement(dataDir.toString()); + Assert.fail("Expected empty internal IoTDB data directory to be rejected."); + } catch (final FileNotFoundException e) { + Assert.assertTrue(e.getMessage().contains("Can not find")); + } } finally { config.setTierDataDirs(originalTierDataDirs); config.setLoadTsFileSourcePathCheckEnabled(originalCheckEnabled); From e376fe0c2675d2497a50acd18e32cdb3a39d25e3 Mon Sep 17 00:00:00 2001 From: luoluoyuyu Date: Fri, 7 Aug 2026 11:26:26 +0800 Subject: [PATCH 4/7] fix: reject empty load tsfile paths --- .../iotdb/db/i18n/DataNodeQueryMessages.java | 2 ++ .../iotdb/db/i18n/DataNodeQueryMessages.java | 2 ++ .../statement/crud/LoadTsFileStatement.java | 12 ++++------- .../crud/LoadTsFileStatementTest.java | 20 ++++++++++++------- 4 files changed, 21 insertions(+), 15 deletions(-) diff --git a/iotdb-core/datanode/src/main/i18n/en/org/apache/iotdb/db/i18n/DataNodeQueryMessages.java b/iotdb-core/datanode/src/main/i18n/en/org/apache/iotdb/db/i18n/DataNodeQueryMessages.java index 0e9e8158ac7b..18d7795940c5 100644 --- a/iotdb-core/datanode/src/main/i18n/en/org/apache/iotdb/db/i18n/DataNodeQueryMessages.java +++ b/iotdb-core/datanode/src/main/i18n/en/org/apache/iotdb/db/i18n/DataNodeQueryMessages.java @@ -3677,6 +3677,8 @@ private DataNodeQueryMessages() {} public static final String EXCEPTION_UDFNAME_IS_NULL_83E9039B = "udfName is null"; public static final String EXCEPTION_URISTRING_IS_NULL_E7458C6A = "uriString is null"; public static final String EXCEPTION_FILEPATH_IS_NULL_84CE8A66 = "filePath is null"; + public static final String EXCEPTION_LOAD_TSFILE_PATH_CANNOT_BE_EMPTY_2B106181 = + "The LOAD TSFILE path cannot be empty."; public static final String EXCEPTION_DETAILS_IS_NULL_8EDEEA03 = "details is null"; public static final String EXCEPTION_COLUMNCATEGORY_IS_NULL_0075924B = "columnCategory is null"; public static final String EXCEPTION_ARGUMENTNAME_IS_NULL_7F8F665F = "argumentName is null"; diff --git a/iotdb-core/datanode/src/main/i18n/zh/org/apache/iotdb/db/i18n/DataNodeQueryMessages.java b/iotdb-core/datanode/src/main/i18n/zh/org/apache/iotdb/db/i18n/DataNodeQueryMessages.java index 1ab922fa121c..0864c4adbc9b 100644 --- a/iotdb-core/datanode/src/main/i18n/zh/org/apache/iotdb/db/i18n/DataNodeQueryMessages.java +++ b/iotdb-core/datanode/src/main/i18n/zh/org/apache/iotdb/db/i18n/DataNodeQueryMessages.java @@ -4420,6 +4420,8 @@ private DataNodeQueryMessages() {} public static final String EXCEPTION_UDFNAME_IS_NULL_83E9039B = "udfName 不能为空"; public static final String EXCEPTION_URISTRING_IS_NULL_E7458C6A = "uriString 不能为空"; public static final String EXCEPTION_FILEPATH_IS_NULL_84CE8A66 = "filePath 不能为空"; + public static final String EXCEPTION_LOAD_TSFILE_PATH_CANNOT_BE_EMPTY_2B106181 = + "LOAD TSFILE 路径不能为空。"; public static final String EXCEPTION_DETAILS_IS_NULL_8EDEEA03 = "details 不能为空"; public static final String EXCEPTION_COLUMNCATEGORY_IS_NULL_0075924B = "columnCategory 不能为空"; public static final String EXCEPTION_ARGUMENTNAME_IS_NULL_7F8F665F = "argumentName 不能为空"; diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/crud/LoadTsFileStatement.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/crud/LoadTsFileStatement.java index 40faa2083cda..ce3a2145de41 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/crud/LoadTsFileStatement.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/crud/LoadTsFileStatement.java @@ -94,6 +94,10 @@ public static LoadTsFileStatement createForPipe(String filePath) throws FileNotF private LoadTsFileStatement( String filePath, boolean validateSourcePath, boolean validateInternalDataDir) throws FileNotFoundException { + if (filePath == null || filePath.isEmpty()) { + throw new FileNotFoundException( + DataNodeQueryMessages.EXCEPTION_LOAD_TSFILE_PATH_CANNOT_BE_EMPTY_2B106181); + } this.file = new File(filePath).getAbsoluteFile(); this.databaseLevel = IoTDBDescriptor.getInstance().getConfig().getDefaultDatabaseLevel(); this.verifySchema = true; @@ -151,14 +155,6 @@ private static List processTsFile( findAllTsFile( file, validateSourcePath, validateInternalDataDir, internalDataDirCanonicalPaths)); } - if (tsFiles.isEmpty()) { - throw new FileNotFoundException( - String.format( - DataNodeQueryMessages - .QUERY_EXCEPTION_CAN_NOT_FIND_S_ON_THIS_MACHINE_NOTICE_THAT_LOAD_CAN_ONLY_B7886C0E, - file.getPath())); - } - sortTsFiles(tsFiles); return tsFiles; } diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/statement/crud/LoadTsFileStatementTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/statement/crud/LoadTsFileStatementTest.java index 1e7e2a3df40e..67867cc607f3 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/statement/crud/LoadTsFileStatementTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/statement/crud/LoadTsFileStatementTest.java @@ -145,7 +145,7 @@ public void testLoadInternalTsFileIsRejectedWithoutLeakingPath() throws Exceptio } @Test - public void testLoadEmptyInternalDataDirIsRejected() throws Exception { + public void testLoadEmptyInternalDataDirDoesNotThrow() throws Exception { final IoTDBConfig config = IoTDBDescriptor.getInstance().getConfig(); final String[][] originalTierDataDirs = config.getTierDataDirs(); final boolean originalCheckEnabled = config.isLoadTsFileSourcePathCheckEnabled(); @@ -156,12 +156,8 @@ public void testLoadEmptyInternalDataDirIsRejected() throws Exception { config.setTierDataDirs(new String[][] {{dataDir.toString()}}); config.setLoadTsFileSourcePathCheckEnabled(false); - try { - new LoadTsFileStatement(dataDir.toString()); - Assert.fail("Expected empty internal IoTDB data directory to be rejected."); - } catch (final FileNotFoundException e) { - Assert.assertTrue(e.getMessage().contains("Can not find")); - } + final LoadTsFileStatement statement = new LoadTsFileStatement(dataDir.toString()); + Assert.assertTrue(statement.getTsFiles().isEmpty()); } finally { config.setTierDataDirs(originalTierDataDirs); config.setLoadTsFileSourcePathCheckEnabled(originalCheckEnabled); @@ -169,6 +165,16 @@ public void testLoadEmptyInternalDataDirIsRejected() throws Exception { } } + @Test + public void testLoadEmptyPathIsRejected() throws Exception { + try { + new LoadTsFileStatement(""); + Assert.fail("Expected empty LOAD TSFILE path to be rejected."); + } catch (final FileNotFoundException e) { + Assert.assertEquals("The LOAD TSFILE path cannot be empty.", e.getMessage()); + } + } + @Test public void testLoadNonEmptyInternalDataDirIsRejected() throws Exception { final IoTDBConfig config = IoTDBDescriptor.getInstance().getConfig(); From 61c95d50072ea2e8b6e6feb242bca5b8c94b4217 Mon Sep 17 00:00:00 2001 From: luoluoyuyu Date: Fri, 7 Aug 2026 11:29:11 +0800 Subject: [PATCH 5/7] Revert "test: cover loading internal data directories" This reverts commit c7557a762854ec890c760c07e6979b66f38e3fff. --- .../crud/LoadTsFileStatementTest.java | 59 ------------------- 1 file changed, 59 deletions(-) diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/statement/crud/LoadTsFileStatementTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/statement/crud/LoadTsFileStatementTest.java index 67867cc607f3..fac3227f4b5e 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/statement/crud/LoadTsFileStatementTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/statement/crud/LoadTsFileStatementTest.java @@ -144,65 +144,6 @@ public void testLoadInternalTsFileIsRejectedWithoutLeakingPath() throws Exceptio } } - @Test - public void testLoadEmptyInternalDataDirDoesNotThrow() throws Exception { - final IoTDBConfig config = IoTDBDescriptor.getInstance().getConfig(); - final String[][] originalTierDataDirs = config.getTierDataDirs(); - final boolean originalCheckEnabled = config.isLoadTsFileSourcePathCheckEnabled(); - final Path dataNodeDir = Files.createTempDirectory("load-tsfile-datanode"); - final Path dataDir = Files.createDirectories(dataNodeDir.resolve("data")); - - try { - config.setTierDataDirs(new String[][] {{dataDir.toString()}}); - config.setLoadTsFileSourcePathCheckEnabled(false); - - final LoadTsFileStatement statement = new LoadTsFileStatement(dataDir.toString()); - Assert.assertTrue(statement.getTsFiles().isEmpty()); - } finally { - config.setTierDataDirs(originalTierDataDirs); - config.setLoadTsFileSourcePathCheckEnabled(originalCheckEnabled); - deleteRecursively(dataNodeDir); - } - } - - @Test - public void testLoadEmptyPathIsRejected() throws Exception { - try { - new LoadTsFileStatement(""); - Assert.fail("Expected empty LOAD TSFILE path to be rejected."); - } catch (final FileNotFoundException e) { - Assert.assertEquals("The LOAD TSFILE path cannot be empty.", e.getMessage()); - } - } - - @Test - public void testLoadNonEmptyInternalDataDirIsRejected() throws Exception { - final IoTDBConfig config = IoTDBDescriptor.getInstance().getConfig(); - final String[][] originalTierDataDirs = config.getTierDataDirs(); - final boolean originalCheckEnabled = config.isLoadTsFileSourcePathCheckEnabled(); - final Path dataNodeDir = Files.createTempDirectory("load-tsfile-datanode"); - final Path dataDir = Files.createDirectories(dataNodeDir.resolve("data")); - Files.createFile(dataDir.resolve("a.tsfile")); - - try { - config.setTierDataDirs(new String[][] {{dataDir.toString()}}); - config.setLoadTsFileSourcePathCheckEnabled(false); - - try { - new LoadTsFileStatement(dataDir.toString()); - Assert.fail("Expected non-empty internal IoTDB data directory to be rejected."); - } catch (final FileNotFoundException e) { - Assert.assertEquals( - "Cannot load files because the specified directory contains IoTDB data.", - e.getMessage()); - } - } finally { - config.setTierDataDirs(originalTierDataDirs); - config.setLoadTsFileSourcePathCheckEnabled(originalCheckEnabled); - deleteRecursively(dataNodeDir); - } - } - @Test public void testLoadPipeReceiverTsFileOutsideDataDirIsAllowed() throws Exception { final IoTDBConfig config = IoTDBDescriptor.getInstance().getConfig(); From 2c680496752ebb0446769c278b1926a634a4a3bf Mon Sep 17 00:00:00 2001 From: luoluoyuyu Date: Fri, 7 Aug 2026 11:29:11 +0800 Subject: [PATCH 6/7] Revert "fix: validate internal tsfile paths for files only" This reverts commit 509b40ed0106f617163be8ac91b62a310ee327b9. --- .../plan/statement/crud/LoadTsFileStatement.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/crud/LoadTsFileStatement.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/crud/LoadTsFileStatement.java index ce3a2145de41..99ddb183cba9 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/crud/LoadTsFileStatement.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/crud/LoadTsFileStatement.java @@ -133,15 +133,15 @@ private static List processTsFile( throws FileNotFoundException { final Path[] internalDataDirCanonicalPaths = IoTDBDescriptor.getInstance().getConfig().getInternalDataDirCanonicalPaths(); + if (validateInternalDataDir) { + validateNotLoadingInternalTsFile(file, internalDataDirCanonicalPaths); + } if (validateSourcePath) { validateLoadSourcePath(file); } final List tsFiles = new ArrayList<>(); if (file.isFile()) { - if (validateInternalDataDir) { - validateNotLoadingInternalTsFile(file, internalDataDirCanonicalPaths); - } tsFiles.add(file); } else { if (file.listFiles() == null) { From d132a6086b6be1dac71c02ac77738300fa49d96a Mon Sep 17 00:00:00 2001 From: luoluoyuyu Date: Fri, 7 Aug 2026 15:12:02 +0800 Subject: [PATCH 7/7] fix: validate empty load tsfile paths for both models --- .../plan/relational/sql/ast/LoadTsFile.java | 1 + .../plan/statement/crud/LoadTsFileStatement.java | 12 ++++++++---- .../plan/analyze/load/LoadTsFileAnalyzerTest.java | 10 ++++++++++ .../plan/statement/crud/LoadTsFileStatementTest.java | 12 ++++++++++++ 4 files changed, 31 insertions(+), 4 deletions(-) diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/LoadTsFile.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/LoadTsFile.java index 8e46f7cd72a1..2e9adadb5766 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/LoadTsFile.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/LoadTsFile.java @@ -111,6 +111,7 @@ private LoadTsFile( initAttributes(); try { + LoadTsFileStatement.validateLoadTsFilePath(filePath); this.tsFiles = validateInternalDataDir ? LoadTsFileStatement.processTsFile(new File(filePath), validateSourcePath) diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/crud/LoadTsFileStatement.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/crud/LoadTsFileStatement.java index 99ddb183cba9..ca0a0a3e2bf6 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/crud/LoadTsFileStatement.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/crud/LoadTsFileStatement.java @@ -94,10 +94,7 @@ public static LoadTsFileStatement createForPipe(String filePath) throws FileNotF private LoadTsFileStatement( String filePath, boolean validateSourcePath, boolean validateInternalDataDir) throws FileNotFoundException { - if (filePath == null || filePath.isEmpty()) { - throw new FileNotFoundException( - DataNodeQueryMessages.EXCEPTION_LOAD_TSFILE_PATH_CANNOT_BE_EMPTY_2B106181); - } + validateLoadTsFilePath(filePath); this.file = new File(filePath).getAbsoluteFile(); this.databaseLevel = IoTDBDescriptor.getInstance().getConfig().getDefaultDatabaseLevel(); this.verifySchema = true; @@ -115,6 +112,13 @@ private LoadTsFileStatement( this.statementType = StatementType.MULTI_BATCH_INSERT; } + public static void validateLoadTsFilePath(final String filePath) throws FileNotFoundException { + if (filePath == null || filePath.isEmpty()) { + throw new FileNotFoundException( + DataNodeQueryMessages.EXCEPTION_LOAD_TSFILE_PATH_CANNOT_BE_EMPTY_2B106181); + } + } + public static List processTsFile(final File file) throws FileNotFoundException { return processTsFile(file, true, true); } 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 68503f3d794d..bf248d7a600b 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 @@ -120,6 +120,16 @@ public void testAnalyzeSingleTableFileShouldNotCountTimestampInPointCount() thro Assert.assertEquals(2, schemaCache.getVerifiedDeviceCount()); } + @Test + public void testTableLoadEmptyPathIsRejected() { + try { + new LoadTsFile(null, "", Collections.emptyMap()); + Assert.fail("Expected empty LOAD TSFILE path to be rejected."); + } catch (final RuntimeException e) { + Assert.assertTrue(e.getMessage().contains("The LOAD TSFILE path cannot be empty.")); + } + } + @Test public void testTableSchemaCacheShouldThrowMismatchWhenVerifyingDataType() throws Exception { final LoadTsFileTableSchemaCache schemaCache = createTableSchemaCache(true); diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/statement/crud/LoadTsFileStatementTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/statement/crud/LoadTsFileStatementTest.java index fac3227f4b5e..488796865b3c 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/statement/crud/LoadTsFileStatementTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/statement/crud/LoadTsFileStatementTest.java @@ -21,6 +21,7 @@ import org.apache.iotdb.db.conf.IoTDBConfig; import org.apache.iotdb.db.conf.IoTDBDescriptor; +import org.apache.iotdb.db.queryengine.plan.parser.StatementGenerator; import org.junit.Assert; import org.junit.Test; @@ -29,6 +30,7 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.time.ZoneId; import java.util.Comparator; import java.util.List; import java.util.stream.Stream; @@ -144,6 +146,16 @@ public void testLoadInternalTsFileIsRejectedWithoutLeakingPath() throws Exceptio } } + @Test + public void testTreeLoadEmptyPathIsRejected() { + try { + StatementGenerator.createStatement("LOAD TSFILE ''", ZoneId.systemDefault()); + Assert.fail("Expected empty LOAD TSFILE path to be rejected."); + } catch (final RuntimeException e) { + Assert.assertTrue(e.getMessage().contains("The LOAD TSFILE path cannot be empty.")); + } + } + @Test public void testLoadPipeReceiverTsFileOutsideDataDirIsAllowed() throws Exception { final IoTDBConfig config = IoTDBDescriptor.getInstance().getConfig();