diff --git common/src/java/org/apache/hadoop/hive/common/StringableMap.java common/src/java/org/apache/hadoop/hive/common/StringableMap.java index 8a93c0fc12..d1813e2fad 100644 --- common/src/java/org/apache/hadoop/hive/common/StringableMap.java +++ common/src/java/org/apache/hadoop/hive/common/StringableMap.java @@ -35,16 +35,36 @@ public StringableMap(String s) { int numElements = Integer.parseInt(parts[0]); s = parts[1]; for (int i = 0; i < numElements; i++) { + // Get the key String. parts = s.split(":", 2); - int len = Integer.parseInt(parts[0]); - String key = null; - if (len > 0) key = parts[1].substring(0, len); + int len = Integer.parseInt(parts[0]); + String key = ""; // Default is now an empty string. + + if (len > 0) key = parts[1].substring(0, len); + // Please check the toString() method of this class. + // null has -1 as length and empty String has 0. + else if (len < 0) { + key = null; + len = 0; // Set 0 to 'len' for null-valued key + // since only len exists for null-valued key from the given String "s". + } + + // Get the value String for the key parts = parts[1].substring(len).split(":", 2); len = Integer.parseInt(parts[0]); - String value = null; + String value = ""; + if (len > 0) value = parts[1].substring(0, len); - s = parts[1].substring(len); + else if (len < 0) { + value = null; + len = 0; // Set 0 to 'len' since only len exists. + } + + // Put the entry into the HashMap. put(key, value); + + // Move to the next substring to process. + s = parts[1].substring(len); } } @@ -59,14 +79,21 @@ public String toString() { buf.append(':'); if (size() > 0) { for (Map.Entry entry : entrySet()) { - int length = (entry.getKey() == null) ? 0 : entry.getKey().length(); - buf.append(entry.getKey() == null ? 0 : length); + // Append the key String to the output StringBuilder. + // Note that null is saved as -1 in length, and that empty String as 0. + int length = (entry.getKey() == null) ? -1 : entry.getKey().length(); + buf.append(length); buf.append(':'); if (length > 0) buf.append(entry.getKey()); - length = (entry.getValue() == null) ? 0 : entry.getValue().length(); + + // Append the value String to the output StringBuilder. + // Note that null is saved as -1 in length, and that empty String as 0. + length = (entry.getValue() == null) ? -1 : entry.getValue().length(); buf.append(length); buf.append(':'); - if (length > 0) buf.append(entry.getValue()); + if (length > 0) { + buf.append(entry.getValue()); + } } } return buf.toString(); diff --git ql/src/test/org/apache/hadoop/hive/ql/TestTxnCommands2.java ql/src/test/org/apache/hadoop/hive/ql/TestTxnCommands2.java index f620283614..34557e3258 100644 --- ql/src/test/org/apache/hadoop/hive/ql/TestTxnCommands2.java +++ ql/src/test/org/apache/hadoop/hive/ql/TestTxnCommands2.java @@ -933,6 +933,23 @@ public void updateDeletePartitioned() throws Exception { Assert.assertEquals("Update " + Table.ACIDTBLPART + " didn't match:", stringifyValues(expectedData), rs); } + /** + * https://issues.apache.org/jira/browse/HIVE-17391 + */ + @Test + public void testEmptyInTblproperties() throws Exception { + runStatementOnDriver("create table t1 " + "(a int, b int) stored as orc TBLPROPERTIES ('serialization.null.format'='', 'transactional'='true')"); + runStatementOnDriver("insert into t1 " + "(a,b) values(1,7),(3,7)"); + runStatementOnDriver("update t1" + " set b = -2 where b = 2"); + runStatementOnDriver("alter table t1 " + " compact 'MAJOR'"); + runWorker(hiveConf); + TxnStore txnHandler = TxnUtils.getTxnStore(hiveConf); + ShowCompactResponse resp = txnHandler.showCompact(new ShowCompactRequest()); + Assert.assertEquals("Unexpected number of compactions in history", 1, resp.getCompactsSize()); + Assert.assertEquals("Unexpected 0 compaction state", TxnStore.CLEANING_RESPONSE, resp.getCompacts().get(0).getState()); + Assert.assertTrue(resp.getCompacts().get(0).getHadoopJobId().startsWith("job_local")); + } + /** * https://issues.apache.org/jira/browse/HIVE-10151 */