Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ClickHouse: Support optimised inserts for ClickHouse #3392

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -199,12 +199,21 @@ public class DatabasePlatform {

protected SqlExceptionTranslator exceptionTranslator = new SqlCodeTranslator();

protected InsertSqlSyntaxExtension insertSqlSyntaxExtension = new StandardInsertSqlSyntax();

/**
* Instantiates a new database platform.
*/
public DatabasePlatform() {
}

/**
* Return the Insert SQL syntax helper.
*/
public InsertSqlSyntaxExtension insertSqlSyntaxExtension() {
return insertSqlSyntaxExtension;
}

/**
* Translate the SQLException into a specific persistence exception if possible.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package io.ebean.config.dbplatform;

/**
* Insert SQL syntax to allow support for ClickHouse type optimisation for inserts.
*/
public interface InsertSqlSyntaxExtension {

/**
* Start the columns.
*/
String startColumns();

/**
* End of the columns.
*/
String endColumns();

/**
* Return true for insert to use standard binding.
*/
boolean useBinding();

/**
* Start types for non-standard binding (e.g. ClickHouse).
*/
String startTypes();

/**
* End types for non-standard binding (e.g. ClickHouse).
*/
String endTypes();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package io.ebean.config.dbplatform;

/**
* Standard Insert SQL syntax.
*/
public final class StandardInsertSqlSyntax implements InsertSqlSyntaxExtension {

@Override
public String startColumns() {
return " (";
}

@Override
public String endColumns() {
return ") values (";
}

@Override
public boolean useBinding() {
return true;
}

@Override
public String startTypes() {
throw new IllegalStateException();
}

@Override
public String endTypes() {
throw new IllegalStateException();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import io.ebean.Model;
import io.ebean.RawSqlBuilder;
import io.ebean.annotation.ConstraintMode;
import io.ebean.annotation.Platform;
import io.ebean.bean.BeanCollection;
import io.ebean.bean.EntityBean;
import io.ebean.config.*;
Expand Down Expand Up @@ -632,6 +633,8 @@ public <T> DeployBeanInfo<T> deploy(Class<T> cls) {
}

private void registerDescriptor(DeployBeanInfo<?> info) {
platformUsesColumnDefinitions(info);

BeanDescriptor<?> desc = new BeanDescriptor<>(this, info.getDescriptor());
descMap.put(desc.type().getName(), desc);
if (desc.isDocStoreMapped()) {
Expand All @@ -644,6 +647,23 @@ private void registerDescriptor(DeployBeanInfo<?> info) {
}
}

private void platformUsesColumnDefinitions(DeployBeanInfo<?> info) {
if (databasePlatform.isPlatform(Platform.CLICKHOUSE) && !DbOffline.isGenerateMigration()) {
// ClickHouse uses column definition to optimise JDBC bulk inserts
DbPlatformTypeMapping typeMapping = databasePlatform.dbTypeMap();
for (DeployBeanProperty property : info.getDescriptor().propertiesAll()) {
if (property.getDbColumnDefn() == null) {
DbPlatformType dbPlatformType = typeMapping.get(property.getDbType());
String columnDefn = dbPlatformType.renderType(property.getDbLength(), property.getDbScale());
if (property.isNullable()) {
columnDefn = "Nullable(" + columnDefn + ")";
}
property.setDbColumnDefn(columnDefn);
}
}
}
}

/**
* Read the initial deployment information for the entities.
* <p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ public interface ImportedId {
*/
void dmlAppend(GenerateDmlRequest request);

/**
* Append column and type for Insert (ClickHouse).
*/
void dmlType(GenerateDmlRequest request);

/**
* Bind the value from the bean.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,16 @@ public void dmlAppend(GenerateDmlRequest request) {
}
}

@Override
public void dmlType(GenerateDmlRequest request) {
boolean update = request.isUpdate();
for (ImportedIdSimple anImported : imported) {
if (anImported.isInclude(update)) {
anImported.dmlType(request);
}
}
}

@Override
public String importedIdClause() {
StringBuilder sb = new StringBuilder();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public int compare(ImportedIdSimple o1, ImportedIdSimple o2) {

final BeanPropertyAssoc<?> owner;
final String localDbColumn;
private final String localColumnDefn;
private final String localSqlFormula;
final BeanProperty foreignProperty;
private final int position;
Expand All @@ -49,6 +50,7 @@ public ImportedIdSimple(BeanPropertyAssoc<?> owner, String localDbColumn, String
this.localDbColumn = InternString.intern(localDbColumn);
this.localSqlFormula = InternString.intern(localSqlFormula);
this.foreignProperty = foreignProperty;
this.localColumnDefn = foreignProperty.dbColumnDefn();
this.position = position;
this.insertable = insertable;
this.updateable = updateable;
Expand Down Expand Up @@ -143,6 +145,11 @@ public void dmlAppend(GenerateDmlRequest request) {
request.appendColumn(localDbColumn);
}

@Override
public void dmlType(GenerateDmlRequest request) {
request.appendColumnDefn(localDbColumn, localColumnDefn);
}

@Override
public String importedIdClause() {
return localDbColumn + " = ?";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,26 @@ public final class GenerateDmlRequest {
private String prefix2;
private int insertMode;
private int bindColumnCount;
private boolean hasColumnDefn;

GenerateDmlRequest append(String s) {
sb.append(s);
return this;
}

/**
* Append column and type for Insert (ClickHouse).
*/
public void appendColumnDefn(String columnName, String columnDefn) {
if (hasColumnDefn) {
sb.append(", ");
} else {
hasColumnDefn = true;
}
sb.append(columnName).append(' ').append(columnDefn);
}

public void appendColumn(String column) {
//String bind = (insertMode > 0) ? "?" : "=?";
appendColumn(column, "?");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import io.ebean.annotation.Platform;
import io.ebean.bean.EntityBean;
import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebean.config.dbplatform.InsertSqlSyntaxExtension;
import io.ebeaninternal.server.core.PersistRequestBean;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.deploy.InheritInfo;
Expand Down Expand Up @@ -37,10 +38,13 @@ final class InsertMeta {
private final Bindable shadowFKey;
private final String[] identityDbColumns;
private final Platform platform;
private final InsertSqlSyntaxExtension insertMetaSql;

private final InsertMetaOptions options;

InsertMeta(DatabasePlatform dbPlatform, BeanDescriptor<?> desc, Bindable shadowFKey, BindableId id, BindableList all) {
this.platform = dbPlatform.platform();
this.insertMetaSql = dbPlatform.insertSqlSyntaxExtension();
this.options = InsertMetaPlatform.create(platform, desc, this);
this.discriminator = discriminator(desc);
this.id = id;
Expand Down Expand Up @@ -174,7 +178,7 @@ void sql(GenerateDmlRequest request, boolean nullId, String table, boolean draft
request.append(defaultValues());
return;
}
request.append(" (");
request.append(insertMetaSql.startColumns());
if (!nullId) {
id.dmlAppend(request);
}
Expand All @@ -189,9 +193,28 @@ void sql(GenerateDmlRequest request, boolean nullId, String table, boolean draft
} else {
allExcludeDraftOnly.dmlAppend(request);
}
request.append(") values (");
request.append(request.insertBindBuffer());
request.append(")");
request.append(insertMetaSql.endColumns());
if (insertMetaSql.useBinding()) {
request.append(request.insertBindBuffer());
request.append(")");
} else {
request.append(insertMetaSql.startTypes());
if (!nullId) {
id.dmlType(request);
}
if (shadowFKey != null) {
shadowFKey.dmlType(request);
}
if (discriminator != null) {
discriminator.dmlType(request);
}
if (draftTable) {
all.dmlType(request);
} else {
allExcludeDraftOnly.dmlType(request);
}
request.append(insertMetaSql.endTypes());
}
}

private String defaultValues() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ public interface Bindable {
*/
void dmlAppend(GenerateDmlRequest request);

/**
* Append column and type for Insert (ClickHouse).
*/
void dmlType(GenerateDmlRequest request);

/**
* Bind given the request and bean. The bean could be the oldValues bean
* when binding a update or delete where clause with ALL concurrency mode.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ public final void dmlAppend(GenerateDmlRequest request) {
importedId.dmlAppend(request);
}

@Override
public void dmlType(GenerateDmlRequest request) {
importedId.dmlType(request);
}

@Override
public void dmlBind(BindableRequest request, EntityBean bean) throws SQLException {
EntityBean assocBean = (EntityBean) assocOne.getValue(bean);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ public void dmlAppend(GenerateDmlRequest request) {
request.appendColumn(columnName);
}

@Override
public void dmlType(GenerateDmlRequest request) {
throw new IllegalArgumentException("Not supported");
}

@Override
public void dmlBind(BindableRequest bindRequest, EntityBean bean) throws SQLException {
bindRequest.bind(discValue, sqlType);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ public void dmlAppend(GenerateDmlRequest request) {
}
}

@Override
public void dmlType(GenerateDmlRequest request) {
for (Bindable item : items) {
item.dmlType(request);
}
}

@Override
public void addToUpdate(PersistRequestBean<?> request, List<Bindable> list) {
if (request.isAddToUpdate(embProp)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ public void dmlAppend(GenerateDmlRequest request) {
request.appendColumn(prop.dbColumn(), prop.dbBind());
}

@Override
public void dmlType(GenerateDmlRequest request) {
request.appendColumnDefn(prop.dbColumn(), prop.dbColumnDefn());
}

@Override
public void dmlBind(BindableRequest request, EntityBean bean) throws SQLException {
Object value = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,13 @@ public void dmlAppend(GenerateDmlRequest request) {
}
}

@Override
public void dmlType(GenerateDmlRequest request) {
for (BeanProperty prop : props) {
request.appendColumn(prop.dbColumnDefn());
}
}

@Override
public boolean deriveConcatenatedId(PersistRequestBean<?> persist) {
if (matches == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ public void dmlAppend(GenerateDmlRequest request) {
// nothing
}

@Override
public void dmlType(GenerateDmlRequest request) {
// nothing
}

@Override
public void dmlBind(BindableRequest request, EntityBean bean) {
// nothing
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,18 @@ public boolean deriveConcatenatedId(PersistRequestBean<?> persist) {

@Override
public void dmlAppend(GenerateDmlRequest request) {

request.appendColumn(uidProp.dbColumn());
}

@Override
public void dmlBind(BindableRequest request, EntityBean bean) throws SQLException {
public void dmlType(GenerateDmlRequest request) {
request.appendColumnDefn(uidProp.dbColumn(), uidProp.dbColumnDefn());
}

@Override
public void dmlBind(BindableRequest request, EntityBean bean) throws SQLException {
Object value = uidProp.getValue(bean);

request.bind(value, uidProp);

// used for summary logging
request.setIdValue(value);
}
Expand Down
Loading
Loading