diff --git a/presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/MetastoreUtil.java b/presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/MetastoreUtil.java index df41c5500242..84de3074ee92 100644 --- a/presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/MetastoreUtil.java +++ b/presto-hive-metastore/src/main/java/com/facebook/presto/hive/metastore/MetastoreUtil.java @@ -60,7 +60,6 @@ import org.apache.hadoop.hive.common.FileUtils; import org.apache.hadoop.hive.common.type.HiveDecimal; import org.apache.hadoop.hive.metastore.ProtectMode; -import org.apache.hadoop.hive.metastore.api.MetaException; import org.apache.hadoop.io.Text; import org.joda.time.DateTimeZone; import org.joda.time.format.DateTimeFormatter; @@ -116,7 +115,6 @@ import static org.apache.hadoop.hive.common.FileUtils.unescapePathName; import static org.apache.hadoop.hive.metastore.ColumnType.typeToThriftType; import static org.apache.hadoop.hive.metastore.ProtectMode.getProtectModeFromString; -import static org.apache.hadoop.hive.metastore.Warehouse.makeSpecFromName; import static org.apache.hadoop.hive.metastore.api.hive_metastoreConstants.BUCKET_COUNT; import static org.apache.hadoop.hive.metastore.api.hive_metastoreConstants.BUCKET_FIELD_NAME; import static org.apache.hadoop.hive.metastore.api.hive_metastoreConstants.FILE_INPUT_FORMAT; @@ -466,15 +464,32 @@ public static void renameFile(FileSystem fileSystem, Path source, Path target) } } - // TODO: https://github.com/prestodb/presto/issues/15974 public static Map toPartitionNamesAndValues(String partitionName) { - try { - return ImmutableMap.copyOf(makeSpecFromName(partitionName)); - } - catch (MetaException e) { - throw new PrestoException(HIVE_INVALID_PARTITION_VALUE, "Invalid partition name: " + partitionName); + ImmutableMap.Builder resultBuilder = ImmutableMap.builder(); + int index = 0; + int length = partitionName.length(); + + while (index < length) { + int keyStart = index; + while (index < length && partitionName.charAt(index) != '=') { + index++; + } + checkState(index < length, "Invalid partition spec: " + partitionName); + + int keyEnd = index++; + int valueStart = index; + while (index < length && partitionName.charAt(index) != '/') { + index++; + } + int valueEnd = index++; + + String key = unescapePathName(partitionName.substring(keyStart, keyEnd)); + String value = unescapePathName(partitionName.substring(valueStart, valueEnd)); + resultBuilder.put(key, value); } + + return resultBuilder.build(); } public static List toPartitionValues(String partitionName) diff --git a/presto-hive/src/test/java/com/facebook/presto/hive/TestHiveUtil.java b/presto-hive/src/test/java/com/facebook/presto/hive/TestHiveUtil.java index 7f38a15f6b2b..7cbd8726fffd 100644 --- a/presto-hive/src/test/java/com/facebook/presto/hive/TestHiveUtil.java +++ b/presto-hive/src/test/java/com/facebook/presto/hive/TestHiveUtil.java @@ -34,6 +34,7 @@ import java.util.AbstractList; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.Properties; @@ -41,7 +42,9 @@ import static com.facebook.presto.hive.HiveUtil.getDeserializer; import static com.facebook.presto.hive.HiveUtil.parseHiveTimestamp; import static com.facebook.presto.hive.HiveUtil.shouldUseRecordReaderFromInputFormat; +import static com.facebook.presto.hive.metastore.MetastoreUtil.toPartitionNamesAndValues; import static com.facebook.presto.hive.metastore.MetastoreUtil.toPartitionValues; +import static com.google.common.base.Preconditions.checkState; import static org.apache.hadoop.hive.serde.serdeConstants.SERIALIZATION_CLASS; import static org.apache.hadoop.hive.serde.serdeConstants.SERIALIZATION_FORMAT; import static org.apache.hadoop.hive.serde.serdeConstants.SERIALIZATION_LIB; @@ -94,6 +97,30 @@ public void testToPartitionValues() assertToPartitionValues("pk=__HIVE_DEFAULT_PARTITION__"); } + @Test + public void testToPartitionNamesAndValues() + throws MetaException + { + List expectedKeyList1 = new ArrayList<>(); + expectedKeyList1.add("ds"); + expectedKeyList1.add("event_type"); + assertToPartitionNamesAndValues("ds=2015-12-30/event_type=QueryCompletion", expectedKeyList1); + + List expectedKeyList2 = new ArrayList<>(); + expectedKeyList2.add("a"); + expectedKeyList2.add("b"); + expectedKeyList2.add("c"); + assertToPartitionNamesAndValues("a=1/b=2/c=3", expectedKeyList2); + + List expectedKeyList3 = new ArrayList<>(); + expectedKeyList3.add("pk"); + assertToPartitionNamesAndValues("pk=!@%23$%25%5E&%2A()%2F%3D", expectedKeyList3); + + List expectedKeyList4 = new ArrayList<>(); + expectedKeyList4.add("pk"); + assertToPartitionNamesAndValues("pk=__HIVE_DEFAULT_PARTITION__", expectedKeyList4); + } + @Test public void testShouldUseRecordReaderFromInputFormat() { @@ -116,6 +143,29 @@ private static void assertToPartitionValues(String partitionName) assertEquals(actual, expected); } + private static void assertToPartitionNamesAndValues(String partitionName, List expectedKeyList) + throws MetaException + { + Map actual = toPartitionNamesAndValues(partitionName); + AbstractList expectedValueList = new ArrayList<>(); + for (String s : expectedKeyList) { + expectedValueList.add(null); + } + Warehouse.makeValsFromName(partitionName, expectedValueList); + checkState(actual.keySet().size() == expectedKeyList.size(), "Keyset size is not same"); + + for (int index = 0; index < expectedKeyList.size(); index++) { + String key = expectedKeyList.get(index); + if (!actual.containsKey(key)) { + break; + } + checkState(actual.containsKey(key), "Actual result does not contains the key"); + String actualValue = actual.get(key); + String expectedValue = expectedValueList.get(index); + checkState(actualValue.equals(expectedValue), "The actual value does not match the expected value"); + } + } + private static long parse(DateTime time, String pattern) { return parseHiveTimestamp(DateTimeFormat.forPattern(pattern).print(time), nonDefaultTimeZone());