diff --git a/plugin/trino-hive/src/test/java/io/trino/plugin/hive/AbstractTestHiveFileSystem.java b/plugin/trino-hive/src/test/java/io/trino/plugin/hive/AbstractTestHiveFileSystem.java index bd01a7c88a31..e574f7da8d22 100644 --- a/plugin/trino-hive/src/test/java/io/trino/plugin/hive/AbstractTestHiveFileSystem.java +++ b/plugin/trino-hive/src/test/java/io/trino/plugin/hive/AbstractTestHiveFileSystem.java @@ -79,7 +79,11 @@ import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +import java.io.BufferedReader; import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; import java.io.UncheckedIOException; import java.util.Collection; import java.util.List; @@ -114,6 +118,7 @@ import static io.trino.testing.QueryAssertions.assertEqualsIgnoreOrder; import static io.trino.testing.TestingPageSinkId.TESTING_PAGE_SINK_ID; import static io.trino.type.InternalTypeManager.TESTING_TYPE_MANAGER; +import static java.nio.charset.StandardCharsets.UTF_8; import static java.util.Locale.ENGLISH; import static java.util.UUID.randomUUID; import static java.util.concurrent.Executors.newCachedThreadPool; @@ -488,6 +493,28 @@ public void testFileIteratorListing() assertEqualsIgnoreOrder(shallowListing, ImmutableList.of(baseFile)); } + @Test + public void testDirectoryWithTrailingSpace() + throws Exception + { + Path basePath = new Path(getBasePath(), randomUUID().toString()); + FileSystem fs = hdfsEnvironment.getFileSystem(TESTING_CONTEXT, basePath); + assertFalse(fs.exists(basePath)); + + Path path = new Path(new Path(basePath, "dir_with_space "), "foo.txt"); + try (OutputStream outputStream = fs.create(path)) { + outputStream.write("test".getBytes(UTF_8)); + } + assertTrue(fs.exists(path)); + + try (InputStream inputStream = fs.open(path)) { + String content = new BufferedReader(new InputStreamReader(inputStream, UTF_8)).readLine(); + assertEquals(content, "test"); + } + + fs.delete(basePath, true); + } + @Test public void testTableCreation() throws Exception diff --git a/plugin/trino-hive/src/test/java/io/trino/plugin/hive/BaseTestHiveOnDataLake.java b/plugin/trino-hive/src/test/java/io/trino/plugin/hive/BaseTestHiveOnDataLake.java index 3a9f1204139e..73a2994e04f9 100644 --- a/plugin/trino-hive/src/test/java/io/trino/plugin/hive/BaseTestHiveOnDataLake.java +++ b/plugin/trino-hive/src/test/java/io/trino/plugin/hive/BaseTestHiveOnDataLake.java @@ -55,6 +55,7 @@ import static io.trino.testing.MaterializedResult.resultBuilder; import static io.trino.testing.TestingNames.randomNameSuffix; import static java.lang.String.format; +import static java.nio.charset.StandardCharsets.UTF_8; import static java.time.temporal.ChronoUnit.DAYS; import static java.time.temporal.ChronoUnit.MINUTES; import static java.util.Objects.requireNonNull; @@ -1624,6 +1625,33 @@ public void testAnalyzePartitionedTableWithCanonicalization() assertUpdate("DROP TABLE " + getFullyQualifiedTestTableName(tableName)); } + @Test + public void testExternalLocationWithTrailingSpace() + { + String tableName = "test_external_location_with_trailing_space_" + randomNameSuffix(); + String tableLocationDirWithTrailingSpace = tableName + " "; + String tableLocation = format("s3a://%s/%s/%s", bucketName, HIVE_TEST_SCHEMA, tableLocationDirWithTrailingSpace); + + byte[] contents = "hello\u0001world\nbye\u0001world".getBytes(UTF_8); + String targetPath = format("%s/%s/test.txt", HIVE_TEST_SCHEMA, tableLocationDirWithTrailingSpace); + hiveMinioDataLake.getMinioClient().putObject(bucketName, contents, targetPath); + + assertUpdate(format( + "CREATE TABLE %s (" + + " a varchar, " + + " b varchar) " + + "WITH (format='TEXTFILE', external_location='%s')", + tableName, + tableLocation)); + + assertQuery("SELECT a, b FROM " + tableName, "VALUES ('hello', 'world'), ('bye', 'world')"); + + String actualTableLocation = getTableLocation(tableName); + assertThat(actualTableLocation).isEqualTo(tableLocation); + + assertUpdate("DROP TABLE " + tableName); + } + private void renamePartitionResourcesOutsideTrino(String tableName, String partitionColumn, String regionKey) { String partitionName = format("%s=%s", partitionColumn, regionKey); @@ -1814,4 +1842,9 @@ private void addPartitions( PartitionStatistics.empty())) .collect(toImmutableList())); } + + private String getTableLocation(String tableName) + { + return (String) computeScalar("SELECT DISTINCT regexp_replace(\"$path\", '/[^/]*$', '') FROM " + tableName); + } }