mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
#1653 - ENH: Add support for ClickHouse database
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
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", 38));
|
||||
|
||||
dbTypeMap.put(DbType.VARCHAR, new DbPlatformType("String", false));
|
||||
dbTypeMap.put(DbType.DATE, new DbPlatformType("Date", false));
|
||||
dbTypeMap.put(DbType.TIMESTAMP, new DbPlatformType("DateTime", false));
|
||||
|
||||
dbTypeMap.put(DbType.UUID, new DbPlatformType("UUID", 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();
|
||||
|
||||
|
||||
@@ -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());
|
||||
@@ -329,6 +330,18 @@ public class BaseTableDdl implements TableDdl {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the table storage engine clause.
|
||||
*/
|
||||
private void addTableStorageEngine(DdlBuffer apply, CreateTable createTable) throws IOException {
|
||||
if (platformDdl.isIncludeStorageEngine()) {
|
||||
String storageEngine = createTable.getStorageEngine();
|
||||
if (!StringHelper.isNull(storageEngine)) {
|
||||
platformDdl.tableStorageEngine(apply, storageEngine);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the table comment inline with the create table statement.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class ClickHouseDdl extends PlatformDdl {
|
||||
|
||||
public ClickHouseDdl(DatabasePlatform platform) {
|
||||
super(platform);
|
||||
this.includeStorageEngine = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an table storage engine to the create table statement.
|
||||
*/
|
||||
@Override
|
||||
public void tableStorageEngine(DdlBuffer apply, String storageEngine) throws IOException {
|
||||
apply.append(" ").append(storageEngine);
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
+40
-13
@@ -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()));
|
||||
|
||||
Reference in New Issue
Block a user