Skip to content

Instantly share code, notes, and snippets.

@lbruun
Last active August 27, 2022 20:17
Show Gist options
  • Select an option

  • Save lbruun/9a7775b0bc3aca868c9500bfa2df42a0 to your computer and use it in GitHub Desktop.

Select an option

Save lbruun/9a7775b0bc3aca868c9500bfa2df42a0 to your computer and use it in GitHub Desktop.

Revisions

  1. lbruun revised this gist Aug 27, 2022. 1 changed file with 2 additions and 3 deletions.
    5 changes: 2 additions & 3 deletions DatabaseEngine.java
    Original file line number Diff line number Diff line change
    @@ -254,9 +254,8 @@ public static DatabaseEngine getDatabaseEngine(DatabaseMetaData databaseMetaData
    // promise on the value of the ProductName. This is why we use the ProductName
    // with some caution below.
    // See : https://www.ibm.com/docs/en/db2-for-zos/11?topic=methods-databasemetadata-identifying-type-data-server
    if (databaseProductNameLower.equals("db2")
    || databaseProductNameLower.contains("db2 ")
    || databaseProductNameLower.contains(" db2") ) {
    if ( databaseProductNameLower.equals("db2")
    | databaseProductNameLower.matches("db2[.-/ ].*") ) {
    if (databaseProductVersion != null && databaseProductVersion.length() > 3) {
    String ppp = databaseProductVersion.substring(0, 3);
    switch (ppp) {
  2. lbruun revised this gist Aug 27, 2022. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions DatabaseEngine.java
    Original file line number Diff line number Diff line change
    @@ -253,6 +253,7 @@ public static DatabaseEngine getDatabaseEngine(DatabaseMetaData databaseMetaData
    // primarily from the ProductVersion value whereas IBM makes no real
    // promise on the value of the ProductName. This is why we use the ProductName
    // with some caution below.
    // See : https://www.ibm.com/docs/en/db2-for-zos/11?topic=methods-databasemetadata-identifying-type-data-server
    if (databaseProductNameLower.equals("db2")
    || databaseProductNameLower.contains("db2 ")
    || databaseProductNameLower.contains(" db2") ) {
  3. lbruun created this gist Feb 7, 2021.
    332 changes: 332 additions & 0 deletions DatabaseEngine.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,332 @@
    /*
    * Copyright 2021 lbruun.net.
    *
    * Licensed 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 net.lbruun.jdbc;

    import java.sql.Connection;
    import java.sql.DatabaseMetaData;
    import java.sql.SQLException;
    import java.util.Locale;
    import java.util.Objects;
    import javax.sql.DataSource;

    /**
    * Database RDBMS engines.
    *
    * <p>
    * Provides enums for most widely uses RDBMSs and methods to detect
    * these from their {@link java.sql.DatabaseMetaData} signature.
    *
    * @author lbruun
    */
    public enum DatabaseEngine {

    /**
    * PostgreSQL database
    */
    POSTGRESQL(Codes.POSTGRESQL_CODE),
    /**
    * Microsoft SQL Server database
    */
    MSSQL(Codes.MSSQL_CODE),
    /**
    * Oracle RDBMS database
    */
    ORACLE(Codes.ORACLE_CODE),
    /**
    * MySQL database
    */
    MYSQL(Codes.MYSQL_CODE),
    /**
    * MariaDB database
    */
    MARIADB(Codes.MARIADB_CODE),
    /**
    * Db2 on Linux, Unix and Windows systems
    */
    DB2_LUW(Codes.DB2_LUW_CODE),
    /**
    * Db2 on z/OS
    */
    DB2_ZOS(Codes.DB2_ZOS_CODE),
    /**
    * H2 database
    */
    H2(Codes.H2_CODE),
    /**
    * Amazon Redshift database
    */
    REDSHIFT(Codes.REDSHIFT_CODE),
    /**
    * Apache Derby database
    */
    DERBY(Codes.DERBY_CODE),
    /**
    * HyperSQL database
    */
    HSQLDB(Codes.HSQLDB_CODE);


    /**
    * Unique string codes for database engines.
    * <p>
    * By convention these codes are in lower-case.
    */
    public static class Codes {
    /**
    * PostgreSQL database
    */
    public static final String POSTGRESQL_CODE = "postgresql";
    /**
    * Microsoft SQL Server database
    */
    public static final String MSSQL_CODE = "mssql";
    /**
    * Oracle RDBMS database
    */
    public static final String ORACLE_CODE = "oracle";
    /**
    * MySQL database
    */
    public static final String MYSQL_CODE = "mysql";
    /**
    * MariaDB database
    */
    public static final String MARIADB_CODE = "mariadb";
    /**
    * Db2 on Linux, Unix and Windows systems
    */
    public static final String DB2_LUW_CODE = "db2";
    /**
    * Db2 on z/OS
    */
    public static final String DB2_ZOS_CODE = "db2z";
    /**
    * H2 database
    */
    public static final String H2_CODE = "h2";
    /**
    * Amazon Redshift
    */
    public static final String REDSHIFT_CODE = "redshift";
    /**
    * Apache Derby
    */
    public static final String DERBY_CODE = "derby";
    /**
    * HyperSQL database
    */
    public static final String HSQLDB_CODE = "hsqldb";
    }



    private String code;

    DatabaseEngine(String code) {
    this.code = code;
    }

    /**
    * Gets the string code for the Database Engine.
    * @return
    */
    public String getCode() {
    return code;
    }

    /**
    * Gets the {@code DatabaseEngine} which corresponds to
    * a code value such as "mysql".
    * @param code string code representing a unique value for a
    * database engine.
    * @return the DatabaseEngine corresponding to the code value
    * or {@code null} if no match for the code value was found.
    */
    public static DatabaseEngine getDatabaseEngineFromCode(String code) {
    if (code == null) {
    return null;
    }
    for(DatabaseEngine dbEngine : DatabaseEngine.values()) {
    if (dbEngine.getCode().equals(code)) {
    return dbEngine;
    }
    }
    return null;
    }

    /**
    * Find {@code DatabaseEngine} from a JDBC DatabaseMetaData
    * object.
    *
    * @return the database engine or {@code null} if the database cannot
    * be determined from the input.
    * @throws SQLException if an error occurs while retrieving data from the
    * {@code databaseMetaData} object.
    */
    public static DatabaseEngine getDatabaseEngine(DatabaseMetaData databaseMetaData) throws SQLException {

    // Sanity check
    Objects.requireNonNull(databaseMetaData, "databaseProductName cannot be null");

    String databaseProductName = databaseMetaData.getDatabaseProductName();
    String databaseProductVersion= databaseMetaData.getDatabaseProductVersion();

    String databaseProductNameLower = databaseProductName.toLowerCase(Locale.US);


    // Detect MySQL
    // Note: the MySQL JDBC driver (known as Connector/J) is open-sourced
    // and available here: https://github.com/mysql/mysql-connector-j
    // so pretty easy to see what the driver returns for ProductName.
    if (databaseProductName.equals("MySQL")) {
    return MYSQL;
    }

    // Detect MariaDB
    if (databaseProductName.equals("MariaDB")) {
    return MARIADB;
    }

    // Detect MS SQL Server
    // Note: The MS SQL Server has been open-sourced and is now available
    // here: https://github.com/microsoft/mssql-jdbc so it is pretty easy
    // to see what the driver returns for ProductName.
    if (databaseProductName.equals("Microsoft SQL Server")) {
    return MSSQL;
    }

    // Detect Oracle RDBMS
    if (databaseProductNameLower.startsWith("oracle")) {
    return ORACLE;
    }

    // Detect PostgreSQL
    // According to documentation on the PgDatabaseMetaData class the
    // ProductName will always be "PostgreSQL".
    if (databaseProductName.equals("PostgreSQL")) {
    return POSTGRESQL;
    }

    // Detect H2
    // ProductName will always be "H2".
    if (databaseProductName.equals("H2")) {
    return H2;
    }

    // Detect Amazon Redshift
    // ProductName will always be "Redshift".
    // See https://github.com/aws/amazon-redshift-jdbc-driver/blob/master/src/main/java/com/amazon/redshift/jdbc/RedshiftDatabaseMetaData.java
    // (Amazon Redshift used to ask users to use the PostgreSQL JDBC driver
    // - which will always return "PostgreSQL" - but nowadays they have their
    // own dedicated JDBC driver)
    if (databaseProductName.equals("Redshift")) {
    return REDSHIFT;
    }

    // Detect Apache Derby
    if (databaseProductName.equals("Apache Derby")) {
    return DERBY;
    }

    // Detect HyperSQL
    // The HSQLDB JDBC driver always returns the value of
    // org.hsqldb.persist.HsqlDatabaseProperties#PRODUCT_NAME
    if (databaseProductNameLower.equals("hsql database engine")) {
    return HSQLDB;
    }

    // Detect IBM Db2
    // According to IBM's documentation the database engine must be detected
    // primarily from the ProductVersion value whereas IBM makes no real
    // promise on the value of the ProductName. This is why we use the ProductName
    // with some caution below.
    if (databaseProductNameLower.equals("db2")
    || databaseProductNameLower.contains("db2 ")
    || databaseProductNameLower.contains(" db2") ) {
    if (databaseProductVersion != null && databaseProductVersion.length() > 3) {
    String ppp = databaseProductVersion.substring(0, 3);
    switch (ppp) {
    case "DSN":
    return DB2_ZOS;
    case "SQL":
    return DB2_LUW;
    default:
    }
    }
    }

    // Cannot determine
    return null;
    }



    /**
    * Find {@code DatabaseEngine} from a JDBC Connection.
    * The connection is left untouched (not closed by this method).
    *
    * @return the database engine or {@code null} if the database cannot
    * be determined from the input.
    * @throws SQLException if an error occurs while retrieving data from the
    * {@code connection} object.
    */
    public static DatabaseEngine getDatabaseEngine(Connection connection) throws SQLException {
    Objects.requireNonNull(connection, "connection cannot be null");
    return getDatabaseEngine(connection.getMetaData());
    }

    /**
    * Find {@code DatabaseEngine} from a JDBC DataSource.
    *
    * @param dataSource opens a connection from this DataSource. The connection
    * is closed again before the the method returns.
    * @param username username for connecting to database engine. May be
    * {@code null} in which case a connection is obtained from the DataSource
    * without explicitly specifying username/password.
    * @param password password for connecting to database engine. May be
    * {@code null} in which case a connection is obtained from the DataSource
    * without explicitly specifying username/password.
    * @return the database engine or {@code null} if the database cannot
    * be determined from the input.
    * @throws SQLException if an error occurs while retrieving data from the
    * {@code dataSource} object.
    */
    public static DatabaseEngine getDatabaseEngine(DataSource dataSource, String username, String password) throws SQLException {
    Objects.requireNonNull(dataSource, "dataSource cannot be null");
    try (Connection connection
    = (username == null) ? dataSource.getConnection() : dataSource.getConnection(username, password)) {
    return getDatabaseEngine(connection.getMetaData());
    }
    }

    /**
    * Find {@code DatabaseEngine} from a JDBC DataSource.
    *
    * <p>
    * Same as calling {@link #getDatabaseEngine(javax.sql.DataSource, java.lang.String, java.lang.String)
    * getDatabaseEngine(dataSource, null, null)}.
    * @param dataSource opens a connection from this DataSource. The connection
    * is closed again before the the method returns.
    * @return the database engine or {@code null} if the database cannot
    * be determined from the input.
    * @throws SQLException if an error occurs while retrieving data from the
    * {@code dataSource} object.
    * @see #getDatabaseEngine(javax.sql.DataSource, java.lang.String, java.lang.String)
    */
    public static DatabaseEngine getDatabaseEngine(DataSource dataSource) throws SQLException {
    return getDatabaseEngine(dataSource, null, null);
    }
    }