package io.ebeaninternal.server.core;
import io.ebean.config.ServerConfig;
import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebean.config.dbplatform.clickhouse.ClickHousePlatform;
import io.ebean.config.dbplatform.cockroach.CockroachPlatform;
import io.ebean.config.dbplatform.db2.DB2Platform;
import io.ebean.config.dbplatform.h2.H2Platform;
import io.ebean.config.dbplatform.hana.HanaPlatform;
import io.ebean.config.dbplatform.hsqldb.HsqldbPlatform;
import io.ebean.config.dbplatform.mysql.MySqlPlatform;
import io.ebean.config.dbplatform.oracle.OraclePlatform;
import io.ebean.config.dbplatform.postgres.Postgres8Platform;
import io.ebean.config.dbplatform.postgres.PostgresPlatform;
import io.ebean.config.dbplatform.sqlanywhere.SqlAnywherePlatform;
import io.ebean.config.dbplatform.sqlite.SQLitePlatform;
import io.ebean.config.dbplatform.sqlserver.SqlServer16Platform;
import io.ebean.config.dbplatform.sqlserver.SqlServer17Platform;
import io.ebean.util.JdbcClose;
import io.ebeaninternal.dbmigration.DbOffline;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.persistence.PersistenceException;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
Create a DatabasePlatform from the configuration.
Will used platform name or use the meta data from the JDBC driver to
determine the platform automatically.
/**
* Create a DatabasePlatform from the configuration.
* <p>
* Will used platform name or use the meta data from the JDBC driver to
* determine the platform automatically.
* </p>
*/
public class DatabasePlatformFactory {
private static final Logger logger = LoggerFactory.getLogger(DatabasePlatformFactory.class);
Create the appropriate database specific platform.
/**
* Create the appropriate database specific platform.
*/
public DatabasePlatform create(ServerConfig serverConfig) {
try {
String offlinePlatform = DbOffline.getPlatform();
if (offlinePlatform != null) {
logger.info("offline platform [{}]", offlinePlatform);
return byDatabaseName(offlinePlatform);
}
if (serverConfig.getDatabasePlatformName() != null) {
// choose based on dbName
return byDatabaseName(serverConfig.getDatabasePlatformName());
}
if (serverConfig.getDataSourceConfig().isOffline()) {
throw new PersistenceException("You must specify a DatabasePlatformName when you are offline");
}
// guess using meta data from driver
return byDataSource(serverConfig.getDataSource());
} catch (Exception ex) {
throw new PersistenceException(ex);
}
}
Lookup the platform by name.
/**
* Lookup the platform by name.
*/
private DatabasePlatform byDatabaseName(String dbName) {
dbName = dbName.toLowerCase();
if (dbName.equals("h2")) {
return new H2Platform();
}
if (dbName.equals("mysql")) {
return new MySqlPlatform();
}
if (dbName.equals("postgres") || dbName.equals("postgres9")) {
return new PostgresPlatform();
}
if (dbName.equals("postgres8") || dbName.equals("postgres83")) {
return new Postgres8Platform();
}
if (dbName.equals("oracle") || dbName.equals("oracle10") || dbName.equals("oracle9")) {
return new OraclePlatform();
}
if (dbName.equals("sqlserver16")) {
return new SqlServer16Platform();
}
if (dbName.equals("sqlserver17")) {
return new SqlServer17Platform();
}
if (dbName.equals("sqlserver")) {
throw new IllegalArgumentException("Please choose the more specific sqlserver16 or sqlserver17 platform. Refer to issue #1340 for details");
}
if (dbName.equals("sqlanywhere")) {
return new SqlAnywherePlatform();
}
if (dbName.equals("db2")) {
return new DB2Platform();
}
if (dbName.equals("clickhouse")) {
return new ClickHousePlatform();
}
if (dbName.equals("sqlite")) {
return new SQLitePlatform();
}
if (dbName.equals("hana")) {
return new HanaPlatform();
}
throw new RuntimeException("database platform " + dbName + " is not known?");
}
Use JDBC DatabaseMetaData to determine the platform.
/**
* Use JDBC DatabaseMetaData to determine the platform.
*/
private DatabasePlatform byDataSource(DataSource dataSource) {
Connection connection = null;
try {
connection = dataSource.getConnection();
DatabaseMetaData metaData = connection.getMetaData();
return byDatabaseMeta(metaData, connection);
} catch (SQLException ex) {
throw new PersistenceException(ex);
} finally {
JdbcClose.close(connection);
}
}
Find the platform by the metaData.getDatabaseProductName().
/**
* Find the platform by the metaData.getDatabaseProductName().
*/
private DatabasePlatform byDatabaseMeta(DatabaseMetaData metaData, Connection connection) throws SQLException {
String dbProductName = metaData.getDatabaseProductName();
dbProductName = dbProductName.toLowerCase();
if (dbProductName.contains("oracle")) {
return new OraclePlatform();
} else if (dbProductName.contains("microsoft")) {
throw new IllegalArgumentException("For SqlServer please explicitly choose either sqlserver16 or sqlserver17 as the platform via ServerConfig.setDatabasePlatformName. Refer to issue #1340 for more details");
} else if (dbProductName.contains("mysql")) {
return new MySqlPlatform();
} else if (dbProductName.contains("h2")) {
return new H2Platform();
} else if (dbProductName.contains("hsql database engine")) {
return new HsqldbPlatform();
} else if (dbProductName.contains("postgres")) {
return readPostgres(connection);
} else if (dbProductName.contains("sqlite")) {
return new SQLitePlatform();
} else if (dbProductName.contains("db2")) {
return new DB2Platform();
} else if (dbProductName.contains("sql anywhere")) {
return new SqlAnywherePlatform();
} else if (dbProductName.contains("hdb")) {
return new HanaPlatform();
} else if (dbProductName.contains("clickhouse")) {
return new ClickHousePlatform();
}
// use the standard one
return new DatabasePlatform();
}
Use a select version() query as it could be Postgres or CockroachDB.
/**
* Use a select version() query as it could be Postgres or CockroachDB.
*/
private static PostgresPlatform readPostgres(Connection connection) {
// Postgres driver uses a hardcoded product name so use version() query
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
statement = connection.prepareStatement("SELECT version() AS \"version\"");
resultSet = statement.executeQuery();
if (resultSet.next()) {
String productVersion = resultSet.getString("version").toLowerCase();
if (productVersion.contains("cockroach")) {
return new CockroachPlatform();
}
}
} catch (SQLException e) {
logger.warn("Error running detection query on Postgres", e);
} finally {
JdbcClose.close(resultSet);
JdbcClose.close(statement);
}
// Real Postgres
return new PostgresPlatform();
}
}