Merge branch 'feature/1653-clickhouse'

This commit is contained in:
rob bygrave
2019-03-20 22:07:42 +13:00
25 changed files with 461 additions and 144 deletions
@@ -0,0 +1,52 @@
package io.ebean.config.dbplatform.clickhouse;
import io.ebean.annotation.Platform;
import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebean.config.dbplatform.DbPlatformType;
import io.ebean.config.dbplatform.DbType;
import io.ebean.config.dbplatform.IdType;
import java.sql.Types;
public class ClickHousePlatform extends DatabasePlatform {
public ClickHousePlatform() {
super();
this.platform = Platform.CLICKHOUSE;
//this.dbEncrypt =
//this.historySupport =
//this.exceptionTranslator =
this.nativeUuidType = true;
this.dbDefaultValue.setNow("now()");
this.columnAliasPrefix = null;
this.dbIdentity.setIdType(IdType.IDENTITY);
this.dbIdentity.setSupportsGetGeneratedKeys(false);
this.dbIdentity.setSupportsSequence(false);
this.dbIdentity.setSupportsIdentity(true);
this.booleanDbType = Types.INTEGER;
dbTypeMap.put(DbType.BOOLEAN, new DbPlatformType("UInt8"));
// using unsigned as default types ...
dbTypeMap.put(DbType.TINYINT, new DbPlatformType("UInt8", false));
dbTypeMap.put(DbType.SMALLINT, new DbPlatformType("UInt16", false));
dbTypeMap.put(DbType.INTEGER, new DbPlatformType("UInt32", false));
dbTypeMap.put(DbType.BIGINT, new DbPlatformType("UInt64", false));
dbTypeMap.put(DbType.DECIMAL, new DbPlatformType("Decimal", 16,4));
dbTypeMap.put(DbType.DOUBLE, new DbPlatformType("Float64", false));
dbTypeMap.put(DbType.DATE, new DbPlatformType("Date", false));
dbTypeMap.put(DbType.TIMESTAMP, new DbPlatformType("DateTime", false));
dbTypeMap.put(DbType.VARCHAR, new DbPlatformType("String", false));
dbTypeMap.put(DbType.LONGVARCHAR, new DbPlatformType("String", false));
dbTypeMap.put(DbType.CLOB, new DbPlatformType("String", false));
dbTypeMap.put(DbType.JSONVARCHAR, new DbPlatformType("String", false));
dbTypeMap.put(DbType.UUID, new DbPlatformType("UUID", false));
dbTypeMap.put(DbType.INET, new DbPlatformType("String", false));
dbTypeMap.put(DbType.CDIR, new DbPlatformType("String", false));
}
}
@@ -189,7 +189,7 @@ public class DdlGenerator {
runScript(connection, false, createAllContent, getCreateFileName());
if (extraDdl && jaxbPresent) {
if (currentModel.isTablePartitioning()) {
if (currentModel().isTablePartitioning()) {
String extraPartitioning = ExtraDdlXmlReader.buildPartitioning(server.getDatabasePlatform().getName());
if (extraPartitioning != null && !extraPartitioning.isEmpty()) {
runScript(connection, false, extraPartitioning, "builtin-partitioning-ddl");
@@ -201,7 +201,7 @@ public class DdlGenerator {
runScript(connection, false, extraApply, "extra-ddl");
}
if (currentModel.isTablePartitioning()) {
if (currentModel().isTablePartitioning()) {
checkInitialTablePartitions(connection);
}
}
@@ -8,6 +8,8 @@ import io.ebean.config.DbMigrationConfig;
import io.ebean.config.PlatformConfig;
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;
@@ -802,6 +804,11 @@ public class DefaultDbMigration implements DbMigration {
return new SQLitePlatform();
case HANA:
return new HanaPlatform();
case COCKROACH:
return new CockroachPlatform();
case CLICKHOUSE:
return new ClickHousePlatform();
case GENERIC:
return new DatabasePlatform();
@@ -19,6 +19,11 @@ public interface DdlBuffer {
*/
boolean isEmpty();
/**
* Append a statement allowing for null or empty statements.
*/
DdlBuffer appendStatement(String content) throws IOException;
/**
* Append DDL content to the buffer.
*/
@@ -38,6 +38,15 @@ public class BaseDdlBuffer implements DdlBuffer {
return this;
}
@Override
public DdlBuffer appendStatement(String content) throws IOException {
if (content != null && !content.isEmpty()) {
writer.append(content);
endOfStatement();
}
return this;
}
@Override
public DdlBuffer append(String content) throws IOException {
writer.append(content);
@@ -73,7 +82,9 @@ public class BaseDdlBuffer implements DdlBuffer {
*/
@Override
public DdlBuffer end() throws IOException {
writer.append("\n");
if (!isEmpty()) {
writer.append("\n");
}
return this;
}
@@ -37,6 +37,8 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import static io.ebeaninternal.dbmigration.ddlgeneration.platform.SplitColumns.split;
/**
* Base implementation for 'create table' and 'alter table' statements.
*/
@@ -148,8 +150,7 @@ public class BaseTableDdl implements TableDdl {
buffer.append("-- NOTE: table has @History - special migration may be necessary").newLine();
}
for (String ddlScript : before) {
buffer.append(translate(ddlScript, tableName, columnName, this.defaultValue));
buffer.endOfStatement();
buffer.appendStatement(translate(ddlScript, tableName, columnName, this.defaultValue));
}
}
@@ -159,8 +160,7 @@ public class BaseTableDdl implements TableDdl {
}
// here we run post migration scripts
for (String ddlScript : after) {
buffer.append(translate(ddlScript, tableName, columnName, defaultValue));
buffer.endOfStatement();
buffer.appendStatement(translate(ddlScript, tableName, columnName, defaultValue));
}
if (!after.isEmpty()) {
buffer.end();
@@ -276,6 +276,7 @@ public class BaseTableDdl implements TableDdl {
}
apply.newLine().append(")");
addTableStorageEngine(apply, createTable);
addTableCommentInline(apply, createTable);
if (partitionMode != null) {
platformDdl.addTablePartition(apply, partitionMode, createTable.getPartitionColumn());
@@ -316,12 +317,11 @@ public class BaseTableDdl implements TableDdl {
private void addComments(DdlBuffer apply, CreateTable createTable) throws IOException {
if (!platformDdl.isInlineComments()) {
String tableComment = createTable.getComment();
if (!StringHelper.isNull(tableComment)) {
if (hasValue(tableComment)) {
platformDdl.addTableComment(apply, createTable.getName(), tableComment);
}
List<Column> columns = createTable.getColumn();
for (Column column : columns) {
for (Column column : createTable.getColumn()) {
if (!StringHelper.isNull(column.getComment())) {
platformDdl.addColumnComment(apply, createTable.getName(), column.getName(), column.getComment());
}
@@ -329,6 +329,15 @@ public class BaseTableDdl implements TableDdl {
}
}
/**
* Add the table storage engine clause.
*/
private void addTableStorageEngine(DdlBuffer apply, CreateTable createTable) throws IOException {
if (platformDdl.isIncludeStorageEngine()) {
platformDdl.tableStorageEngine(apply, createTable.getStorageEngine());
}
}
/**
* Add the table comment inline with the create table statement.
*/
@@ -358,26 +367,17 @@ public class BaseTableDdl implements TableDdl {
uqName = col.getUnique();
}
String[] columnNames = {col.getName()};
write.apply()
.append(platformDdl.alterTableAddUniqueConstraint(tableName, uqName, columnNames, Boolean.TRUE.equals(col.isNotnull()) ? null : columnNames))
.endOfStatement();
write.dropAllForeignKeys()
.append(platformDdl.dropIndex(uqName, tableName))
.endOfStatement();
write.apply().appendStatement(platformDdl.alterTableAddUniqueConstraint(tableName, uqName, columnNames, Boolean.TRUE.equals(col.isNotnull()) ? null : columnNames));
write.dropAllForeignKeys().appendStatement(platformDdl.dropIndex(uqName, tableName));
}
for (UniqueConstraint constraint : externalCompoundUnique) {
String uqName = constraint.getName();
String[] columnNames = SplitColumns.split(constraint.getColumnNames());
String[] nullableColumns = SplitColumns.split(constraint.getNullableColumns());
write.apply()
.append(platformDdl.alterTableAddUniqueConstraint(tableName, uqName, columnNames, nullableColumns))
.endOfStatement();
String[] columnNames = split(constraint.getColumnNames());
String[] nullableColumns = split(constraint.getNullableColumns());
write.dropAllForeignKeys()
.append(platformDdl.dropIndex(uqName, tableName))
.endOfStatement();
write.apply().appendStatement(platformDdl.alterTableAddUniqueConstraint(tableName, uqName, columnNames, nullableColumns));
write.dropAllForeignKeys().appendStatement(platformDdl.dropIndex(uqName, tableName));
}
}
@@ -394,9 +394,9 @@ public class BaseTableDdl implements TableDdl {
}
String createSeq = platformDdl.createSequence(seqName, initial, allocate);
if (createSeq != null) {
if (hasValue(createSeq)) {
writer.apply().append(createSeq).newLine();
writer.dropAll().append(platformDdl.dropSequence(seqName)).endOfStatement();
writer.dropAll().appendStatement(platformDdl.dropSequence(seqName));
}
}
@@ -425,8 +425,7 @@ public class BaseTableDdl implements TableDdl {
protected void writeInlineCompoundForeignKeys(DdlWrite write, CreateTable createTable) throws IOException {
List<ForeignKey> foreignKey = createTable.getForeignKey();
for (ForeignKey key : foreignKey) {
for (ForeignKey key : createTable.getForeignKey()) {
String fkConstraint = platformDdl.tableInlineForeignKey(new WriteForeignKey(null, key));
write.apply().append(",").newLine().append(" ").append(fkConstraint);
}
@@ -434,12 +433,10 @@ public class BaseTableDdl implements TableDdl {
protected void writeAddForeignKeys(DdlWrite write, CreateTable createTable) throws IOException {
String tableName = createTable.getName();
List<Column> columns = createTable.getColumn();
for (Column column : columns) {
for (Column column : createTable.getColumn()) {
String references = column.getReferences();
if (hasValue(references)) {
writeForeignKey(write, tableName, column);
writeForeignKey(write, createTable.getName(), column);
}
}
@@ -448,11 +445,8 @@ public class BaseTableDdl implements TableDdl {
protected void writeAddCompoundForeignKeys(DdlWrite write, CreateTable createTable) throws IOException {
String tableName = createTable.getName();
List<ForeignKey> foreignKey = createTable.getForeignKey();
for (ForeignKey key : foreignKey) {
writeForeignKey(write, new WriteForeignKey(tableName, key));
for (ForeignKey key : createTable.getForeignKey()) {
writeForeignKey(write, new WriteForeignKey(createTable.getName(), key));
}
}
@@ -466,19 +460,15 @@ public class BaseTableDdl implements TableDdl {
String tableName = lowerTableName(request.table());
if (request.indexName() != null) {
// no matching unique constraint so add the index
fkeyBuffer.append(platformDdl.createIndex(request.indexName(), tableName, request.cols())).endOfStatement();
fkeyBuffer.appendStatement(platformDdl.createIndex(request.indexName(), tableName, request.cols()));
}
alterTableAddForeignKey(fkeyBuffer, request);
fkeyBuffer.end();
write.dropAllForeignKeys()
.append(platformDdl.alterTableDropForeignKey(tableName, request.fkName())).endOfStatement();
if (request.indexName() != null) {
write.dropAllForeignKeys()
.append(platformDdl.dropIndex(request.indexName(), tableName)).endOfStatement();
write.dropAllForeignKeys().appendStatement(platformDdl.alterTableDropForeignKey(tableName, request.fkName()));
if (hasValue(request.indexName())) {
write.dropAllForeignKeys().appendStatement(platformDdl.dropIndex(request.indexName(), tableName));
}
write.dropAllForeignKeys().end();
@@ -486,10 +476,7 @@ public class BaseTableDdl implements TableDdl {
protected void alterTableAddForeignKey(DdlBuffer buffer, WriteForeignKey request) throws IOException {
String fkConstraint = platformDdl.alterTableAddForeignKey(request);
if (fkConstraint != null && !fkConstraint.isEmpty()) {
buffer.append(fkConstraint).endOfStatement();
}
buffer.appendStatement(platformDdl.alterTableAddForeignKey(request));
}
protected void appendColumns(String[] columns, DdlBuffer buffer) throws IOException {
@@ -503,13 +490,12 @@ public class BaseTableDdl implements TableDdl {
buffer.append(")");
}
/**
* Add 'drop table' statement to the buffer.
*/
protected void dropTable(DdlBuffer buffer, String tableName) throws IOException {
buffer.append(platformDdl.dropTable(tableName)).endOfStatement();
buffer.appendStatement(platformDdl.dropTable(tableName));
}
/**
@@ -517,7 +503,7 @@ public class BaseTableDdl implements TableDdl {
*/
protected void dropSequence(DdlBuffer buffer, String sequenceName) throws IOException {
buffer.append(platformDdl.dropSequence(sequenceName)).endOfStatement();
buffer.appendStatement(platformDdl.dropSequence(sequenceName));
}
/**
@@ -525,8 +511,7 @@ public class BaseTableDdl implements TableDdl {
*/
protected void writeCheckConstraints(DdlBuffer apply, CreateTable createTable) throws IOException {
List<Column> columns = createTable.getColumn();
for (Column column : columns) {
for (Column column : createTable.getColumn()) {
String checkConstraint = column.getCheckConstraint();
if (hasValue(checkConstraint)) {
writeCheckConstraint(apply, column, checkConstraint);
@@ -548,12 +533,11 @@ public class BaseTableDdl implements TableDdl {
protected void writeCompoundUniqueConstraints(DdlBuffer apply, CreateTable createTable) throws IOException {
List<UniqueConstraint> uniqueConstraints = createTable.getUniqueConstraint();
boolean inlineUniqueWhenNull = platformDdl.isInlineUniqueWhenNullable();
for (UniqueConstraint uniqueConstraint : uniqueConstraints) {
for (UniqueConstraint uniqueConstraint : createTable.getUniqueConstraint()) {
if (inlineUniqueWhenNull) {
String uqName = uniqueConstraint.getName();
String[] columns = SplitColumns.split(uniqueConstraint.getColumnNames());
String[] columns = split(uniqueConstraint.getColumnNames());
apply.append(",").newLine();
apply.append(" constraint ").append(uqName).append(" unique");
appendColumns(columns, apply);
@@ -650,54 +634,34 @@ public class BaseTableDdl implements TableDdl {
@Override
public void generate(DdlWrite writer, CreateIndex createIndex) throws IOException {
String[] cols = SplitColumns.split(createIndex.getColumns());
writer.apply()
.append(platformDdl.createIndex(createIndex.getIndexName(), createIndex.getTableName(), cols))
.endOfStatement();
writer.dropAll()
.append(platformDdl.dropIndex(createIndex.getIndexName(), createIndex.getTableName()))
.endOfStatement();
writer.apply().appendStatement(platformDdl.createIndex(createIndex.getIndexName(), createIndex.getTableName(), split(createIndex.getColumns())));
writer.dropAll().appendStatement(platformDdl.dropIndex(createIndex.getIndexName(), createIndex.getTableName()));
}
@Override
public void generate(DdlWrite writer, DropIndex dropIndex) throws IOException {
writer.apply()
.append(platformDdl.dropIndex(dropIndex.getIndexName(), dropIndex.getTableName()))
.endOfStatement();
writer.apply().appendStatement(platformDdl.dropIndex(dropIndex.getIndexName(), dropIndex.getTableName()));
}
@Override
public void generate(DdlWrite writer, AddUniqueConstraint constraint) throws IOException {
if (DdlHelp.isDropConstraint(constraint.getColumnNames())) {
String ddl = platformDdl.alterTableDropUniqueConstraint(constraint.getTableName(), constraint.getConstraintName());
if (hasValue(ddl)) {
writer.apply().append(ddl).endOfStatement();
}
writer.apply().appendStatement(platformDdl.alterTableDropUniqueConstraint(constraint.getTableName(), constraint.getConstraintName()));
} else {
String[] cols = SplitColumns.split(constraint.getColumnNames());
String[] nullableColumns = SplitColumns.split(constraint.getNullableColumns());
String ddl = platformDdl.alterTableAddUniqueConstraint(constraint.getTableName(), constraint.getConstraintName(), cols, nullableColumns);
if (hasValue(ddl)) {
writer.apply().append(ddl).endOfStatement();
}
String[] cols = split(constraint.getColumnNames());
String[] nullableColumns = split(constraint.getNullableColumns());
writer.apply().appendStatement(platformDdl.alterTableAddUniqueConstraint(constraint.getTableName(), constraint.getConstraintName(), cols, nullableColumns));
}
}
@Override
public void generate(DdlWrite writer, AlterForeignKey alterForeignKey) throws IOException {
if (DdlHelp.isDropForeignKey(alterForeignKey.getColumnNames())) {
String ddl = platformDdl.alterTableDropForeignKey(alterForeignKey.getTableName(), alterForeignKey.getName());
if (hasValue(ddl)) {
writer.apply().append(ddl).endOfStatement();
}
writer.apply().appendStatement(platformDdl.alterTableDropForeignKey(alterForeignKey.getTableName(), alterForeignKey.getName()));
} else {
String ddl = platformDdl.alterTableAddForeignKey(new WriteForeignKey(alterForeignKey));
if (hasValue(ddl)) {
writer.apply().append(ddl).endOfStatement();
}
writer.apply().appendStatement(platformDdl.alterTableAddForeignKey(new WriteForeignKey(alterForeignKey)));
}
}
@@ -907,7 +871,7 @@ public class BaseTableDdl implements TableDdl {
String ddl = platformDdl.alterColumnBaseAttributes(alter);
if (hasValue(ddl)) {
writer.apply().append(ddl).endOfStatement();
writer.apply().appendStatement(ddl);
if (isTrue(alter.isWithHistory()) && alter.getType() != null && historySupport == HistorySupport.TRIGGER_BASED) {
// mysql and sql server column type change allowing nulls in the history table column
@@ -919,53 +883,41 @@ public class BaseTableDdl implements TableDdl {
String histColumnDdl = platformDdl.alterColumnBaseAttributes(alterHistoryColumn);
// write the apply to history table
writer.apply().append(histColumnDdl).endOfStatement();
writer.apply().appendStatement(histColumnDdl);
}
}
}
protected void alterColumnDefaultValue(DdlWrite writer, AlterColumn alter) throws IOException {
String ddl = platformDdl.alterColumnDefaultValue(alter.getTableName(), alter.getColumnName(), alter.getDefaultValue());
if (hasValue(ddl)) {
writer.apply().append(ddl).endOfStatement();
}
writer.apply().appendStatement(platformDdl.alterColumnDefaultValue(alter.getTableName(), alter.getColumnName(), alter.getDefaultValue()));
}
protected void dropCheckConstraint(DdlWrite writer, AlterColumn alter, String constraintName) throws IOException {
String ddl = platformDdl.alterTableDropConstraint(alter.getTableName(), constraintName);
if (hasValue(ddl)) {
writer.apply().append(ddl).endOfStatement();
}
writer.apply().appendStatement(platformDdl.alterTableDropConstraint(alter.getTableName(), constraintName));
}
protected void addCheckConstraint(DdlWrite writer, AlterColumn alter) throws IOException {
String ddl = platformDdl.alterTableAddCheckConstraint(alter.getTableName(), alter.getCheckConstraintName(), alter.getCheckConstraint());
if (hasValue(ddl)) {
writer.apply().append(ddl).endOfStatement();
}
writer.apply().appendStatement(platformDdl.alterTableAddCheckConstraint(alter.getTableName(), alter.getCheckConstraintName(), alter.getCheckConstraint()));
}
protected void alterColumnNotnull(DdlWrite writer, AlterColumn alter) throws IOException {
String ddl = platformDdl.alterColumnNotnull(alter.getTableName(), alter.getColumnName(), alter.isNotnull());
if (hasValue(ddl)) {
writer.apply().append(ddl).endOfStatement();
}
writer.apply().appendStatement(platformDdl.alterColumnNotnull(alter.getTableName(), alter.getColumnName(), alter.isNotnull()));
}
protected void alterColumnType(DdlWrite writer, AlterColumn alter) throws IOException {
String ddl = platformDdl.alterColumnType(alter.getTableName(), alter.getColumnName(), alter.getType());
if (hasValue(ddl)) {
writer.apply().append(ddl).endOfStatement();
writer.apply().appendStatement(ddl);
if (isTrue(alter.isWithHistory()) && historySupport == HistorySupport.TRIGGER_BASED) {
regenerateHistoryTriggers(alter.getTableName(), HistoryTableUpdate.Change.ALTER, alter.getColumnName());
// apply same type change to matching column in the history table
ddl = platformDdl.alterColumnType(historyTable(alter.getTableName()), alter.getColumnName(), alter.getType());
writer.apply().append(ddl).endOfStatement();
writer.apply().appendStatement(ddl);
}
}
}
@@ -977,17 +929,13 @@ public class BaseTableDdl implements TableDdl {
protected void alterColumnDropForeignKey(DdlWrite writer, AlterColumn alter) throws IOException {
writer.apply()
.append(platformDdl.alterTableDropForeignKey(alter.getTableName(), alter.getDropForeignKey()))
.endOfStatement();
writer.apply().appendStatement(platformDdl.alterTableDropForeignKey(alter.getTableName(), alter.getDropForeignKey()));
}
protected void alterColumnDropUniqueConstraint(DdlWrite writer, AlterColumn alter) throws IOException {
writer.apply()
.append(platformDdl.alterTableDropUniqueConstraint(alter.getTableName(), alter.getDropUnique()))
.endOfStatement();
writer.apply().appendStatement(platformDdl.alterTableDropUniqueConstraint(alter.getTableName(), alter.getDropUnique()));
}
protected void alterColumnAddUniqueOneToOneConstraint(DdlWrite writer, AlterColumn alter) throws IOException {
@@ -1004,13 +952,9 @@ public class BaseTableDdl implements TableDdl {
String[] cols = {alter.getColumnName()};
boolean notNull = alter.isNotnull() != null ? alter.isNotnull() : Boolean.TRUE.equals(alter.isNotnull());
writer.apply()
.append(platformDdl.alterTableAddUniqueConstraint(alter.getTableName(), uqName, cols, notNull ? null : cols))
.endOfStatement();
writer.apply().appendStatement(platformDdl.alterTableAddUniqueConstraint(alter.getTableName(), uqName, cols, notNull ? null : cols));
writer.dropAllForeignKeys()
.append(platformDdl.dropIndex(uqName, alter.getTableName()))
.endOfStatement();
writer.dropAllForeignKeys().appendStatement(platformDdl.dropIndex(uqName, alter.getTableName()));
}
@@ -0,0 +1,33 @@
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
import java.util.HashMap;
import java.util.Map;
/**
* Logical array type to ClickHouse array type conversion.
*/
class ClickHouseDbArray {
private static final Map<String, String> mapping = new HashMap<>();
static {
mapping.put("uuid[]", "Array(UUID)");
mapping.put("varchar[]", "Array(String)");
mapping.put("integer[]", "Array(UInt32)");
mapping.put("bigint[]", "Array(UInt64)");
}
/**
* Covert the 'logical' array type to a native one (for Postgres and Cockroach).
*/
static String logicalToNative(String logicalArrayType) {
int colonPos = logicalArrayType.indexOf(':');
if (colonPos > -1) {
logicalArrayType = logicalArrayType.substring(0, colonPos);
}
String clickHouseType = mapping.get(logicalArrayType);
if (clickHouseType == null) {
throw new IllegalStateException("No mapping for logical array type " + logicalArrayType);
}
return clickHouseType;
}
}
@@ -0,0 +1,86 @@
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
import io.ebean.config.ServerConfig;
import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlHandler;
import java.io.IOException;
public class ClickHouseDdl extends PlatformDdl {
private static final String LOG_TABLE = "ENGINE = Log()";
public ClickHouseDdl(DatabasePlatform platform) {
super(platform);
this.includeStorageEngine = true;
this.identitySuffix = "";
}
@Override
public DdlHandler createDdlHandler(ServerConfig serverConfig) {
return new ClickHouseDdlHandler(serverConfig, this);
}
@Override
protected String convertArrayType(String logicalArrayType) {
return ClickHouseDbArray.logicalToNative(logicalArrayType);
}
/**
* Add an table storage engine to the create table statement.
*/
@Override
public void tableStorageEngine(DdlBuffer apply, String storageEngine) throws IOException {
if (storageEngine == null) {
// default to Log() table but really should all be explicit (need arguments for MergeTree etc)
storageEngine = LOG_TABLE;
}
apply.append(" ").append(storageEngine);
}
@Override
public String alterTableAddForeignKey(WriteForeignKey request) {
return null;
}
@Override
public String alterTableDropForeignKey(String tableName, String fkName) {
return null;
}
@Override
public String tableInlineForeignKey(WriteForeignKey request) {
return null;
}
@Override
public String dropIndex(String indexName, String tableName) {
return null;
}
@Override
public String createIndex(String indexName, String tableName, String[] columns) {
return null;
}
@Override
protected void writeColumnNotNull(DdlBuffer buffer) {
// do nothing
}
@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;
}
}
@@ -0,0 +1,11 @@
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
import io.ebean.config.ServerConfig;
import io.ebeaninternal.dbmigration.ddlgeneration.BaseDdlHandler;
public class ClickHouseDdlHandler extends BaseDdlHandler {
public ClickHouseDdlHandler(ServerConfig serverConfig, PlatformDdl platformDdl) {
super(serverConfig, platformDdl, new ClickHouseTableDdl(serverConfig, platformDdl));
}
}
@@ -0,0 +1,34 @@
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
import io.ebean.config.ServerConfig;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
import io.ebeaninternal.dbmigration.migration.CreateTable;
public class ClickHouseTableDdl extends BaseTableDdl {
public ClickHouseTableDdl(ServerConfig serverConfig, PlatformDdl platformDdl) {
super(serverConfig, platformDdl);
}
@Override
protected void writePrimaryKeyConstraint(DdlBuffer buffer, String pkName, String[] pkColumns) {
// do nothing
}
@Override
protected void writeCompoundUniqueConstraints(DdlBuffer apply, CreateTable createTable) {
// do nothing
}
@Override
protected void writeUniqueConstraints(DdlBuffer apply, CreateTable createTable) {
// do nothing
}
@Override
protected void writeCheckConstraints(DdlBuffer apply, CreateTable createTable) {
// do nothing
}
}
@@ -104,7 +104,6 @@ public class MySqlDdl extends PlatformDdl {
}
buffer.append(String.format(" comment '%s'", comment));
}
}
@Override
@@ -118,6 +118,8 @@ public class PlatformDdl {
*/
protected boolean inlineForeignKeys;
protected boolean includeStorageEngine;
protected final DbDefaultValue dbDefaultValue;
protected String fallbackArrayType = "varchar(1000)";
@@ -191,6 +193,13 @@ public class PlatformDdl {
return inlineComments;
}
/**
* Return true if the platform includes storage engine clause.
*/
public boolean isIncludeStorageEngine() {
return includeStorageEngine;
}
/**
* Return true if foreign key reference constraints need to inlined with create table.
* Ideally we don't do this as then the constraints are not named. Do this for SQLite.
@@ -230,13 +239,20 @@ public class PlatformDdl {
}
}
if (isTrue(column.isNotnull()) || isTrue(column.isPrimaryKey())) {
buffer.append(" not null");
writeColumnNotNull(buffer);
}
// add check constraints later as we really want to give them a nice name
// so that the database can potentially provide a nice SQL error
}
/**
* Allow for platform overriding (e.g. ClickHouse).
*/
protected void writeColumnNotNull(DdlBuffer buffer) throws IOException {
buffer.append(" not null");
}
/**
* Convert the DB column default literal to platform specific.
*/
@@ -409,13 +425,17 @@ public class PlatformDdl {
}
protected String translate(ConstraintMode mode) {
switch(mode) {
case SET_NULL: return "set null";
case SET_DEFAULT: return "set default";
case RESTRICT: return "restrict";
case CASCADE: return "cascade";
switch (mode) {
case SET_NULL:
return "set null";
case SET_DEFAULT:
return "set default";
case RESTRICT:
return "restrict";
case CASCADE:
return "cascade";
default:
throw new IllegalStateException("Unknown mode "+mode);
throw new IllegalStateException("Unknown mode " + mode);
}
}
@@ -465,7 +485,7 @@ public class PlatformDdl {
if (!onHistoryTable) {
if (isTrue(column.isNotnull())) {
buffer.append(" not null");
writeColumnNotNull(buffer);
}
buffer.append(addColumnSuffix);
buffer.endOfStatement();
@@ -473,7 +493,7 @@ public class PlatformDdl {
// check constraints cannot be added in one statement for h2
if (!StringHelper.isNull(column.getCheckConstraint())) {
String ddl = alterTableAddCheckConstraint(tableName, column.getCheckConstraintName(),
column.getCheckConstraint());
column.getCheckConstraint());
buffer.append(ddl).endOfStatement();
}
} else {
@@ -485,7 +505,7 @@ public class PlatformDdl {
public void alterTableDropColumn(DdlBuffer buffer, String tableName, String columnName) throws IOException {
buffer.append("alter table ").append(tableName).append(" ").append(dropColumn).append(" ").append(columnName)
.append(dropColumnSuffix).endOfStatement();
.append(dropColumnSuffix).endOfStatement();
}
/**
@@ -607,6 +627,13 @@ public class PlatformDdl {
// do nothing by default (MySql only)
}
/**
* Add an table storage engine to the create table statement.
*/
public void tableStorageEngine(DdlBuffer apply, String storageEngine) throws IOException {
// do nothing by default
}
/**
* Add table comment as a separate statement (from the create table statement).
*/
@@ -643,10 +670,10 @@ public class PlatformDdl {
/**
* Shortens the given name to the maximum constraint name length of the platform in a deterministic way.
*
* <p>
* First, all vowels are removed, If the string is still to long, 31 bits are taken from the hash code
* of the string and base36 encoded (10 digits and 26 chars) string.
*
* <p>
* As 36^6 > 31^2, the resulting string is never longer as 6 chars.
*/
protected String maxConstraintName(String name) {
@@ -654,7 +681,7 @@ public class PlatformDdl {
int hash = name.hashCode() & 0x7FFFFFFF;
name = VowelRemover.trim(name, 4);
if (name.length() > platform.getMaxConstraintNameLength()) {
return name.substring(0, platform.getMaxConstraintNameLength()-7) + "_" + Integer.toString(hash, 36);
return name.substring(0, platform.getMaxConstraintNameLength() - 7) + "_" + Integer.toString(hash, 36);
}
}
return name;
@@ -77,6 +77,8 @@ public class CreateTable {
protected BigInteger sequenceAllocate;
@XmlAttribute(name = "pkName")
protected String pkName;
@XmlAttribute(name = "storageEngine")
protected String storageEngine;
@XmlAttribute(name = "tablespace")
protected String tablespace;
@XmlAttribute(name = "indexTablespace")
@@ -365,6 +367,26 @@ public class CreateTable {
this.pkName = value;
}
/**
* Gets the value of the storageEngine property.
*
* @return possible object is
* {@link String }
*/
public String getStorageEngine() {
return storageEngine;
}
/**
* Sets the value of the storageEngine property.
*
* @param value allowed object is
* {@link String }
*/
public void setStorageEngine(String value) {
this.storageEngine = value;
}
/**
* Gets the value of the tablespace property.
*
@@ -67,14 +67,14 @@ public class CurrentModel {
* Return true if the model contains tables that are partitioned.
*/
public boolean isTablePartitioning() {
return model.isTablePartitioning();
return read().isTablePartitioning();
}
/**
* Return the tables that have partitioning.
*/
public List<MTable> getPartitionedTables() {
return model.getPartitionedTables();
return read().getPartitionedTables();
}
private static DbConstraintNaming.MaxLength maxLength(SpiEbeanServer server, DbConstraintNaming naming) {
@@ -79,6 +79,8 @@ public class MTable {
*/
private String tablespace;
private String storageEngine;
/**
* Tablespace to use for indexes on this table.
*/
@@ -159,6 +161,7 @@ public class MTable {
this.name = createTable.getName();
this.pkName = createTable.getPkName();
this.comment = createTable.getComment();
this.storageEngine = createTable.getStorageEngine();
this.tablespace = createTable.getTablespace();
this.indexTablespace = createTable.getIndexTablespace();
this.withHistory = Boolean.TRUE.equals(createTable.isWithHistory());
@@ -244,6 +247,7 @@ public class MTable {
createTable.setPartitionMode(partitionMeta.getMode().name());
createTable.setPartitionColumn(partitionMeta.getProperty());
}
createTable.setStorageEngine(storageEngine);
createTable.setTablespace(tablespace);
createTable.setIndexTablespace(indexTablespace);
createTable.setSequenceName(sequenceName);
@@ -452,6 +456,10 @@ public class MTable {
this.comment = comment;
}
public void setStorageEngine(String storageEngine) {
this.storageEngine = storageEngine;
}
public String getTablespace() {
return tablespace;
}
@@ -36,6 +36,7 @@ public class ModelBuildBeanVisitor implements BeanVisitor {
}
MTable table = new MTable(descriptor.getBaseTable());
table.setStorageEngine(descriptor.getStorageEngine());
table.setPartitionMeta(descriptor.getPartitionMeta());
table.setComment(descriptor.getDbComment());
if (descriptor.isHistorySupport()) {
@@ -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.clickhouse.ClickHousePlatform;
import io.ebean.config.dbplatform.cockroach.CockroachPlatform;
import io.ebean.config.dbplatform.db2.DB2Platform;
import io.ebean.config.dbplatform.h2.H2Platform;
@@ -104,6 +105,9 @@ public class DatabasePlatformFactory {
if (dbName.equals("db2")) {
return new DB2Platform();
}
if (dbName.equals("clickhouse")) {
return new ClickHousePlatform();
}
if (dbName.equals("sqlite")) {
return new SQLitePlatform();
}
@@ -162,6 +166,8 @@ public class DatabasePlatformFactory {
return new SqlAnywherePlatform();
} else if (dbProductName.contains("hdb")) {
return new HanaPlatform();
} else if (dbProductName.contains("clickhouse")) {
return new ClickHousePlatform();
}
// use the standard one
@@ -1,6 +1,7 @@
package io.ebeaninternal.server.core;
import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebeaninternal.dbmigration.ddlgeneration.platform.ClickHouseDdl;
import io.ebeaninternal.dbmigration.ddlgeneration.platform.CockroachDdl;
import io.ebeaninternal.dbmigration.ddlgeneration.platform.DB2Ddl;
import io.ebeaninternal.dbmigration.ddlgeneration.platform.H2Ddl;
@@ -50,6 +51,8 @@ public class PlatformDdlBuilder {
return new SqlServerDdl(platform);
case HANA:
return new HanaColumnStoreDdl(platform);
case CLICKHOUSE:
return new ClickHouseDdl(platform);
default:
return new PlatformDdl(platform);
}
@@ -211,6 +211,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
private final String draftTable;
private final PartitionMeta partitionMeta;
private final String storageEngine;
/**
* DB table comment.
@@ -492,6 +493,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
this.dependentTables = deploy.getDependentTables();
this.dbComment = deploy.getDbComment();
this.partitionMeta = deploy.getPartitionMeta();
this.storageEngine = deploy.getStorageEngine();
this.autoTunable = EntityType.ORM == entityType && (beanFinder == null);
// helper object used to derive lists of properties
@@ -1970,10 +1972,10 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
DefaultOrmQuery<T> query = new DefaultOrmQuery<>(this, ebeanServer, ebeanServer.getExpressionFactory());
query.setPersistenceContext(pc);
return query
// .select(getIdProperty().getName())
// we do not select the id because we
// probably have to load the entire bean
.setId(id).findOne();
// .select(getIdProperty().getName())
// we do not select the id because we
// probably have to load the entire bean
.setId(id).findOne();
}
/**
@@ -2874,6 +2876,13 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
return partitionMeta;
}
/**
* Return the storage engine.
*/
public String getStorageEngine() {
return storageEngine;
}
/**
* Return the dependent tables for a view based entity.
* <p>
@@ -136,6 +136,8 @@ public class DeployBeanDescriptor<T> {
private List<IndexDefinition> indexDefinitions;
private String storageEngine;
/**
* The base database table.
*/
@@ -275,6 +277,14 @@ public class DeployBeanDescriptor<T> {
return Modifier.isAbstract(beanType.getModifiers());
}
public void setStorageEngine(String storageEngine) {
this.storageEngine = storageEngine;
}
public String getStorageEngine() {
return storageEngine;
}
/**
* Set to true for @History entity beans that have history.
*/
@@ -315,7 +325,7 @@ public class DeployBeanDescriptor<T> {
this.partitionMeta = partitionMeta;
}
public PartitionMeta getPartitionMeta() {
public PartitionMeta getPartitionMeta() {
if (partitionMeta != null) {
DeployBeanProperty beanProperty = getBeanProperty(partitionMeta.getProperty());
if (beanProperty != null) {
@@ -10,6 +10,7 @@ import io.ebean.annotation.History;
import io.ebean.annotation.Index;
import io.ebean.annotation.InvalidateQueryCache;
import io.ebean.annotation.ReadAudit;
import io.ebean.annotation.StorageEngine;
import io.ebean.annotation.UpdateMode;
import io.ebean.annotation.View;
import io.ebean.config.TableName;
@@ -154,6 +155,11 @@ public class AnnotationClass extends AnnotationParser {
}
}
StorageEngine storage = AnnotationUtil.findAnnotationRecursive(cls, StorageEngine.class);
if (storage != null) {
descriptor.setStorageEngine(storage.value());
}
DbPartition partition = AnnotationUtil.findAnnotationRecursive(cls, DbPartition.class);
if (partition != null) {
descriptor.setPartitionMeta(new PartitionMeta(partition.mode(), partition.property()));