From 6ceec25c5d4cdf3ba7e0c2b291f98a56b71b27b1 Mon Sep 17 00:00:00 2001 From: Yingjie Luan <1275963@gmail.com> Date: Mon, 19 Jul 2021 15:32:58 -0700 Subject: [PATCH] Quote field with reserved key name when reading hive view using coral This fixed issue when reading coral translated hive view with definition such as: struct<`from`:int> --- .../io/trino/plugin/hive/ViewReaderUtil.java | 6 +++- .../tests/product/hive/TestHiveViews.java | 34 +++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/plugin/trino-hive/src/main/java/io/trino/plugin/hive/ViewReaderUtil.java b/plugin/trino-hive/src/main/java/io/trino/plugin/hive/ViewReaderUtil.java index 9f053a48c0b5..bd1a35a7a76b 100644 --- a/plugin/trino-hive/src/main/java/io/trino/plugin/hive/ViewReaderUtil.java +++ b/plugin/trino-hive/src/main/java/io/trino/plugin/hive/ViewReaderUtil.java @@ -47,6 +47,7 @@ import static com.google.common.base.Verify.verify; import static com.google.common.collect.ImmutableList.toImmutableList; +import static com.linkedin.coral.trino.rel2trino.functions.TrinoKeywordsConverter.quoteWordIfNotQuoted; import static io.trino.plugin.hive.HiveErrorCode.HIVE_INVALID_VIEW_DATA; import static io.trino.plugin.hive.HiveErrorCode.HIVE_VIEW_TRANSLATION_ERROR; import static io.trino.plugin.hive.HiveMetadata.TABLE_COMMENT; @@ -245,8 +246,11 @@ private String getTypeString(RelDataType type) switch (type.getSqlTypeName()) { case ROW: { verify(type.isStruct(), "expected ROW type to be a struct: %s", type); + // There is no API in RelDataType for Coral to add quotes for rowType. + // We add the Coral function here to parse data types successfully. + // Goal is to use data type mapping instead of translating to strings return type.getFieldList().stream() - .map(field -> field.getName().toLowerCase(Locale.ENGLISH) + " " + getTypeString(field.getType())) + .map(field -> quoteWordIfNotQuoted(field.getName().toLowerCase(Locale.ENGLISH)) + " " + getTypeString(field.getType())) .collect(joining(",", "row(", ")")); } case CHAR: diff --git a/testing/trino-product-tests/src/main/java/io/trino/tests/product/hive/TestHiveViews.java b/testing/trino-product-tests/src/main/java/io/trino/tests/product/hive/TestHiveViews.java index 9f2815b3efae..97741c9e719a 100644 --- a/testing/trino-product-tests/src/main/java/io/trino/tests/product/hive/TestHiveViews.java +++ b/testing/trino-product-tests/src/main/java/io/trino/tests/product/hive/TestHiveViews.java @@ -14,6 +14,7 @@ package io.trino.tests.product.hive; import com.google.common.collect.ImmutableList; +import io.trino.jdbc.Row; import io.trino.tempto.Requires; import io.trino.tempto.fulfillment.table.hive.tpch.ImmutableTpchTablesRequirements.ImmutableNationTable; import io.trino.tempto.fulfillment.table.hive.tpch.ImmutableTpchTablesRequirements.ImmutableOrdersTable; @@ -397,6 +398,39 @@ public void testFromUtcTimestampInvalidTimeZone() onTrino().executeQuery("DROP TABLE test_from_utc_timestamp_invalid_time_zone_source"); } + @Test(groups = HIVE_VIEWS) + public void testNestedFieldWithReservedKeyNames() + { + onTrino().executeQuery("DROP TABLE IF EXISTS test_nested_field_with_reserved_key_names_source"); + onHive().executeQuery("CREATE TABLE test_nested_field_with_reserved_key_names_source (nested_field_key_word_lower_case struct<`from`:BIGINT>, " + + "nested_field_key_word_upper_case struct<`FROM`:BIGINT>, nested_field_quote struct<`do...from`:BIGINT>)"); + + onTrino().executeQuery("INSERT INTO test_nested_field_with_reserved_key_names_source VALUES (row(row(1), row(2), row(3)))"); + + onHive().executeQuery("DROP VIEW IF EXISTS test_nested_field_with_reserved_key_names_view"); + onHive().executeQuery("CREATE VIEW " + + "test_nested_field_with_reserved_key_names_view " + + "AS SELECT nested_field_key_word_lower_case, nested_field_key_word_upper_case, nested_field_quote " + + "FROM test_nested_field_with_reserved_key_names_source"); + + assertThat(onHive().executeQuery("SELECT nested_field_key_word_lower_case, nested_field_key_word_upper_case, nested_field_quote FROM test_nested_field_with_reserved_key_names_view")) + .containsOnly(row("{\"from\":1}", "{\"from\":2}", "{\"do...from\":3}")); + + assertThat(onHive().executeQuery("SELECT nested_field_key_word_lower_case.`from`, nested_field_key_word_upper_case.`from`, nested_field_quote.`do...from` FROM test_nested_field_with_reserved_key_names_view")) + .containsOnly(row(1L, 2L, 3L)); + + assertThat(onTrino().executeQuery("SELECT nested_field_key_word_lower_case, nested_field_key_word_upper_case, nested_field_quote FROM test_nested_field_with_reserved_key_names_view")) + .containsOnly(row(Row.builder().addField("from", 1L).build(), + Row.builder().addField("from", 2L).build(), + Row.builder().addField("do...from", 3L).build())); + + assertThat(onTrino().executeQuery("SELECT nested_field_key_word_lower_case.\"from\", nested_field_key_word_upper_case.\"from\", nested_field_quote.\"do...from\" FROM test_nested_field_with_reserved_key_names_view")) + .containsOnly(row(1L, 2L, 3L)); + + onHive().executeQuery("DROP VIEW test_nested_field_with_reserved_key_names_view"); + onHive().executeQuery("DROP TABLE test_nested_field_with_reserved_key_names_source"); + } + @Test(groups = HIVE_VIEWS) public void testFromUtcTimestampCornerCases() {