#1344 - ENH: Add initial Cockroach DB support ... need to review JSON and DB ARRAY support

This commit is contained in:
Rob Bygrave
2018-03-09 16:54:38 +13:00
parent 6c8cf0c5b7
commit 8ac1b745df
7 changed files with 141 additions and 9 deletions
@@ -517,6 +517,13 @@ public class DatabasePlatform {
this.forwardOnlyHintOnFindIterate = forwardOnlyHintOnFindIterate;
}
/**
* Normally not needed - overridden in CockroachPlatform.
*/
public boolean isDdlCommitOnCreateIndex() {
return false;
}
/**
* Return the DB identity/sequence features for this platform.
*
@@ -0,0 +1,28 @@
package io.ebean.config.dbplatform.cockroach;
import io.ebean.annotation.Platform;
import io.ebean.config.dbplatform.postgres.PostgresPlatform;
/**
* CockroachDB based platform.
*/
public class CockroachPlatform extends PostgresPlatform {
public CockroachPlatform() {
super();
this.platform = Platform.COCKROACH;
// no like escape clause supported
this.likeSpecialCharacters = new char[]{'%', '_'};
this.likeClauseRaw = "like ?";
this.likeClauseEscaped = "like ?";
}
/**
* Needs a commit after create index such that alter table add foreign key ... succeeds.
*/
@Override
public boolean isDdlCommitOnCreateIndex() {
return true;
}
}
@@ -37,6 +37,7 @@ public class DdlGenerator {
private final boolean runDdl;
private final boolean createOnly;
private final boolean jaxbPresent;
private final boolean ddlCommitOnCreateIndex;
private CurrentModel currentModel;
private String dropAllContent;
@@ -50,8 +51,10 @@ public class DdlGenerator {
if (!serverConfig.getTenantMode().isDdlEnabled() && serverConfig.isDdlRun()) {
log.warn("DDL can't be run on startup with TenantMode " + serverConfig.getTenantMode());
this.runDdl = false;
this.ddlCommitOnCreateIndex = false;
} else {
this.runDdl = serverConfig.isDdlRun();
this.ddlCommitOnCreateIndex = server.getDatabasePlatform().isDdlCommitOnCreateIndex();
}
}
@@ -109,6 +112,8 @@ public class DdlGenerator {
try {
if (expectErrors) {
connection.setAutoCommit(true);
} else if (ddlCommitOnCreateIndex) {
runner.setCommitOnCreateIndex();
}
int count = runner.runAll(content, connection);
if (expectErrors) {
@@ -0,0 +1,57 @@
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
/**
* CockroachDB specific DDL handling.
*/
public class CockroachDdl extends PlatformDdl {
public CockroachDdl(DatabasePlatform platform) {
super(platform);
this.historyDdl = new PostgresHistoryDdl();
this.dropTableCascade = " cascade";
this.columnSetType = "type ";
this.alterTableIfExists = "if exists ";
this.columnSetNull = "drop not null";
}
// @Override
// protected String convertArrayType(String logicalArrayType) {
// TODO: Need to look at DB Array support ...
// }
/**
* Map bigint, integer and smallint all into serial.
*/
@Override
public String asIdentityColumn(String columnDefn) {
if ("bigint".equalsIgnoreCase(columnDefn)) {
return "serial";
}
if ("integer".equalsIgnoreCase(columnDefn)) {
return "serial";
}
if ("smallint".equalsIgnoreCase(columnDefn)) {
return "serial";
}
return columnDefn;
}
@Override
public void addTableComment(DdlBuffer apply, String tableName, String tableComment) {
// do nothing
}
@Override
public void addColumnComment(DdlBuffer apply, String table, String column, String comment) {
// do nothing
}
@Override
public boolean isInlineComments() {
return false;
}
}
@@ -2,6 +2,7 @@ package io.ebeaninternal.server.core;
import io.ebean.config.ServerConfig;
import io.ebean.config.dbplatform.DatabasePlatform;
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.hsqldb.HsqldbPlatform;
@@ -13,6 +14,7 @@ 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.migration.util.JdbcClose;
import io.ebeaninternal.dbmigration.DbOffline;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -21,6 +23,8 @@ 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;
/**
@@ -111,20 +115,20 @@ public class DatabasePlatformFactory {
*/
private DatabasePlatform byDataSource(DataSource dataSource) {
Connection conn = null;
Connection connection = null;
try {
conn = dataSource.getConnection();
DatabaseMetaData metaData = conn.getMetaData();
connection = dataSource.getConnection();
DatabaseMetaData metaData = connection.getMetaData();
return byDatabaseMeta(metaData);
return byDatabaseMeta(metaData, connection);
} catch (SQLException ex) {
throw new PersistenceException(ex);
} finally {
try {
if (conn != null) {
conn.close();
if (connection != null) {
connection.close();
}
} catch (SQLException ex) {
logger.error(null, ex);
@@ -135,7 +139,7 @@ public class DatabasePlatformFactory {
/**
* Find the platform by the metaData.getDatabaseProductName().
*/
private DatabasePlatform byDatabaseMeta(DatabaseMetaData metaData) throws SQLException {
private DatabasePlatform byDatabaseMeta(DatabaseMetaData metaData, Connection connection) throws SQLException {
String dbProductName = metaData.getDatabaseProductName();
dbProductName = dbProductName.toLowerCase();
@@ -151,7 +155,7 @@ public class DatabasePlatformFactory {
} else if (dbProductName.contains("hsql database engine")) {
return new HsqldbPlatform();
} else if (dbProductName.contains("postgres")) {
return new PostgresPlatform();
return readPostgres(connection);
} else if (dbProductName.contains("sqlite")) {
return new SQLitePlatform();
} else if (dbProductName.contains("db2")) {
@@ -163,4 +167,32 @@ public class DatabasePlatformFactory {
// use the standard one
return new DatabasePlatform();
}
/**
* 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();
}
}
@@ -1,6 +1,7 @@
package io.ebeaninternal.server.core;
import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebeaninternal.dbmigration.ddlgeneration.platform.CockroachDdl;
import io.ebeaninternal.dbmigration.ddlgeneration.platform.DB2Ddl;
import io.ebeaninternal.dbmigration.ddlgeneration.platform.H2Ddl;
import io.ebeaninternal.dbmigration.ddlgeneration.platform.HsqldbDdl;
@@ -38,6 +39,8 @@ public class PlatformDdlBuilder {
return new PlatformDdl(platform);
case POSTGRES:
return new PostgresDdl(platform);
case COCKROACH:
return new CockroachDdl(platform);
case SQLANYWHERE:
return new PlatformDdl(platform);
case SQLSERVER16: