You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hive.apache.org by kh...@apache.org on 2015/01/27 00:20:02 UTC

svn commit: r1654909 - in /hive/trunk: common/src/java/org/apache/hadoop/hive/conf/ itests/hive-unit/src/test/java/org/apache/hadoop/hive/metastore/ metastore/src/java/org/apache/hadoop/hive/metastore/

Author: khorgath
Date: Mon Jan 26 23:20:01 2015
New Revision: 1654909

URL: http://svn.apache.org/r1654909
Log:
HIVE-8485 : HMS on Oracle incompatibility (Sushanth Sowmyan, reviewed by Sergey Shelukhin, Chaoyu Tang)

Added:
    hive/trunk/itests/hive-unit/src/test/java/org/apache/hadoop/hive/metastore/TestMetaStoreUtils.java
Modified:
    hive/trunk/common/src/java/org/apache/hadoop/hive/conf/HiveConf.java
    hive/trunk/metastore/src/java/org/apache/hadoop/hive/metastore/MetaStoreDirectSql.java
    hive/trunk/metastore/src/java/org/apache/hadoop/hive/metastore/MetaStoreUtils.java
    hive/trunk/metastore/src/java/org/apache/hadoop/hive/metastore/ObjectStore.java

Modified: hive/trunk/common/src/java/org/apache/hadoop/hive/conf/HiveConf.java
URL: http://svn.apache.org/viewvc/hive/trunk/common/src/java/org/apache/hadoop/hive/conf/HiveConf.java?rev=1654909&r1=1654908&r2=1654909&view=diff
==============================================================================
--- hive/trunk/common/src/java/org/apache/hadoop/hive/conf/HiveConf.java (original)
+++ hive/trunk/common/src/java/org/apache/hadoop/hive/conf/HiveConf.java Mon Jan 26 23:20:01 2015
@@ -159,6 +159,7 @@ public class HiveConf extends Configurat
       HiveConf.ConfVars.HMSHANDLERINTERVAL,
       HiveConf.ConfVars.HMSHANDLERFORCERELOADCONF,
       HiveConf.ConfVars.METASTORE_PARTITION_NAME_WHITELIST_PATTERN,
+      HiveConf.ConfVars.METASTORE_ORM_RETRIEVE_MAPNULLS_AS_EMPTY_STRINGS,
       HiveConf.ConfVars.METASTORE_DISALLOW_INCOMPATIBLE_COL_TYPE_CHANGES,
       HiveConf.ConfVars.USERS_IN_ADMIN_ROLE,
       HiveConf.ConfVars.HIVE_AUTHORIZATION_MANAGER,
@@ -545,6 +546,11 @@ public class HiveConf extends Configurat
         "select query has incorrect syntax or something similar inside a transaction, the\n" +
         "entire transaction will fail and fall-back to DataNucleus will not be possible. You\n" +
         "should disable the usage of direct SQL inside transactions if that happens in your case."),
