Compare commits

...
14 changed files with 215 additions and 35 deletions
+2 -2
View File
@@ -9,7 +9,7 @@
<groupId>io.ebean</groupId>
<artifactId>ebean</artifactId>
<version>11.22.9</version>
<version>11.22.10</version>
<packaging>jar</packaging>
<name>ebean</name>
@@ -22,7 +22,7 @@
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-11.22.9</tag>
<tag>ebean-11.22.10</tag>
</scm>
<profiles>
@@ -8,7 +8,9 @@ import java.util.regex.Pattern;
*/
public class DbIdentity {
private static final Pattern TABLE_REPLACE = Pattern.compile("{table}", Pattern.LITERAL);
private static final String TABLE_PLACEHOLDER = "{table}";
private static final Pattern TABLE_REPLACE = Pattern.compile(TABLE_PLACEHOLDER, Pattern.LITERAL);
/**
* Set if this DB supports sequences. Note some DB's support both Sequences
@@ -53,7 +55,9 @@ public class DbIdentity {
if (selectLastInsertedIdTemplate == null) {
return null;
}
if (!selectLastInsertedIdTemplate.contains(TABLE_PLACEHOLDER)) {
return selectLastInsertedIdTemplate;
}
return TABLE_REPLACE.matcher(selectLastInsertedIdTemplate).replaceAll(Matcher.quoteReplacement(table));
}
@@ -7,6 +7,7 @@ import io.ebean.config.dbplatform.DatabasePlatform;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.ServiceLoader;
/**
@@ -147,6 +148,11 @@ public interface DbMigration {
*/
void addDatabasePlatform(DatabasePlatform databasePlatform, String prefix);
/**
* Return the list of versions that contain pending drops.
*/
List<String> getPendingDrops();
/**
* Generate the next migration xml file and associated apply and rollback sql scripts.
* <p>
@@ -303,6 +303,23 @@ public class DefaultDbMigration implements DbMigration {
}
}
/**
* Return the versions containing pending drops.
*/
public List<String> getPendingDrops() {
if (!online) {
DbOffline.setGenerateMigration();
}
setDefaults();
try {
return createRequest().getPendingDrops();
} finally {
if (!online) {
DbOffline.reset();
}
}
}
/**
* Load the configuration for each of the target platforms.
*/
@@ -494,6 +511,9 @@ public class DefaultDbMigration implements DbMigration {
if (nextDrop != null) {
return nextDrop;
}
if (generatePendingDrop != null) {
return generatePendingDrop;
}
return migrationConfig.getGeneratePendingDrop();
}
@@ -595,9 +615,6 @@ public class DefaultDbMigration implements DbMigration {
if (name != null) {
migrationConfig.setName(name);
}
if (generatePendingDrop != null) {
migrationConfig.setGeneratePendingDrop(generatePendingDrop);
}
}
}
@@ -1398,4 +1398,10 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
return orphanBean;
}
/**
* Return the SQL used to fetch the last inserted id value.
*/
public String getSelectLastInsertedId() {
return beanDescriptor.getSelectLastInsertedId(publish);
}
}
@@ -182,6 +182,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
* getGeneratedKeys is not supported.
*/
private final String selectLastInsertedId;
private final String selectLastInsertedIdDraft;
private final boolean autoTunable;
@@ -473,6 +474,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
this.sequenceInitialValue = deploy.getSequenceInitialValue();
this.sequenceAllocationSize = deploy.getSequenceAllocationSize();
this.selectLastInsertedId = deploy.getSelectLastInsertedId();
this.selectLastInsertedIdDraft = deploy.getSelectLastInsertedIdDraft();
this.concurrencyMode = deploy.getConcurrencyMode();
this.updateChangesOnly = deploy.isUpdateChangesOnly();
this.indexDefinitions = deploy.getIndexDefinitions();
@@ -3086,8 +3088,15 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
* supported.
* </p>
*/
public String getSelectLastInsertedId() {
return selectLastInsertedId;
public String getSelectLastInsertedId(boolean publish) {
return publish ? selectLastInsertedId : selectLastInsertedIdDraft;
}
/**
* Return true if this bean uses a SQL select to fetch the last inserted id value.
*/
public boolean supportsSelectLastInsertedId() {
return selectLastInsertedId != null;
}
@Override
@@ -1387,9 +1387,10 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
}
if (IdType.IDENTITY == desc.getIdType()) {
// used when getGeneratedKeys is not supported (SQL Server 2000)
// used when getGeneratedKeys is not supported (SQL Server 2000, SAP Hana)
String selectLastInsertedId = dbIdentity.getSelectLastInsertedId(desc.getBaseTable());
desc.setSelectLastInsertedId(selectLastInsertedId);
String selectLastInsertedIdDraft = (!desc.isDraftable()) ? selectLastInsertedId : dbIdentity.getSelectLastInsertedId(desc.getDraftTable());
desc.setSelectLastInsertedId(selectLastInsertedId, selectLastInsertedIdDraft);
return;
}
@@ -126,6 +126,7 @@ public class DeployBeanDescriptor<T> {
* Used with Identity columns but no getGeneratedKeys support.
*/
private String selectLastInsertedId;
private String selectLastInsertedIdDraft;
/**
* The concurrency mode for beans of this type.
@@ -839,11 +840,16 @@ public class DeployBeanDescriptor<T> {
return selectLastInsertedId;
}
public String getSelectLastInsertedIdDraft() {
return selectLastInsertedIdDraft;
}
/**
* Set the SQL used to return the last inserted Id.
*/
public void setSelectLastInsertedId(String selectLastInsertedId) {
public void setSelectLastInsertedId(String selectLastInsertedId, String selectLastInsertedIdDraft) {
this.selectLastInsertedId = selectLastInsertedId;
this.selectLastInsertedIdDraft = selectLastInsertedIdDraft;
}
/**
@@ -39,7 +39,7 @@ public class InsertHandler extends DmlHandler {
* A SQL Select used to fetch back the Id where generatedKeys is not
* supported.
*/
private String selectLastInsertedId;
private boolean useSelectLastInsertedId;
/**
* Create to handle the insert execution.
@@ -79,7 +79,7 @@ public class InsertHandler extends DmlHandler {
useGeneratedKeys = true;
} else {
// use a query to get the last inserted id
selectLastInsertedId = meta.getSelectLastInsertedId();
useSelectLastInsertedId = meta.supportsSelectLastInsertedId();
}
}
@@ -117,8 +117,7 @@ public class InsertHandler extends DmlHandler {
}
/**
* Execute the insert in a normal non batch fashion. Additionally using
* getGeneratedKeys if required.
* Execute non batched insert additionally using getGeneratedKeys if required.
*/
@Override
public int execute() throws SQLException, OptimisticLockException {
@@ -127,7 +126,7 @@ public class InsertHandler extends DmlHandler {
// get the auto-increment value back and set into the bean
getGeneratedKeys();
} else if (selectLastInsertedId != null) {
} else if (useSelectLastInsertedId) {
// fetch back the Id using a query
fetchGeneratedKeyUsingSelect();
}
@@ -167,12 +166,10 @@ public class InsertHandler extends DmlHandler {
*/
private void fetchGeneratedKeyUsingSelect() throws SQLException {
Connection conn = transaction.getConnection();
PreparedStatement stmt = null;
ResultSet rset = null;
try {
stmt = conn.prepareStatement(selectLastInsertedId);
stmt = transaction.getConnection().prepareStatement(persistRequest.getSelectLastInsertedId());
rset = stmt.executeQuery();
setGeneratedKey(rset);
} finally {
@@ -38,7 +38,7 @@ public final class InsertMeta {
/**
* Used for DB that do not support getGeneratedKeys.
*/
private final String selectLastInsertedId;
private final boolean supportsSelectLastInsertedId;
private final Bindable shadowFKey;
@@ -69,7 +69,7 @@ public final class InsertMeta {
this.sqlNullId = null;
this.sqlDraftNullId = null;
this.supportsGetGeneratedKeys = false;
this.selectLastInsertedId = null;
this.supportsSelectLastInsertedId = false;
} else {
// insert sql for db identity or sequence insert
@@ -77,11 +77,11 @@ public final class InsertMeta {
if (id.getIdentityColumn() == null) {
this.identityDbColumns = new String[]{};
this.supportsGetGeneratedKeys = false;
this.selectLastInsertedId = null;
this.supportsSelectLastInsertedId = false;
} else {
this.identityDbColumns = new String[]{id.getIdentityColumn()};
this.supportsGetGeneratedKeys = dbPlatform.getDbIdentity().isSupportsGetGeneratedKeys();
this.selectLastInsertedId = desc.getSelectLastInsertedId();
this.supportsSelectLastInsertedId = desc.supportsSelectLastInsertedId();
}
this.sqlNullId = genSql(true, tableName, false);
this.sqlDraftNullId = desc.isDraftable() ? genSql(true, draftTableName, true) : sqlNullId;
@@ -116,15 +116,11 @@ public final class InsertMeta {
}
/**
* Returns sql that is used to fetch back the last inserted id. This will
* return null if it should not be used.
* <p>
* This is only for DB's that do not support getGeneratedKeys. For MS
* SQLServer 2000 this could return "SELECT (at)(at)IDENTITY as id".
* </p>
* Return true if we should use a SQL query to return the generated key.
* This can not be used with JDBC batch mode.
*/
public String getSelectLastInsertedId() {
return selectLastInsertedId;
public boolean supportsSelectLastInsertedId() {
return supportsSelectLastInsertedId;
}
/**
@@ -0,0 +1,103 @@
package io.ebean.config;
import io.ebean.EbeanServer;
import io.ebean.EbeanServerFactory;
import io.ebean.Transaction;
import io.ebean.annotation.Platform;
import io.ebean.config.dbplatform.DbIdentity;
import io.ebean.config.dbplatform.IdType;
import io.ebean.config.dbplatform.h2.H2Platform;
import org.junit.Test;
import org.tests.model.basic.EBasicVer;
import org.tests.model.draftable.BasicDraftableBean;
import static org.assertj.core.api.StrictAssertions.assertThat;
public class PlatformNoGeneratedKeysTest {
static EbeanServer server = testH2Server();
@Test
public void insertBatch_expect_noIdValuesFetched() {
EBasicVer b0 = new EBasicVer("a");
EBasicVer b1 = new EBasicVer("b");
EBasicVer b2 = new EBasicVer("c");
try (Transaction transaction = server.beginTransaction()) {
transaction.setBatchMode(true);
server.save(b0);
server.save(b1);
server.save(b2);
transaction.commit();
}
assertThat(b0.getId()).isNull();
assertThat(b1.getId()).isNull();
assertThat(b2.getId()).isNull();
}
@Test
public void insertNoBatch_expect_selectIdentity() {
EBasicVer b0 = new EBasicVer("one");
server.save(b0);
assertThat(b0.getId()).isNotNull();
BasicDraftableBean d0 = new BasicDraftableBean("done");
server.save(d0);
assertThat(d0.getId()).isNotNull();
server.publish(BasicDraftableBean.class, d0.getId());
BasicDraftableBean one = server.find(BasicDraftableBean.class, d0.getId());
assertThat(one.getName()).isEqualTo("done");
assertThat(one.isDraft()).isFalse();
}
private static EbeanServer testH2Server() {
ServerConfig config = new ServerConfig();
config.setName("h2_noGeneratedKeys");
OtherH2Platform platform = new OtherH2Platform();
DbIdentity dbIdentity = platform.getDbIdentity();
dbIdentity.setIdType(IdType.IDENTITY);
dbIdentity.setSupportsIdentity(true);
dbIdentity.setSupportsGetGeneratedKeys(false);
dbIdentity.setSupportsSequence(false);
dbIdentity.setSelectLastInsertedIdTemplate("select identity() --{table}");
config.setDatabasePlatform(platform);
config.getDataSourceConfig().setUsername("sa");
config.getDataSourceConfig().setPassword("");
config.getDataSourceConfig().setUrl("jdbc:h2:mem:withPCQuery;");
config.getDataSourceConfig().setDriver("org.h2.Driver");
config.setDisableL2Cache(true);
config.setDefaultServer(false);
config.setRegister(false);
config.setDdlGenerate(true);
config.setDdlRun(true);
config.getClasses().add(EBasicVer.class);
config.getClasses().add(BasicDraftableBean.class);
return EbeanServerFactory.create(config);
}
static class OtherH2Platform extends H2Platform {
OtherH2Platform() {
super();
this.platform = Platform.GENERIC;
}
}
}
@@ -2,7 +2,6 @@ package io.ebeaninternal.dbmigration;
import io.ebean.EbeanServer;
import io.ebean.EbeanServerFactory;
import io.ebean.annotation.Platform;
import io.ebean.config.ServerConfig;
import org.junit.Test;
import org.slf4j.Logger;
@@ -13,6 +12,7 @@ import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.StrictAssertions.assertThatThrownBy;
@@ -71,8 +71,11 @@ public class DbMigrationDropHistoryTest {
assertThat(migration.generateMigration()).isNull(); // subsequent call
List<String> pendingDrops = migration.getPendingDrops();
assertThat(pendingDrops).contains("1.1");
System.setProperty("ddl.migration.pendingDropsFor", "1.1");
//System.setProperty("ddl.migration.pendingDropsFor", "1.1");
migration.setGeneratePendingDrop("1.1");
assertThat(migration.generateMigration()).isEqualTo("1.2__dropsFor_1.1");
assertThatThrownBy(()->migration.generateMigration())
.isInstanceOf(IllegalArgumentException.class)
@@ -0,0 +1,32 @@
package org.tests.model.draftable;
import io.ebean.annotation.Draft;
import io.ebean.annotation.Draftable;
import javax.persistence.Entity;
@Entity
@Draftable
public class BasicDraftableBean extends BaseDomain {
private String name;
@Draft
boolean draft;
public BasicDraftableBean(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isDraft() {
return draft;
}
}
+1 -1
View File
@@ -4,7 +4,7 @@
<ddl-script name="order views" platforms="h2" drop="true">
drop view order_agg_vw if exists;
</ddl-script>
<ddl-script name="order views" platforms="generic,db2,h2,postgres,oracle,mysql">
<ddl-script name="order views" platforms="db2,h2,postgres,oracle,mysql">
create or replace view order_agg_vw as
select d.order_id, sum(d.order_qty * d.unit_price) as order_total,