[ 
https://issues.apache.org/jira/browse/HIVE-24120?focusedWorklogId=484804&page=com.atlassian.jira.plugin.system.issuetabpanels:worklog-tabpanel#worklog-484804
 ]

ASF GitHub Bot logged work on HIVE-24120:
-----------------------------------------

                Author: ASF GitHub Bot
            Created on: 15/Sep/20 22:43
            Start Date: 15/Sep/20 22:43
    Worklog Time Spent: 10m 
      Work Description: vihangk1 commented on a change in pull request #1470:
URL: https://github.com/apache/hive/pull/1470#discussion_r489027437



##########
File path: 
standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/DatabaseProduct.java
##########
@@ -20,71 +20,646 @@
 
 import java.sql.SQLException;
 import java.sql.SQLTransactionRollbackException;
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.EnumMap;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
-/** Database product infered via JDBC. */
-public enum DatabaseProduct {
-  DERBY, MYSQL, POSTGRES, ORACLE, SQLSERVER, OTHER;
+import org.apache.hadoop.conf.Configurable;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hive.metastore.api.MetaException;
+import org.apache.hadoop.hive.metastore.conf.MetastoreConf;
+import org.apache.hadoop.hive.metastore.conf.MetastoreConf.ConfVars;
+import org.apache.hadoop.util.ReflectionUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
+/** Database product inferred via JDBC. Encapsulates all SQL logic associated 
with
+ * the database product.
+ * This class is a singleton, which is instantiated the first time
+ * method determineDatabaseProduct is invoked.
+ * Tests that need to create multiple instances can use the reset method
+ * */
+public class DatabaseProduct implements Configurable {
+  static final private Logger LOG = 
LoggerFactory.getLogger(DatabaseProduct.class.getName());
+
+  private static enum DbType {DERBY, MYSQL, POSTGRES, ORACLE, SQLSERVER, 
EXTERNAL, OTHER};
+  public DbType dbType;
+  
+  // Singleton instance
+  private static DatabaseProduct theDatabaseProduct;
+
+  static {
+    final Configuration conf = MetastoreConf.newMetastoreConf();
+    // Check if we are using an external database product
+    boolean isExternal = MetastoreConf.getBoolVar(conf, 
ConfVars.USE_CUSTOM_RDBMS);
+
+    if (isExternal) {
+      // The DatabaseProduct will be created by instantiating an external 
class via
+      // reflection. The external class can override any method in the current 
class
+      String className = MetastoreConf.getVar(conf, 
ConfVars.CUSTOM_RDBMS_CLASSNAME);
+      
+      if (className != null) {
+        try {
+          theDatabaseProduct = (DatabaseProduct)
+              ReflectionUtils.newInstance(Class.forName(className), conf);
+
+          theDatabaseProduct.dbType = DbType.EXTERNAL;
+        }catch (Exception e) {
+          LOG.warn("Unable to instantiate custom database product. Reverting 
to default", e);
+        }
+      }
+      else {
+        LOG.warn("metastore.use.custom.database.product was set, " +
+                 "but metastore.custom.database.product.classname was not. 
Reverting to default");
+      }
+    }
+  }
+
+  /**
+   * Private constructor for singleton class
+   * @param id
+   */
+  private DatabaseProduct() {}
+  
+  public static final String DERBY_NAME = "derby";
+  public static final String SQL_SERVER_NAME = "microsoft sql server";
+  public static final String MYSQL_NAME = "mysql";
+  public static final String POSTGRESQL_NAME = "postgresql";
+  public static final String ORACLE_NAME = "oracle";
+  public static final String OTHER_NAME = "other";
+  
   /**
    * Determine the database product type
    * @param productName string to defer database connection
    * @return database product type
    */
-  public static DatabaseProduct determineDatabaseProduct(String productName) 
throws SQLException {
+  public static DatabaseProduct determineDatabaseProduct(String productName) {
+    DbType dbt;
+
     if (productName == null) {
-      return OTHER;
+      productName = OTHER_NAME;
     }
+
     productName = productName.toLowerCase();
-    if (productName.contains("derby")) {
-      return DERBY;
-    } else if (productName.contains("microsoft sql server")) {
-      return SQLSERVER;
-    } else if (productName.contains("mysql")) {
-      return MYSQL;
-    } else if (productName.contains("oracle")) {
-      return ORACLE;
-    } else if (productName.contains("postgresql")) {
-      return POSTGRES;
+
+    if (productName.contains(DERBY_NAME)) {
+      dbt = DbType.DERBY;
+    } else if (productName.contains(SQL_SERVER_NAME)) {
+      dbt = DbType.SQLSERVER;
+    } else if (productName.contains(MYSQL_NAME)) {
+      dbt = DbType.MYSQL;
+    } else if (productName.contains(ORACLE_NAME)) {
+      dbt = DbType.ORACLE;
+    } else if (productName.contains(POSTGRESQL_NAME)) {
+      dbt = DbType.POSTGRES;
     } else {
-      return OTHER;
+      dbt = DbType.OTHER;
     }
+
+    // This method may be invoked by concurrent connections
+    synchronized (DatabaseProduct.class) {
+      if (theDatabaseProduct == null) {
+        theDatabaseProduct = new DatabaseProduct();
+      }
+  
+      theDatabaseProduct.dbType = dbt;
+    }
+    return theDatabaseProduct;
+  }
+
+  public final boolean isDERBY() {
+    return dbType == DbType.DERBY;
+  }
+
+  public final boolean isMYSQL() {
+    return dbType == DbType.MYSQL;
   }
 
-  public static boolean isDeadlock(DatabaseProduct dbProduct, SQLException e) {
+  public final boolean isORACLE() {
+    return dbType == DbType.ORACLE;
+  }
+
+  public final boolean isSQLSERVER() {
+    return dbType == DbType.SQLSERVER;
+  }
+
+  public final boolean isPOSTGRES() {
+    return dbType == DbType.POSTGRES;
+  }
+
+  public final boolean isEXTERNAL() {
+    return dbType == DbType.EXTERNAL;

Review comment:
       Its getting a bit confusing with the usage of external, other, custom. 
Can this be avoided? If not, we should document it somewhere in this class.

##########
File path: 
standalone-metastore/metastore-common/src/main/java/org/apache/hadoop/hive/metastore/conf/MetastoreConf.java
##########
@@ -1337,6 +1337,13 @@ public static ConfVars getMetaConf(String name) {
     HIVE_TXN_STATS_ENABLED("hive.txn.stats.enabled", "hive.txn.stats.enabled", 
true,
         "Whether Hive supports transactional stats (accurate stats for 
transactional tables)"),
 
+    // External RDBMS support
+    USE_CUSTOM_RDBMS("metastore.use.custom.database.product",
+            "hive.metastore.use.custom.database.product", false,
+            "Use an external RDBMS for the metastore"),
+    CUSTOM_RDBMS_CLASSNAME("metastore.custom.database.product.classname", 
"hive.metastore.custom.database.product.classname", "none",
+          "Hook for external RDBMS. This class will be instantiated only when 
metastore.use.custom.database.product is set to true."),

Review comment:
       nit, can you fix the formatting here?

##########
File path: 
standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/DatabaseProduct.java
##########
@@ -20,71 +20,646 @@
 
 import java.sql.SQLException;
 import java.sql.SQLTransactionRollbackException;
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.EnumMap;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
-/** Database product infered via JDBC. */
-public enum DatabaseProduct {
-  DERBY, MYSQL, POSTGRES, ORACLE, SQLSERVER, OTHER;
+import org.apache.hadoop.conf.Configurable;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hive.metastore.api.MetaException;
+import org.apache.hadoop.hive.metastore.conf.MetastoreConf;
+import org.apache.hadoop.hive.metastore.conf.MetastoreConf.ConfVars;
+import org.apache.hadoop.util.ReflectionUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
+/** Database product inferred via JDBC. Encapsulates all SQL logic associated 
with
+ * the database product.
+ * This class is a singleton, which is instantiated the first time
+ * method determineDatabaseProduct is invoked.
+ * Tests that need to create multiple instances can use the reset method
+ * */
+public class DatabaseProduct implements Configurable {
+  static final private Logger LOG = 
LoggerFactory.getLogger(DatabaseProduct.class.getName());
+
+  private static enum DbType {DERBY, MYSQL, POSTGRES, ORACLE, SQLSERVER, 
EXTERNAL, OTHER};
+  public DbType dbType;
+  
+  // Singleton instance
+  private static DatabaseProduct theDatabaseProduct;
+
+  static {
+    final Configuration conf = MetastoreConf.newMetastoreConf();
+    // Check if we are using an external database product
+    boolean isExternal = MetastoreConf.getBoolVar(conf, 
ConfVars.USE_CUSTOM_RDBMS);
+
+    if (isExternal) {
+      // The DatabaseProduct will be created by instantiating an external 
class via
+      // reflection. The external class can override any method in the current 
class
+      String className = MetastoreConf.getVar(conf, 
ConfVars.CUSTOM_RDBMS_CLASSNAME);
+      
+      if (className != null) {
+        try {
+          theDatabaseProduct = (DatabaseProduct)
+              ReflectionUtils.newInstance(Class.forName(className), conf);
+
+          theDatabaseProduct.dbType = DbType.EXTERNAL;
+        }catch (Exception e) {
+          LOG.warn("Unable to instantiate custom database product. Reverting 
to default", e);
+        }
+      }
+      else {
+        LOG.warn("metastore.use.custom.database.product was set, " +
+                 "but metastore.custom.database.product.classname was not. 
Reverting to default");
+      }
+    }
+  }
+
+  /**
+   * Private constructor for singleton class
+   * @param id
+   */
+  private DatabaseProduct() {}
+  
+  public static final String DERBY_NAME = "derby";
+  public static final String SQL_SERVER_NAME = "microsoft sql server";
+  public static final String MYSQL_NAME = "mysql";
+  public static final String POSTGRESQL_NAME = "postgresql";
+  public static final String ORACLE_NAME = "oracle";
+  public static final String OTHER_NAME = "other";
+  
   /**
    * Determine the database product type
    * @param productName string to defer database connection
    * @return database product type
    */
-  public static DatabaseProduct determineDatabaseProduct(String productName) 
throws SQLException {
+  public static DatabaseProduct determineDatabaseProduct(String productName) {
+    DbType dbt;
+
     if (productName == null) {
-      return OTHER;
+      productName = OTHER_NAME;
     }
+
     productName = productName.toLowerCase();
-    if (productName.contains("derby")) {
-      return DERBY;
-    } else if (productName.contains("microsoft sql server")) {
-      return SQLSERVER;
-    } else if (productName.contains("mysql")) {
-      return MYSQL;
-    } else if (productName.contains("oracle")) {
-      return ORACLE;
-    } else if (productName.contains("postgresql")) {
-      return POSTGRES;
+
+    if (productName.contains(DERBY_NAME)) {
+      dbt = DbType.DERBY;
+    } else if (productName.contains(SQL_SERVER_NAME)) {
+      dbt = DbType.SQLSERVER;
+    } else if (productName.contains(MYSQL_NAME)) {
+      dbt = DbType.MYSQL;
+    } else if (productName.contains(ORACLE_NAME)) {
+      dbt = DbType.ORACLE;
+    } else if (productName.contains(POSTGRESQL_NAME)) {
+      dbt = DbType.POSTGRES;
     } else {
-      return OTHER;
+      dbt = DbType.OTHER;
     }
+
+    // This method may be invoked by concurrent connections
+    synchronized (DatabaseProduct.class) {
+      if (theDatabaseProduct == null) {
+        theDatabaseProduct = new DatabaseProduct();
+      }
+  
+      theDatabaseProduct.dbType = dbt;
+    }
+    return theDatabaseProduct;
+  }
+
+  public final boolean isDERBY() {
+    return dbType == DbType.DERBY;
+  }
+
+  public final boolean isMYSQL() {
+    return dbType == DbType.MYSQL;
   }
 
-  public static boolean isDeadlock(DatabaseProduct dbProduct, SQLException e) {
+  public final boolean isORACLE() {
+    return dbType == DbType.ORACLE;
+  }
+
+  public final boolean isSQLSERVER() {
+    return dbType == DbType.SQLSERVER;
+  }
+
+  public final boolean isPOSTGRES() {
+    return dbType == DbType.POSTGRES;
+  }
+
+  public final boolean isEXTERNAL() {
+    return dbType == DbType.EXTERNAL;
+  }
+
+  public final boolean isOTHER() {
+    return dbType == DbType.OTHER;
+  }
+
+  public boolean isDeadlock(SQLException e) {
     return e instanceof SQLTransactionRollbackException
-        || ((dbProduct == MYSQL || dbProduct == POSTGRES || dbProduct == 
SQLSERVER)
+        || ((isMYSQL() || isPOSTGRES() || isSQLSERVER() || isEXTERNAL())
             && "40001".equals(e.getSQLState()))
-        || (dbProduct == POSTGRES && "40P01".equals(e.getSQLState()))
-        || (dbProduct == ORACLE && (e.getMessage() != null && 
(e.getMessage().contains("deadlock detected")
+        || (isPOSTGRES() && "40P01".equals(e.getSQLState()))
+        || (isORACLE() && (e.getMessage() != null && 
(e.getMessage().contains("deadlock detected")
             || e.getMessage().contains("can't serialize access for this 
transaction"))));
   }
 
   /**
    * Whether the RDBMS has restrictions on IN list size (explicit, or poor 
perf-based).
    */
-  public static boolean needsInBatching(DatabaseProduct dbType) {
-    return dbType == ORACLE || dbType == SQLSERVER;
+  protected boolean needsInBatching() {
+    return isORACLE() || isSQLSERVER();
   }
 
   /**
    * Whether the RDBMS has a bug in join and filter operation order described 
in DERBY-6358.
    */
-  public static boolean hasJoinOperationOrderBug(DatabaseProduct dbType) {
-    return dbType == DERBY || dbType == ORACLE || dbType == POSTGRES;
+  protected boolean hasJoinOperationOrderBug() {
+    return isDERBY() || isORACLE() || isPOSTGRES();
   }
 
-  public static String getHiveSchemaPostfix(DatabaseProduct dbType) {
+  public String getHiveSchemaPostfix() {
     switch (dbType) {
     case SQLSERVER:
       return "mssql";
     case DERBY:
     case MYSQL:
     case POSTGRES:
     case ORACLE:
+    case EXTERNAL:
       return dbType.name().toLowerCase();
     case OTHER:
     default:
       return null;
     }
   }
+
+  public static void reset() {

Review comment:
       Curious to know why we would need this? If we don't do this may be we 
can make theDatabaseProduct as a final variable.

##########
File path: 
standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/DatabaseProduct.java
##########
@@ -20,71 +20,646 @@
 
 import java.sql.SQLException;
 import java.sql.SQLTransactionRollbackException;
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.EnumMap;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
-/** Database product infered via JDBC. */
-public enum DatabaseProduct {
-  DERBY, MYSQL, POSTGRES, ORACLE, SQLSERVER, OTHER;
+import org.apache.hadoop.conf.Configurable;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hive.metastore.api.MetaException;
+import org.apache.hadoop.hive.metastore.conf.MetastoreConf;
+import org.apache.hadoop.hive.metastore.conf.MetastoreConf.ConfVars;
+import org.apache.hadoop.util.ReflectionUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
+/** Database product inferred via JDBC. Encapsulates all SQL logic associated 
with
+ * the database product.
+ * This class is a singleton, which is instantiated the first time
+ * method determineDatabaseProduct is invoked.
+ * Tests that need to create multiple instances can use the reset method
+ * */
+public class DatabaseProduct implements Configurable {
+  static final private Logger LOG = 
LoggerFactory.getLogger(DatabaseProduct.class.getName());
+
+  private static enum DbType {DERBY, MYSQL, POSTGRES, ORACLE, SQLSERVER, 
EXTERNAL, OTHER};
+  public DbType dbType;
+  
+  // Singleton instance
+  private static DatabaseProduct theDatabaseProduct;
+
+  static {
+    final Configuration conf = MetastoreConf.newMetastoreConf();
+    // Check if we are using an external database product
+    boolean isExternal = MetastoreConf.getBoolVar(conf, 
ConfVars.USE_CUSTOM_RDBMS);
+
+    if (isExternal) {
+      // The DatabaseProduct will be created by instantiating an external 
class via
+      // reflection. The external class can override any method in the current 
class
+      String className = MetastoreConf.getVar(conf, 
ConfVars.CUSTOM_RDBMS_CLASSNAME);
+      
+      if (className != null) {
+        try {
+          theDatabaseProduct = (DatabaseProduct)
+              ReflectionUtils.newInstance(Class.forName(className), conf);
+
+          theDatabaseProduct.dbType = DbType.EXTERNAL;
+        }catch (Exception e) {
+          LOG.warn("Unable to instantiate custom database product. Reverting 
to default", e);
+        }
+      }
+      else {
+        LOG.warn("metastore.use.custom.database.product was set, " +
+                 "but metastore.custom.database.product.classname was not. 
Reverting to default");
+      }
+    }
+  }
+
+  /**
+   * Private constructor for singleton class
+   * @param id
+   */
+  private DatabaseProduct() {}
+  
+  public static final String DERBY_NAME = "derby";
+  public static final String SQL_SERVER_NAME = "microsoft sql server";
+  public static final String MYSQL_NAME = "mysql";
+  public static final String POSTGRESQL_NAME = "postgresql";
+  public static final String ORACLE_NAME = "oracle";
+  public static final String OTHER_NAME = "other";
+  
   /**
    * Determine the database product type
    * @param productName string to defer database connection
    * @return database product type
    */
-  public static DatabaseProduct determineDatabaseProduct(String productName) 
throws SQLException {
+  public static DatabaseProduct determineDatabaseProduct(String productName) {
+    DbType dbt;
+
     if (productName == null) {
-      return OTHER;
+      productName = OTHER_NAME;
     }
+
     productName = productName.toLowerCase();
-    if (productName.contains("derby")) {
-      return DERBY;
-    } else if (productName.contains("microsoft sql server")) {
-      return SQLSERVER;
-    } else if (productName.contains("mysql")) {
-      return MYSQL;
-    } else if (productName.contains("oracle")) {
-      return ORACLE;
-    } else if (productName.contains("postgresql")) {
-      return POSTGRES;
+
+    if (productName.contains(DERBY_NAME)) {

Review comment:
       Can we refactor these lines (108-119) into a separate private method 
which can be used like below at line 100?
   
   if (theDatabaseProduct != null) {
     Preconditions.checkState(this.dbType == getDbType(productName));
     return theDatabaseProduct;
   }

##########
File path: 
standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/DatabaseProduct.java
##########
@@ -20,71 +20,646 @@
 
 import java.sql.SQLException;
 import java.sql.SQLTransactionRollbackException;
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.EnumMap;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
-/** Database product infered via JDBC. */
-public enum DatabaseProduct {
-  DERBY, MYSQL, POSTGRES, ORACLE, SQLSERVER, OTHER;
+import org.apache.hadoop.conf.Configurable;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hive.metastore.api.MetaException;
+import org.apache.hadoop.hive.metastore.conf.MetastoreConf;
+import org.apache.hadoop.hive.metastore.conf.MetastoreConf.ConfVars;
+import org.apache.hadoop.util.ReflectionUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
+/** Database product inferred via JDBC. Encapsulates all SQL logic associated 
with
+ * the database product.
+ * This class is a singleton, which is instantiated the first time
+ * method determineDatabaseProduct is invoked.
+ * Tests that need to create multiple instances can use the reset method
+ * */
+public class DatabaseProduct implements Configurable {
+  static final private Logger LOG = 
LoggerFactory.getLogger(DatabaseProduct.class.getName());
+
+  private static enum DbType {DERBY, MYSQL, POSTGRES, ORACLE, SQLSERVER, 
EXTERNAL, OTHER};
+  public DbType dbType;
+  
+  // Singleton instance
+  private static DatabaseProduct theDatabaseProduct;
+
+  static {
+    final Configuration conf = MetastoreConf.newMetastoreConf();

Review comment:
       I think instead of this getting initialized in the static block, it 
would be better to pass the configuration object from the HiveMetastore.java in 
a constructor

##########
File path: 
standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/DatabaseProduct.java
##########
@@ -20,71 +20,646 @@
 
 import java.sql.SQLException;
 import java.sql.SQLTransactionRollbackException;
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.EnumMap;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
-/** Database product infered via JDBC. */
-public enum DatabaseProduct {
-  DERBY, MYSQL, POSTGRES, ORACLE, SQLSERVER, OTHER;
+import org.apache.hadoop.conf.Configurable;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hive.metastore.api.MetaException;
+import org.apache.hadoop.hive.metastore.conf.MetastoreConf;
+import org.apache.hadoop.hive.metastore.conf.MetastoreConf.ConfVars;
+import org.apache.hadoop.util.ReflectionUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
+/** Database product inferred via JDBC. Encapsulates all SQL logic associated 
with
+ * the database product.
+ * This class is a singleton, which is instantiated the first time
+ * method determineDatabaseProduct is invoked.
+ * Tests that need to create multiple instances can use the reset method
+ * */
+public class DatabaseProduct implements Configurable {
+  static final private Logger LOG = 
LoggerFactory.getLogger(DatabaseProduct.class.getName());
+
+  private static enum DbType {DERBY, MYSQL, POSTGRES, ORACLE, SQLSERVER, 
EXTERNAL, OTHER};
+  public DbType dbType;
+  
+  // Singleton instance
+  private static DatabaseProduct theDatabaseProduct;
+
+  static {
+    final Configuration conf = MetastoreConf.newMetastoreConf();
+    // Check if we are using an external database product
+    boolean isExternal = MetastoreConf.getBoolVar(conf, 
ConfVars.USE_CUSTOM_RDBMS);
+
+    if (isExternal) {
+      // The DatabaseProduct will be created by instantiating an external 
class via
+      // reflection. The external class can override any method in the current 
class
+      String className = MetastoreConf.getVar(conf, 
ConfVars.CUSTOM_RDBMS_CLASSNAME);
+      
+      if (className != null) {
+        try {
+          theDatabaseProduct = (DatabaseProduct)
+              ReflectionUtils.newInstance(Class.forName(className), conf);
+
+          theDatabaseProduct.dbType = DbType.EXTERNAL;
+        }catch (Exception e) {
+          LOG.warn("Unable to instantiate custom database product. Reverting 
to default", e);
+        }
+      }
+      else {
+        LOG.warn("metastore.use.custom.database.product was set, " +
+                 "but metastore.custom.database.product.classname was not. 
Reverting to default");
+      }
+    }
+  }
+
+  /**
+   * Private constructor for singleton class
+   * @param id
+   */
+  private DatabaseProduct() {}
+  
+  public static final String DERBY_NAME = "derby";
+  public static final String SQL_SERVER_NAME = "microsoft sql server";
+  public static final String MYSQL_NAME = "mysql";
+  public static final String POSTGRESQL_NAME = "postgresql";
+  public static final String ORACLE_NAME = "oracle";
+  public static final String OTHER_NAME = "other";
+  
   /**
    * Determine the database product type
    * @param productName string to defer database connection
    * @return database product type
    */
-  public static DatabaseProduct determineDatabaseProduct(String productName) 
throws SQLException {
+  public static DatabaseProduct determineDatabaseProduct(String productName) {
+    DbType dbt;
+
     if (productName == null) {
-      return OTHER;
+      productName = OTHER_NAME;
     }
+
     productName = productName.toLowerCase();
-    if (productName.contains("derby")) {
-      return DERBY;
-    } else if (productName.contains("microsoft sql server")) {
-      return SQLSERVER;
-    } else if (productName.contains("mysql")) {
-      return MYSQL;
-    } else if (productName.contains("oracle")) {
-      return ORACLE;
-    } else if (productName.contains("postgresql")) {
-      return POSTGRES;
+
+    if (productName.contains(DERBY_NAME)) {
+      dbt = DbType.DERBY;
+    } else if (productName.contains(SQL_SERVER_NAME)) {
+      dbt = DbType.SQLSERVER;
+    } else if (productName.contains(MYSQL_NAME)) {
+      dbt = DbType.MYSQL;
+    } else if (productName.contains(ORACLE_NAME)) {
+      dbt = DbType.ORACLE;
+    } else if (productName.contains(POSTGRESQL_NAME)) {
+      dbt = DbType.POSTGRES;
     } else {
-      return OTHER;
+      dbt = DbType.OTHER;
     }
+
+    // This method may be invoked by concurrent connections
+    synchronized (DatabaseProduct.class) {

Review comment:
       why not add a happy path check on line 100 which returns 
theDatabaseProduct if it is not null.




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


Issue Time Tracking
-------------------

    Worklog Id:     (was: 484804)
    Time Spent: 20m  (was: 10m)

> Plugin for external DatabaseProduct in standalone HMS
> -----------------------------------------------------
>
>                 Key: HIVE-24120
>                 URL: https://issues.apache.org/jira/browse/HIVE-24120
>             Project: Hive
>          Issue Type: Improvement
>          Components: Standalone Metastore
>    Affects Versions: 3.1.1
>            Reporter: Gustavo Arocena
>            Assignee: Gustavo Arocena
>            Priority: Minor
>              Labels: pull-request-available
>             Fix For: 4.0.0
>
>          Time Spent: 20m
>  Remaining Estimate: 0h
>
> Add a pluggable way to support ANSI compliant databases as backends for 
> standalone HMS



--
This message was sent by Atlassian Jira
(v8.3.4#803005)

Reply via email to