+    METASTORE_ORM_RETRIEVE_MAPNULLS_AS_EMPTY_STRINGS("hive.metastore.orm.retrieveMapNullsAsEmptyStrings",false,
+        "Thrift does not support nulls in maps, so any nulls present in maps retrieved from ORM must " +
+        "either be pruned or converted to empty strings. Some backing dbs such as Oracle persist empty strings " +
+        "as nulls, so we should set this parameter if we wish to reverse that behaviour. For others, " +
+        "pruning is the correct behaviour"),
     METASTORE_DISALLOW_INCOMPATIBLE_COL_TYPE_CHANGES(
         "hive.metastore.disallow.incompatible.col.type.changes", false,
         "If true (default is false), ALTER TABLE operations which change the type of a\n" +

Added: hive/trunk/itests/hive-unit/src/test/java/org/apache/hadoop/hive/metastore/TestMetaStoreUtils.java
URL: http://svn.apache.org/viewvc/hive/trunk/itests/hive-unit/src/test/java/org/apache/hadoop/hive/metastore/TestMetaStoreUtils.java?rev=1654909&view=auto
==============================================================================
--- hive/trunk/itests/hive-unit/src/test/java/org/apache/hadoop/hive/metastore/TestMetaStoreUtils.java (added)
+++ hive/trunk/itests/hive-unit/src/test/java/org/apache/hadoop/hive/metastore/TestMetaStoreUtils.java Mon Jan 26 23:20:01 2015
@@ -0,0 +1,62 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.hive.metastore;
+
+import junit.framework.TestCase;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class TestMetaStoreUtils extends TestCase {
+
+  public void testTrimMapNullsXform() throws Exception {
+    Map<String,String> m = new HashMap<String,String>();
+    m.put("akey","aval");
+    m.put("blank","");
+    m.put("null",null);
+
+    Map<String,String> xformed = MetaStoreUtils.trimMapNulls(m,true);
+    assertEquals(3,xformed.size());
+    assert(xformed.containsKey("akey"));
+    assert(xformed.containsKey("blank"));
+    assert(xformed.containsKey("null"));
+    assertEquals("aval",xformed.get("akey"));
+    assertEquals("",xformed.get("blank"));
+    assertEquals("",xformed.get("null"));
+  }
+
+  public void testTrimMapNullsPrune() throws Exception {
+    Map<String,String> m = new HashMap<String,String>();
+    m.put("akey","aval");
+    m.put("blank","");
+    m.put("null",null);
+
+    Map<String,String> pruned = MetaStoreUtils.trimMapNulls(m,false);
+    assertEquals(2,pruned.size());
+    assert(pruned.containsKey("akey"));
+    assert(pruned.containsKey("blank"));
+    assert(!pruned.containsKey("null"));
+    assertEquals("aval",pruned.get("akey"));
+    assertEquals("",pruned.get("blank"));
+    assert(!pruned.containsValue(null));
+  }
+
+
+
+}

Modified: hive/trunk/metastore/src/java/org/apache/hadoop/hive/metastore/MetaStoreDirectSql.java
URL: http://svn.apache.org/viewvc/hive/trunk/metastore/src/java/org/apache/hadoop/hive/metastore/MetaStoreDirectSql.java?rev=1654909&r1=1654908&r2=1654909&view=diff
==============================================================================
--- hive/trunk/metastore/src/java/org/apache/hadoop/hive/metastore/MetaStoreDirectSql.java (original)
+++ hive/trunk/metastore/src/java/org/apache/hadoop/hive/metastore/MetaStoreDirectSql.java Mon Jan 26 23:20:01 2015
@@ -108,6 +108,7 @@ class MetaStoreDirectSql {
    */
   private final DB dbType;
   private final int batchSize;
+  private final boolean convertMapNullsToEmptyStrings;
 
   /**
    * Whether direct SQL can be used with the current datastore backing {@link #pm}.
@@ -123,6 +124,9 @@ class MetaStoreDirectSql {
     }
     this.batchSize = batchSize;
 
+    convertMapNullsToEmptyStrings =
+        HiveConf.getBoolVar(conf, ConfVars.METASTORE_ORM_RETRIEVE_MAPNULLS_AS_EMPTY_STRINGS);
+
     this.isCompatibleDatastore = ensureDbInit() && runTestQuery();
     if (isCompatibleDatastore) {
       LOG.info("Using direct SQL, underlying DB is " + dbType);
@@ -298,7 +302,7 @@ class MetaStoreDirectSql {
       String type = extractSqlString(dbline[5]);
       db.setOwnerType(
           (null == type || type.trim().isEmpty()) ? null : PrincipalType.valueOf(type));
-      db.setParameters(dbParams);
+      db.setParameters(MetaStoreUtils.trimMapNulls(dbParams,convertMapNullsToEmptyStrings));
       if (LOG.isDebugEnabled()){
         LOG.debug("getDatabase: directsql returning db " + db.getName()
             + " locn["+db.getLocationUri()  +"] desc [" +db.getDescription()

Modified: hive/trunk/metastore/src/java/org/apache/hadoop/hive/metastore/MetaStoreUtils.java
URL: http://svn.apache.org/viewvc/hive/trunk/metastore/src/java/org/apache/hadoop/hive/metastore/MetaStoreUtils.java?rev=1654909&r1=1654908&r2=1654909&view=diff
==============================================================================
--- hive/trunk/metastore/src/java/org/apache/hadoop/hive/metastore/MetaStoreUtils.java (original)
+++ hive/trunk/metastore/src/java/org/apache/hadoop/hive/metastore/MetaStoreUtils.java Mon Jan 26 23:20:01 2015
@@ -37,6 +37,8 @@ import java.util.Set;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import com.google.common.base.Predicates;
+import com.google.common.collect.Maps;
 import org.apache.commons.lang.StringUtils;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -76,6 +78,8 @@ import org.apache.hadoop.hive.shims.Shim
 import org.apache.hadoop.hive.thrift.HadoopThriftAuthBridge;
 import org.apache.hadoop.util.ReflectionUtils;
 
+import javax.annotation.Nullable;
+
 public class MetaStoreUtils {
 
   protected static final Log LOG = LogFactory.getLog("hive.log");
@@ -1609,4 +1613,44 @@ public class MetaStoreUtils {
     }
     return new String[] {names[0], names[1]};
   }
+
+  /**
+   * Helper function to transform Nulls to empty strings.
+   */
+  private static final com.google.common.base.Function<String,String> transFormNullsToEmptyString
+      = new com.google.common.base.Function<String, String>() {
+    @Override
+    public java.lang.String apply(@Nullable java.lang.String string) {
+      if (string == null){
+        return "";
+      } else {
+        return string;
+      }
+    }
+  };
+
+  /**
+   * We have aneed to sanity-check the map before conversion from persisted objects to
+   * metadata thrift objects because null values in maps will cause a NPE if we send
+   * across thrift. Pruning is appropriate for most cases except for databases such as
+   * Oracle where Empty strings are stored as nulls, in which case we need to handle that.
+   * See HIVE-8485 for motivations for this.
+   */
+  public static Map<String,String> trimMapNulls(
+      Map<String,String> dnMap, boolean retrieveMapNullsAsEmptyStrings){
+    if (dnMap == null){
+      return null;
+    }
+    // Must be deterministic order map - see HIVE-8707
+    //   => we use Maps.newLinkedHashMap instead of Maps.newHashMap
+    if (retrieveMapNullsAsEmptyStrings) {
+      // convert any nulls present in map values to empty strings - this is done in the case
+      // of backing dbs like oracle which persist empty strings as nulls.
+      return Maps.newLinkedHashMap(Maps.transformValues(dnMap, transFormNullsToEmptyString));
+    } else {
+      // prune any nulls present in map values - this is the typical case.
+      return Maps.newLinkedHashMap(Maps.filterValues(dnMap, Predicates.notNull()));
+    }
+  }
+
 }

Modified: hive/trunk/metastore/src/java/org/apache/hadoop/hive/metastore/ObjectStore.java
URL: http://svn.apache.org/viewvc/hive/trunk/metastore/src/java/org/apache/hadoop/hive/metastore/ObjectStore.java?rev=1654909&r1=1654908&r2=1654909&view=diff
==============================================================================
--- hive/trunk/metastore/src/java/org/apache/hadoop/hive/metastore/ObjectStore.java (original)
+++ hive/trunk/metastore/src/java/org/apache/hadoop/hive/metastore/ObjectStore.java Mon Jan 26 23:20:01 2015
@@ -148,8 +148,6 @@ import org.apache.thrift.TException;
 import org.datanucleus.store.rdbms.exceptions.MissingTableException;
 
 import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-
 
 /**
  * This class is the interface between the application logic and the database
@@ -583,7 +581,7 @@ public class ObjectStore implements RawS
     db.setName(mdb.getName());
     db.setDescription(mdb.getDescription());
     db.setLocationUri(mdb.getLocationUri());
-    db.setParameters(mdb.getParameters());
+    db.setParameters(convertMap(mdb.getParameters()));
     db.setOwnerName(mdb.getOwnerName());
     String type = mdb.getOwnerType();
     db.setOwnerType((null == type || type.trim().isEmpty()) ? null : PrincipalType.valueOf(type));
@@ -1030,9 +1028,9 @@ public class ObjectStore implements RawS
   }
 
   /** Makes shallow copy of a map to avoid DataNucleus mucking with our objects. */
-  private <K, V> Map<K, V> convertMap(Map<K, V> dnMap) {
-    // Must be deterministic order map - see HIVE-8707
-    return (dnMap == null) ? null : Maps.newLinkedHashMap(dnMap);
+  private Map<String, String> convertMap(Map<String, String> dnMap) {
+    return MetaStoreUtils.trimMapNulls(dnMap,
+        HiveConf.getBoolVar(getConf(), ConfVars.METASTORE_ORM_RETRIEVE_MAPNULLS_AS_EMPTY_STRINGS));
   }
 
   private Table convertToTable(MTable mtbl) throws MetaException {