From 00b0fcaeb3e81417a8f211b3094f2e052136bbc4 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Mon, 22 Mar 2021 23:24:16 +1300 Subject: [PATCH 01/52] #2202 - kotlin-maven-plugin issue with JDK 16 Temporary modify tests to not invoke the kotlin-maven-plugin while adding JDK 16 specific tests. Hitting error InaccessibleObjectException: Unable to make protected void java.util.ResourceBundle.setParent(java.util.ResourceBundle) accessible: module java.base does not "opens java.util" to unnamed module @62732be7 --- kotlin-querybean-generator/pom.xml | 77 +++++++++++++++--------------- 1 file changed, 39 insertions(+), 38 deletions(-) diff --git a/kotlin-querybean-generator/pom.xml b/kotlin-querybean-generator/pom.xml index 7016e2aa4..cf3dca074 100644 --- a/kotlin-querybean-generator/pom.xml +++ b/kotlin-querybean-generator/pom.xml @@ -12,7 +12,7 @@ kotlin-querybean-generator - 1.4.21 + 1.4.31 @@ -81,46 +81,47 @@ src/test/kotlin - - org.jetbrains.kotlin - kotlin-maven-plugin - ${kotlin.version} - - - test-compile - test-compile - - test-compile - - - - test-kapt - - test-kapt - - - - src/test/kotlin - - - - - - - - - - - - - - 1.8 - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.apache.maven.plugins maven-compiler-plugin - 3.2 + 3.8.1 default-testCompile From 78965c1ac4476ea3f6fc03b945f9b8582cbc52f6 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Mon, 22 Mar 2021 23:43:35 +1300 Subject: [PATCH 02/52] #2203 - Support use of Java Record type with @Entity, @Embeddable @IdClass Allow java.lang.Record to be a root level parent for entity beans etc --- .../ebeaninternal/server/deploy/BeanDescriptorManager.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java index 0cb5deeaa..dca6b2b09 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java @@ -93,6 +93,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap { private static final Logger logger = LoggerFactory.getLogger(BeanDescriptorManager.class); private static final BeanDescComparator beanDescComparator = new BeanDescComparator(); + public static final String JAVA_LANG_RECORD = "java.lang.Record"; private final ReadAnnotations readAnnotations; private final TransientProperties transientProperties; @@ -1418,14 +1419,10 @@ public class BeanDescriptorManager implements BeanDescriptorMap { */ private void checkInheritedClasses(Class beanClass) { Class superclass = beanClass.getSuperclass(); - if (Object.class.equals(superclass)) { + if (Object.class.equals(superclass) || Model.class.equals(superclass) || JAVA_LANG_RECORD.equals(superclass.getName())) { // we got to the top of the inheritance return; } - if (Model.class.equals(superclass)) { - // top of the inheritance. Not enhancing Model at this stage - return; - } if (!EntityBean.class.isAssignableFrom(superclass)) { if (isMappedSuperWithNoProperties(superclass)) { // ok to stop and treat just the same as Object.class From 94bab5f83b7e0b959dc2e63e7a3e4c7609450bf0 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Mon, 22 Mar 2021 23:44:10 +1300 Subject: [PATCH 03/52] #2203 - Support use of Java Record type with @Entity, @Embeddable @IdClass Add tests for entity use of record type --- tests/pom.xml | 23 +++++++ tests/test-java16/pom.xml | 69 +++++++++++++++++++ .../java/org/example/records/BaseModel.java | 35 ++++++++++ .../main/java/org/example/records/Course.java | 33 +++++++++ .../example/records/CourseRecordEntity.java | 13 ++++ .../records/CourseRecordEntityTest.java | 40 +++++++++++ .../records/DtoQueryUsingRecordsTest.java | 59 ++++++++++++++++ .../src/test/resources/application-test.yaml | 6 ++ .../src/test/resources/logback-test.xml | 22 ++++++ 9 files changed, 300 insertions(+) create mode 100644 tests/pom.xml create mode 100644 tests/test-java16/pom.xml create mode 100644 tests/test-java16/src/main/java/org/example/records/BaseModel.java create mode 100644 tests/test-java16/src/main/java/org/example/records/Course.java create mode 100644 tests/test-java16/src/main/java/org/example/records/CourseRecordEntity.java create mode 100644 tests/test-java16/src/test/java/org/example/records/CourseRecordEntityTest.java create mode 100644 tests/test-java16/src/test/java/org/example/records/DtoQueryUsingRecordsTest.java create mode 100644 tests/test-java16/src/test/resources/application-test.yaml create mode 100644 tests/test-java16/src/test/resources/logback-test.xml diff --git a/tests/pom.xml b/tests/pom.xml new file mode 100644 index 000000000..2c79d71fa --- /dev/null +++ b/tests/pom.xml @@ -0,0 +1,23 @@ + + + 4.0.0 + + org.avaje + java8-oss + 2.3 + + + io.ebean + tests + 1.0 + pom + + tests + test modules + + + test-java16 + + + + diff --git a/tests/test-java16/pom.xml b/tests/test-java16/pom.xml new file mode 100644 index 000000000..21dfa7852 --- /dev/null +++ b/tests/test-java16/pom.xml @@ -0,0 +1,69 @@ + + + 4.0.0 + + + + + + + io.ebean + test-java16 + 1.0 + + + 3.8.1 + + + + + io.ebean + ebean + 12.8.1-SNAPSHOT + + + + ch.qos.logback + logback-classic + 1.2.3 + + + + io.ebean + ebean-test + 12.8.1-SNAPSHOT + test + + + + org.avaje.composite + junit + 5.0 + test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + 16 + 16 + 16 + + + io.ebean + querybean-generator + 12.8.1-SNAPSHOT + + + + + + + + + diff --git a/tests/test-java16/src/main/java/org/example/records/BaseModel.java b/tests/test-java16/src/main/java/org/example/records/BaseModel.java new file mode 100644 index 000000000..b5116e638 --- /dev/null +++ b/tests/test-java16/src/main/java/org/example/records/BaseModel.java @@ -0,0 +1,35 @@ +package org.example.records; + +import io.ebean.Model; +import io.ebean.annotation.Identity; + +import javax.persistence.Id; +import javax.persistence.MappedSuperclass; +import javax.persistence.Version; + +@Identity(start = 1000, cache = 100) +@MappedSuperclass +public class BaseModel extends Model { + + @Id + long id; + + @Version + long version; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public long getVersion() { + return version; + } + + public void setVersion(long version) { + this.version = version; + } +} diff --git a/tests/test-java16/src/main/java/org/example/records/Course.java b/tests/test-java16/src/main/java/org/example/records/Course.java new file mode 100644 index 000000000..19e8d09fe --- /dev/null +++ b/tests/test-java16/src/main/java/org/example/records/Course.java @@ -0,0 +1,33 @@ +package org.example.records; + +import io.ebean.annotation.Length; + +import javax.persistence.Entity; +import javax.persistence.Table; + +@Entity +@Table(name = "course") +public class Course extends BaseModel { + + @Length(200) + final String name; + + @Length(400) + String summary; + + public Course(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public String getSummary() { + return summary; + } + + public void setSummary(String summary) { + this.summary = summary; + } +} diff --git a/tests/test-java16/src/main/java/org/example/records/CourseRecordEntity.java b/tests/test-java16/src/main/java/org/example/records/CourseRecordEntity.java new file mode 100644 index 000000000..dc95a8723 --- /dev/null +++ b/tests/test-java16/src/main/java/org/example/records/CourseRecordEntity.java @@ -0,0 +1,13 @@ +package org.example.records; + +import io.ebean.annotation.Identity; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; + +@Identity(start = 1000) +@Entity +@Table(name="course_rec") +public record CourseRecordEntity(@Id long id, String name, String notes) { +} diff --git a/tests/test-java16/src/test/java/org/example/records/CourseRecordEntityTest.java b/tests/test-java16/src/test/java/org/example/records/CourseRecordEntityTest.java new file mode 100644 index 000000000..63e0c7d84 --- /dev/null +++ b/tests/test-java16/src/test/java/org/example/records/CourseRecordEntityTest.java @@ -0,0 +1,40 @@ +package org.example.records; + +import io.ebean.DB; +import org.example.records.query.QCourseRecordEntity; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class CourseRecordEntityTest { + + @Test + void record_insert_withGivenIdValue() { + var course = new CourseRecordEntity(42, "SuppliedId", "Record"); + DB.save(course); + assertThat(course.id()).isEqualTo(42); + + var found = new QCourseRecordEntity() + .name.startsWith("SuppliedId") + .findOneOrEmpty(); + + assertThat(found).isPresent(); + assertThat(found.get().id()).isEqualTo(42L); + assertThat(found.get().notes()).isEqualTo("Record"); + } + + @Test + void record_insert_usingGeneratedId() { + var course2 = new CourseRecordEntity(0, "Second", "Record with generated id"); + DB.save(course2); + // as using @Identity(start = 1000) + assertThat(course2.id()).isEqualTo(1000); + + var second = new QCourseRecordEntity() + .name.startsWith("Second") + .findOneOrEmpty(); + + assertThat(second).isPresent(); + assertThat(second.get().notes()).isEqualTo("Record with generated id"); + } +} diff --git a/tests/test-java16/src/test/java/org/example/records/DtoQueryUsingRecordsTest.java b/tests/test-java16/src/test/java/org/example/records/DtoQueryUsingRecordsTest.java new file mode 100644 index 000000000..e64c15b1c --- /dev/null +++ b/tests/test-java16/src/test/java/org/example/records/DtoQueryUsingRecordsTest.java @@ -0,0 +1,59 @@ +package org.example.records; + +import io.ebean.DB; +import org.example.records.query.QCourse; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.example.records.query.QCourse.Alias.id; +import static org.example.records.query.QCourse.Alias.name; + +class DtoQueryUsingRecordsTest { + + @Test + void dtoQuery_projectRecords() { + + var course = new Course("Calculus"); + course.setSummary("Something here"); + course.save(); + + performOrmQuery(); + + records_via_SqlDtoQuery(course); + records_via_OrmQueryToDtoQuery(course); + + course.delete(); + } + + private void performOrmQuery() { + List courses = new QCourse() + .name.startsWith("Calc") + .findList(); + + assertThat(courses).hasSize(1); + } + + private void records_via_SqlDtoQuery(Course course) { + List records = DB.findDto(Foo.class, "select id, name from course where name like ?") + .setParameter("Calc%") + .findList(); + + assertThat(records).hasSize(1); + assertThat(records.get(0).name()).isEqualTo(course.getName()); + } + + private void records_via_OrmQueryToDtoQuery(Course course) { + List records2 = new QCourse() + .select(id, name ) + .name.startsWith("Calc") + .asDto(Foo.class) + .findList(); + + assertThat(records2).hasSize(1); + assertThat(records2.get(0).name()).isEqualTo(course.getName()); + } + + public record Foo(long id, String name){} +} diff --git a/tests/test-java16/src/test/resources/application-test.yaml b/tests/test-java16/src/test/resources/application-test.yaml new file mode 100644 index 000000000..029b11023 --- /dev/null +++ b/tests/test-java16/src/test/resources/application-test.yaml @@ -0,0 +1,6 @@ +ebean: + test: + platform: h2 + ddlMode: dropCreate + dbName: foo + diff --git a/tests/test-java16/src/test/resources/logback-test.xml b/tests/test-java16/src/test/resources/logback-test.xml new file mode 100644 index 000000000..ce7ad5968 --- /dev/null +++ b/tests/test-java16/src/test/resources/logback-test.xml @@ -0,0 +1,22 @@ + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + + + + + + + + + From 548454c90d7d920efb6e9b217d084924b2f6b6f1 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Mon, 22 Mar 2021 23:57:14 +1300 Subject: [PATCH 04/52] #2203 - Support use of Java Record type with @Entity, @Embeddable @IdClass Add tests for embedded use of record type --- .../java/org/example/records/Address.java | 7 +++ .../java/org/example/records/Contact.java | 58 +++++++++++++++++++ .../example/records/RecordAsEmbeddedTest.java | 48 +++++++++++++++ 3 files changed, 113 insertions(+) create mode 100644 tests/test-java16/src/main/java/org/example/records/Address.java create mode 100644 tests/test-java16/src/main/java/org/example/records/Contact.java create mode 100644 tests/test-java16/src/test/java/org/example/records/RecordAsEmbeddedTest.java diff --git a/tests/test-java16/src/main/java/org/example/records/Address.java b/tests/test-java16/src/main/java/org/example/records/Address.java new file mode 100644 index 000000000..2ac531402 --- /dev/null +++ b/tests/test-java16/src/main/java/org/example/records/Address.java @@ -0,0 +1,7 @@ +package org.example.records; + +import javax.persistence.Embeddable; + +@Embeddable +public record Address (String line1, String line2, String city) { +} diff --git a/tests/test-java16/src/main/java/org/example/records/Contact.java b/tests/test-java16/src/main/java/org/example/records/Contact.java new file mode 100644 index 000000000..871862f21 --- /dev/null +++ b/tests/test-java16/src/main/java/org/example/records/Contact.java @@ -0,0 +1,58 @@ +package org.example.records; + +import io.ebean.Model; + +import javax.persistence.Embedded; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Version; + +@Entity +public class Contact extends Model { + + @Id + private long id; + + @Version + private long version; + + private final String name; + + @Embedded(prefix = "home_") + private Address homeAddress; + + @Embedded(prefix = "work_") + private Address workAddress; + + public Contact(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public Address getHomeAddress() { + return homeAddress; + } + + public void setHomeAddress(Address homeAddress) { + this.homeAddress = homeAddress; + } + + public Address getWorkAddress() { + return workAddress; + } + + public void setWorkAddress(Address workAddress) { + this.workAddress = workAddress; + } + + public long getId() { + return id; + } + + public long getVersion() { + return version; + } +} diff --git a/tests/test-java16/src/test/java/org/example/records/RecordAsEmbeddedTest.java b/tests/test-java16/src/test/java/org/example/records/RecordAsEmbeddedTest.java new file mode 100644 index 000000000..271481468 --- /dev/null +++ b/tests/test-java16/src/test/java/org/example/records/RecordAsEmbeddedTest.java @@ -0,0 +1,48 @@ +package org.example.records; + +import org.example.records.query.QContact; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.example.records.query.QContact.Alias.homeAddress; +import static org.example.records.query.QContact.Alias.name; + +public class RecordAsEmbeddedTest { + + @Test + void insert_query() { + + var contact = new Contact("Rob"); + contact.setWorkAddress(new Address("45 work", "workling", "wo")); + contact.setHomeAddress(new Address("94 home st", "homeline", "wo")); + + contact.save(); + + Contact found = new QContact() + .id.eq(contact.getId()) + .findOne(); + + assertThat(found.getWorkAddress().toString()).isEqualTo("Address[line1=45 work, line2=workling, city=wo]"); + assertThat(found.getHomeAddress().toString()).isEqualTo("Address[line1=94 home st, line2=homeline, city=wo]"); + + Contact foundPartial = new QContact() + .select(name, homeAddress) + .id.eq(contact.getId()) + .findOne(); + + // invoke lazy loading on getWorkAddress + assertThat(foundPartial.getWorkAddress().toString()).isEqualTo("Address[line1=45 work, line2=workling, city=wo]"); + assertThat(foundPartial.getHomeAddress().toString()).isEqualTo("Address[line1=94 home st, line2=homeline, city=wo]"); + + Contact foundNoLazyLoading = new QContact() + .select(name, homeAddress) + .setDisableLazyLoading(true) + .id.eq(contact.getId()) + .findOne(); + + // no lazy loading on getWorkAddress this time + assertThat(foundNoLazyLoading.getWorkAddress()).isNull(); + assertThat(foundNoLazyLoading.getHomeAddress().toString()).isEqualTo("Address[line1=94 home st, line2=homeline, city=wo]"); + + } +} From 53c903fa4815ddda4aa07079790a247cbab9cecd Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 23 Mar 2021 00:10:28 +1300 Subject: [PATCH 05/52] #2203 - Support use of Java Record type with @Entity, @Embeddable @IdClass Add tests for EmbeddedId use of record type --- .../java/org/example/records/UserRole.java | 36 ++++++++++++++++++ .../java/org/example/records/UserRoleId.java | 7 ++++ .../org/example/records/UserRoleTest.java | 38 +++++++++++++++++++ 3 files changed, 81 insertions(+) create mode 100644 tests/test-java16/src/main/java/org/example/records/UserRole.java create mode 100644 tests/test-java16/src/main/java/org/example/records/UserRoleId.java create mode 100644 tests/test-java16/src/test/java/org/example/records/UserRoleTest.java diff --git a/tests/test-java16/src/main/java/org/example/records/UserRole.java b/tests/test-java16/src/main/java/org/example/records/UserRole.java new file mode 100644 index 000000000..682e61f4a --- /dev/null +++ b/tests/test-java16/src/main/java/org/example/records/UserRole.java @@ -0,0 +1,36 @@ +package org.example.records; + +import io.ebean.Model; + +import javax.persistence.EmbeddedId; +import javax.persistence.Entity; +import javax.persistence.Version; + +@Entity +public class UserRole extends Model { + + @EmbeddedId + final UserRoleId id; + + String note; + + @Version + long version; + + public UserRole(UserRoleId id, String note) { + this.id = id; + this.note = note; + } + + public UserRoleId getId() { + return id; + } + + public String getNote() { + return note; + } + + public long getVersion() { + return version; + } +} diff --git a/tests/test-java16/src/main/java/org/example/records/UserRoleId.java b/tests/test-java16/src/main/java/org/example/records/UserRoleId.java new file mode 100644 index 000000000..a0807de0a --- /dev/null +++ b/tests/test-java16/src/main/java/org/example/records/UserRoleId.java @@ -0,0 +1,7 @@ +package org.example.records; + +import javax.persistence.Embeddable; + +@Embeddable +public record UserRoleId(Integer userId, String roleId) { +} diff --git a/tests/test-java16/src/test/java/org/example/records/UserRoleTest.java b/tests/test-java16/src/test/java/org/example/records/UserRoleTest.java new file mode 100644 index 000000000..1b4231b58 --- /dev/null +++ b/tests/test-java16/src/test/java/org/example/records/UserRoleTest.java @@ -0,0 +1,38 @@ +package org.example.records; + +import org.example.records.query.QUserRole; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class UserRoleTest { + + final UserRoleId id = new UserRoleId(42, "R7"); + + @Test + void id_equals() { + assertThat(id).isEqualTo(new UserRoleId(42, "R7")); + } + + @Test + void id_notEquals() { + assertThat(id).isNotEqualTo(new UserRoleId(43, "R7")); + assertThat(id).isNotEqualTo(new UserRoleId(42, "R8")); + } + + @Test + void insert_query() { + + var userRole = new UserRole(id, "hello"); + userRole.save(); + + UserRole found = new QUserRole() + .id.eq(new UserRoleId(42, "R7")) + .findOne(); + + UserRoleId id1 = found.getId(); + assertThat(id1).isEqualTo(id); + assertThat(id1.userId()).isEqualTo(42); + assertThat(id1.roleId()).isEqualTo("R7"); + } +} From 09a887aeb7df25466286bf7a8eaf7f388b8187d8 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 23 Mar 2021 00:19:52 +1300 Subject: [PATCH 06/52] #2203 - Support use of Java Record type with @Entity, @Embeddable @IdClass Add tests for IdClass use of record type --- .../java/org/example/records/UserSite.java | 51 +++++++++++++++++++ .../java/org/example/records/UserSiteId.java | 8 +++ .../example/records/RecordIdClassTest.java | 34 +++++++++++++ 3 files changed, 93 insertions(+) create mode 100644 tests/test-java16/src/main/java/org/example/records/UserSite.java create mode 100644 tests/test-java16/src/main/java/org/example/records/UserSiteId.java create mode 100644 tests/test-java16/src/test/java/org/example/records/RecordIdClassTest.java diff --git a/tests/test-java16/src/main/java/org/example/records/UserSite.java b/tests/test-java16/src/main/java/org/example/records/UserSite.java new file mode 100644 index 000000000..a8cf46449 --- /dev/null +++ b/tests/test-java16/src/main/java/org/example/records/UserSite.java @@ -0,0 +1,51 @@ +package org.example.records; + +import io.ebean.Model; + +import javax.persistence.*; +import java.util.UUID; + +@IdClass(UserSiteId.class) +@Entity +public class UserSite extends Model { + + @Id + final UUID userId; + + @Id + final UUID siteId; + + String note; + + @Version + long version; + + public UserSite(UUID userId, UUID siteId) { + this.userId = userId; + this.siteId = siteId; + } + + public UUID getUserId() { + return userId; + } + + public UUID getSiteId() { + return siteId; + } + + public void setNote(String note) { + this.note = note; + } + + public void setVersion(long version) { + this.version = version; + } + + public String getNote() { + return note; + } + + public long getVersion() { + return version; + } +} diff --git a/tests/test-java16/src/main/java/org/example/records/UserSiteId.java b/tests/test-java16/src/main/java/org/example/records/UserSiteId.java new file mode 100644 index 000000000..36c4dd599 --- /dev/null +++ b/tests/test-java16/src/main/java/org/example/records/UserSiteId.java @@ -0,0 +1,8 @@ +package org.example.records; + +import javax.persistence.Embeddable; +import java.util.UUID; + +@Embeddable +public record UserSiteId(UUID userId, UUID siteId) { +} diff --git a/tests/test-java16/src/test/java/org/example/records/RecordIdClassTest.java b/tests/test-java16/src/test/java/org/example/records/RecordIdClassTest.java new file mode 100644 index 000000000..47008c544 --- /dev/null +++ b/tests/test-java16/src/test/java/org/example/records/RecordIdClassTest.java @@ -0,0 +1,34 @@ +package org.example.records; + +import org.example.records.query.QUserSite; +import org.junit.jupiter.api.Test; + +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; + +class RecordIdClassTest { + + @Test + void insert_query() { + + UUID userId = UUID.randomUUID(); + UUID siteId = UUID.randomUUID(); + + var userSite = new UserSite(userId, siteId); + userSite.setNote("HelloIdClass"); + userSite.save(); + + var id = new UserSiteId(userId, siteId); + + UserSite found = new QUserSite() + .setId(id) + .findOne(); + + assertThat(found.getUserId()).isEqualTo(userId); + assertThat(found.getSiteId()).isEqualTo(siteId); + assertThat(found.getNote()).isEqualTo("HelloIdClass"); + + + } +} From b5cef354ad39ad70b07dca042e2f9f26b829ad02 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Tue, 23 Mar 2021 14:53:30 +1300 Subject: [PATCH 07/52] Refactor simplify LoadContext.getSecondaryQueriesMinBatchSize() No functional change here. Just move the constant into DLoadContext. --- .../src/main/java/io/ebeaninternal/api/LoadContext.java | 2 +- .../java/io/ebeaninternal/server/core/OrmQueryRequest.java | 4 ++-- .../io/ebeaninternal/server/loadcontext/DLoadContext.java | 4 ++-- .../main/java/io/ebeaninternal/server/query/CQueryEngine.java | 4 +--- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/ebean-core/src/main/java/io/ebeaninternal/api/LoadContext.java b/ebean-core/src/main/java/io/ebeaninternal/api/LoadContext.java index 4ba56604f..51f02826c 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/api/LoadContext.java +++ b/ebean-core/src/main/java/io/ebeaninternal/api/LoadContext.java @@ -16,7 +16,7 @@ public interface LoadContext { /** * Return the minimum batch size when using QueryIterator with query joins. */ - int getSecondaryQueriesMinBatchSize(int defaultQueryBatch); + int getSecondaryQueriesMinBatchSize(); /** * Execute any secondary (+query) queries if there are any defined. diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/core/OrmQueryRequest.java b/ebean-core/src/main/java/io/ebeaninternal/server/core/OrmQueryRequest.java index 9b0e1235e..3ec5deac7 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/core/OrmQueryRequest.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/core/OrmQueryRequest.java @@ -173,8 +173,8 @@ public final class OrmQueryRequest extends BeanRequest implements SpiOrmQuery * iteration is fine. *

*/ - public int getSecondaryQueriesMinBatchSize(int defaultQueryBatch) { - return loadContext.getSecondaryQueriesMinBatchSize(defaultQueryBatch); + public int getSecondaryQueriesMinBatchSize() { + return loadContext.getSecondaryQueriesMinBatchSize(); } /** diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadContext.java b/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadContext.java index b5aa6f873..912b8fc0c 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadContext.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadContext.java @@ -182,7 +182,7 @@ public class DLoadContext implements LoadContext { * Return the minimum batch size when using QueryIterator with query joins. */ @Override - public int getSecondaryQueriesMinBatchSize(int defaultQueryBatch) { + public int getSecondaryQueriesMinBatchSize() { if (secQuery == null) { return -1; } @@ -190,7 +190,7 @@ public class DLoadContext implements LoadContext { for (OrmQueryProperties aSecQuery : secQuery) { int batchSize = aSecQuery.getBatchSize(); if (batchSize == 0) { - batchSize = defaultQueryBatch; + batchSize = 100; } maxBatch = Math.max(maxBatch, batchSize); } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryEngine.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryEngine.java index 945b343ca..6e4804ca6 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryEngine.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryEngine.java @@ -37,8 +37,6 @@ public class CQueryEngine { private static final Logger logger = LoggerFactory.getLogger(CQueryEngine.class); - private static final int defaultSecondaryQueryBatchSize = 100; - private static final String T0 = "t0"; private final int defaultFetchSizeFindList; @@ -214,7 +212,7 @@ public class CQueryEngine { logSql(cquery); } // first check batch sizes set on query joins - int iterateBufferSize = request.getSecondaryQueriesMinBatchSize(defaultSecondaryQueryBatchSize); + int iterateBufferSize = request.getSecondaryQueriesMinBatchSize(); if (iterateBufferSize < 1) { // not set on query joins so check if batch size set on query itself int queryBatch = request.getQuery().getLazyLoadBatchSize(); From 562d175de1f4435d623f2c4abeec82b38b609f41 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Tue, 23 Mar 2021 23:17:07 +1300 Subject: [PATCH 08/52] With FetchConfig.ofLazy() honor query.setLazyLoadBatchSize() Use 0 for default lazy batch such that it honors a value set via query.setLazyLoadBatchSize() --- .../src/main/java/io/ebean/FetchConfig.java | 21 ++++------ .../server/loadcontext/DLoadBaseContext.java | 8 +--- .../server/loadcontext/DLoadBeanContext.java | 4 +- .../server/loadcontext/DLoadContext.java | 42 ++++++++++--------- .../server/loadcontext/DLoadManyContext.java | 7 +--- .../test/java/io/ebean/FetchConfigTest.java | 3 +- .../server/grammer/ParseFetchConfigTest.java | 2 +- .../org/tests/query/TestQueryFindEach.java | 38 ++++++++++++----- 8 files changed, 68 insertions(+), 57 deletions(-) diff --git a/ebean-api/src/main/java/io/ebean/FetchConfig.java b/ebean-api/src/main/java/io/ebean/FetchConfig.java index 64f4c3daa..e2d4fbe35 100644 --- a/ebean-api/src/main/java/io/ebean/FetchConfig.java +++ b/ebean-api/src/main/java/io/ebean/FetchConfig.java @@ -46,7 +46,7 @@ public class FetchConfig implements Serializable { /** * Deprecated - migrate to one of the static factory methods like {@link FetchConfig#ofQuery()} - * + *

* Construct using default JOIN mode. */ @Deprecated @@ -89,7 +89,7 @@ public class FetchConfig implements Serializable { * Return FetchConfig to lazily load the relationship. */ public static FetchConfig ofLazy() { - return new FetchConfig(LAZY_MODE, 10); + return new FetchConfig(LAZY_MODE, 0); } /** @@ -110,8 +110,8 @@ public class FetchConfig implements Serializable { * We want to migrate away from mutating FetchConfig to a fully immutable FetchConfig. */ private FetchConfig mutate(int mode, int batchSize) { - if (batchSize < 1) { - throw new IllegalArgumentException("batch size "+batchSize+" must be > 0"); + if (batchSize < 0) { + throw new IllegalArgumentException("batch size " + batchSize + " must be > 0"); } this.mode = mode; this.batchSize = batchSize; @@ -124,7 +124,7 @@ public class FetchConfig implements Serializable { */ @Deprecated public FetchConfig lazy() { - return mutate(LAZY_MODE, 10); + return mutate(LAZY_MODE, 0); } /** @@ -137,7 +137,7 @@ public class FetchConfig implements Serializable { /** * Deprecated - migrate to FetchConfig.ofQuery(). - * + *

* Eagerly fetch the beans in this path as a separate query (rather than as * part of the main query). *

@@ -150,17 +150,15 @@ public class FetchConfig implements Serializable { /** * Deprecated - migrate to FetchConfig.ofQuery(batchSize). - * + *

* Eagerly fetch the beans in this path as a separate query (rather than as * part of the main query). *

* The queryBatchSize is the number of parent id's that this separate query * will load per batch. - *

*

* This will load all beans on this path eagerly unless a {@link #lazy(int)} * is also used. - *

* * @param batchSize the batch size used to load beans on this path */ @@ -171,13 +169,12 @@ public class FetchConfig implements Serializable { /** * Deprecated - migrate to FetchConfig.ofQuery(batchSize). - * + *

* Eagerly fetch the first batch of beans on this path. * This is similar to {@link #query(int)} but only fetches the first batch. *

* If there are more parent beans than the batch size then they will not be * loaded eagerly but instead use lazy loading. - *

* * @param batchSize the number of parent beans this path is populated for */ @@ -188,7 +185,7 @@ public class FetchConfig implements Serializable { /** * Deprecated - migrate to FetchConfig.ofCache(). - * + *

* Eagerly fetch the beans fetching the beans from the L2 bean cache * and using the DB for beans not in the cache. */ diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadBaseContext.java b/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadBaseContext.java index 1be4717e9..24233cf87 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadBaseContext.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadBaseContext.java @@ -33,7 +33,7 @@ abstract class DLoadBaseContext { final boolean queryFetch; - DLoadBaseContext(DLoadContext parent, BeanDescriptor desc, String path, int defaultBatchSize, OrmQueryProperties queryProps) { + DLoadBaseContext(DLoadContext parent, BeanDescriptor desc, String path, OrmQueryProperties queryProps) { this.parent = parent; this.serverName = parent.getEbeanServer().getName(); this.desc = desc; @@ -42,11 +42,7 @@ abstract class DLoadBaseContext { this.hitCache = parent.isBeanCacheGet() && desc.isBeanCaching(); this.objectGraphNode = parent.getObjectGraphNode(path); this.queryFetch = queryProps != null && queryProps.isQueryFetch(); - this.batchSize = initBatchSize(defaultBatchSize, queryProps); - } - - private int initBatchSize(int batchSize, OrmQueryProperties queryProps) { - return queryProps == null ? batchSize : queryProps.getBatchSize(); + this.batchSize = parent.batchSize(queryProps); } /** diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadBeanContext.java b/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadBeanContext.java index d24a24532..25fffe5b7 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadBeanContext.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadBeanContext.java @@ -31,8 +31,8 @@ class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext { private LoadBuffer currentBuffer; - DLoadBeanContext(DLoadContext parent, BeanDescriptor desc, String path, int defaultBatchSize, OrmQueryProperties queryProps) { - super(parent, desc, path, defaultBatchSize, queryProps); + DLoadBeanContext(DLoadContext parent, BeanDescriptor desc, String path, OrmQueryProperties queryProps) { + super(parent, desc, path, queryProps); // bufferList only required when using query joins (queryFetch) this.bufferList = (!queryFetch) ? null : new ArrayList<>(); this.currentBuffer = createBuffer(batchSize); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadContext.java b/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadContext.java index 912b8fc0c..060633073 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadContext.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadContext.java @@ -90,7 +90,7 @@ public class DLoadContext implements LoadContext { this.planLabel = null; this.profileLocation = null; this.profilingListener = null; - this.rootBeanContext = new DLoadBeanContext(this, rootDescriptor, null, defaultBatchSize, null); + this.rootBeanContext = new DLoadBeanContext(this, rootDescriptor, null, null); } private ObjectGraphOrigin initOrigin() { @@ -128,7 +128,7 @@ public class DLoadContext implements LoadContext { } // initialise rootBeanContext after origin and relativePath have been set - this.rootBeanContext = new DLoadBeanContext(this, rootDescriptor, null, defaultBatchSize, null); + this.rootBeanContext = new DLoadBeanContext(this, rootDescriptor, null, null); registerSecondaryQueries(secondaryQueries); } @@ -287,51 +287,55 @@ public class DLoadContext implements LoadContext { getManyContext(path, many).register(bc); } + int batchSize(OrmQueryProperties props) { + if (props == null) { + return defaultBatchSize; + } + int batchSize = props.getBatchSize(); + return batchSize == 0 ? defaultBatchSize : batchSize; + } + DLoadBeanContext getBeanContext(String path) { if (path == null) { return rootBeanContext; } - return beanMap.computeIfAbsent(path, p -> createBeanContext(p, defaultBatchSize, null)); + return beanMap.computeIfAbsent(path, p -> createBeanContext(p, null)); } DLoadBeanContext getBeanContextWithInherit(String path, BeanPropertyAssocOne property) { String key = path + ":" + property.getTargetDescriptor().getName(); - return beanMap.computeIfAbsent(key, p -> createBeanContext(property, path, defaultBatchSize, null)); + return beanMap.computeIfAbsent(key, p -> createBeanContext(property, path, null)); } private void registerSecondaryNode(boolean many, OrmQueryProperties props) { - int batchSize = props.getBatchSize(); - if (batchSize == 0) { - batchSize = defaultBatchSize; - } String path = props.getPath(); if (many) { - manyMap.put(path, createManyContext(path, batchSize, props)); + manyMap.put(path, createManyContext(path, props)); } else { - beanMap.put(path, createBeanContext(path, batchSize, props)); + beanMap.put(path, createBeanContext(path, props)); } } DLoadManyContext getManyContext(String path, BeanPropertyAssocMany many) { - return manyMap.computeIfAbsent(path, p -> createManyContext(p, many, defaultBatchSize)); + return manyMap.computeIfAbsent(path, p -> createManyContext(p, many)); } - private DLoadManyContext createManyContext(String path, BeanPropertyAssocMany many, int batchSize) { - return new DLoadManyContext(this, many, path, batchSize, null); + private DLoadManyContext createManyContext(String path, BeanPropertyAssocMany many) { + return new DLoadManyContext(this, many, path, null); } - private DLoadManyContext createManyContext(String path, int batchSize, OrmQueryProperties queryProps) { + private DLoadManyContext createManyContext(String path, OrmQueryProperties queryProps) { BeanPropertyAssocMany p = (BeanPropertyAssocMany) getBeanProperty(rootDescriptor, path); - return new DLoadManyContext(this, p, path, batchSize, queryProps); + return new DLoadManyContext(this, p, path, queryProps); } - private DLoadBeanContext createBeanContext(String path, int batchSize, OrmQueryProperties queryProps) { + private DLoadBeanContext createBeanContext(String path, OrmQueryProperties queryProps) { BeanPropertyAssoc p = (BeanPropertyAssoc) getBeanProperty(rootDescriptor, path); - return new DLoadBeanContext(this, p.getTargetDescriptor(), path, batchSize, queryProps); + return new DLoadBeanContext(this, p.getTargetDescriptor(), path, queryProps); } - private DLoadBeanContext createBeanContext(BeanPropertyAssoc property, String path, int batchSize, OrmQueryProperties queryProps) { - return new DLoadBeanContext(this, property.getTargetDescriptor(), path, batchSize, queryProps); + private DLoadBeanContext createBeanContext(BeanPropertyAssoc property, String path, OrmQueryProperties queryProps) { + return new DLoadBeanContext(this, property.getTargetDescriptor(), path, queryProps); } private BeanProperty getBeanProperty(BeanDescriptor desc, String path) { diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadManyContext.java b/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadManyContext.java index 7a51127d8..5035f0802 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadManyContext.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadManyContext.java @@ -31,11 +31,8 @@ class DLoadManyContext extends DLoadBaseContext implements LoadManyContext { private LoadBuffer currentBuffer; - DLoadManyContext(DLoadContext parent, BeanPropertyAssocMany property, - String path, int defaultBatchSize, OrmQueryProperties queryProps) { - - super(parent, property.getBeanDescriptor(), path, defaultBatchSize, queryProps); - + DLoadManyContext(DLoadContext parent, BeanPropertyAssocMany property, String path, OrmQueryProperties queryProps) { + super(parent, property.getBeanDescriptor(), path, queryProps); this.property = property; this.docStoreMapped = property.isTargetDocStoreMapped(); // bufferList only required when using query joins (queryFetch) diff --git a/ebean-core/src/test/java/io/ebean/FetchConfigTest.java b/ebean-core/src/test/java/io/ebean/FetchConfigTest.java index abd09d692..f85808f6c 100644 --- a/ebean-core/src/test/java/io/ebean/FetchConfigTest.java +++ b/ebean-core/src/test/java/io/ebean/FetchConfigTest.java @@ -1,6 +1,5 @@ package io.ebean; -import io.ebean.FetchConfig; import org.junit.Test; import static org.assertj.core.api.Assertions.assertThat; @@ -10,7 +9,7 @@ public class FetchConfigTest { @Test public void testLazy() { FetchConfig config = new FetchConfig().lazy(); - assertThat(config.getBatchSize()).isEqualTo(10); + assertThat(config.getBatchSize()).isEqualTo(0); } @Test diff --git a/ebean-core/src/test/java/io/ebeaninternal/server/grammer/ParseFetchConfigTest.java b/ebean-core/src/test/java/io/ebeaninternal/server/grammer/ParseFetchConfigTest.java index a940cd26b..c4976f56d 100644 --- a/ebean-core/src/test/java/io/ebeaninternal/server/grammer/ParseFetchConfigTest.java +++ b/ebean-core/src/test/java/io/ebeaninternal/server/grammer/ParseFetchConfigTest.java @@ -19,7 +19,7 @@ public class ParseFetchConfigTest { @Test public void parseLazy() { FetchConfig lazy = ParseFetchConfig.parse("lazy"); - assertThat(lazy.getBatchSize()).isEqualTo(10); + assertThat(lazy.getBatchSize()).isEqualTo(0); } @Test diff --git a/ebean-core/src/test/java/org/tests/query/TestQueryFindEach.java b/ebean-core/src/test/java/org/tests/query/TestQueryFindEach.java index 1a2c16bab..b37f67279 100644 --- a/ebean-core/src/test/java/org/tests/query/TestQueryFindEach.java +++ b/ebean-core/src/test/java/org/tests/query/TestQueryFindEach.java @@ -169,22 +169,40 @@ public class TestQueryFindEach extends BaseTestCase { DB.find(OmBasicParent.class).delete(); insertData(); + test_setLazyLoadBatchSize_withFetchLazy(); + LoggedSqlCollector.start(); - try (final Transaction transaction = DB.beginTransaction()) { - // DB.find(OmBasicParent.class).findList(); - DB.find(OmBasicChild.class) - .setLazyLoadBatchSize(100) - //.fetchQuery("parent","name") - //.fetch("parent","name") - .findEach(child -> { - assertNotNull(child.getParent().getName()); - }); - } + + DB.find(OmBasicChild.class) + .setLazyLoadBatchSize(100) + .findEach(child -> { + assertNotNull(child.getParent().getName()); + }); final List sql = LoggedSqlCollector.stop(); assertThat(sql.size()).isLessThan(50); } + private void test_setLazyLoadBatchSize_withFetchLazy() { + + LoggedSqlCollector.start(); + + DB.find(OmBasicParent.class) + .setLazyLoadBatchSize(5) + .fetchLazy("children") + .setMaxRows(50) + .findEach(it -> { + it.getChildren().size(); + }); + + final List sql = LoggedSqlCollector.stop(); + assertThat(sql).hasSize(11); + assertThat(sql.get(0)).contains(" from om_basic_parent "); + for (int i = 1; i < 11; i++) { + assertThat(sql.get(i)).contains(" --bind(Array[5]"); + } + } + @Transactional(batchSize = 40) private void insertData() { for (int i = 0; i < 150; i++) { From abfa841ed787f332b637b9d7c16081b0bd92783f Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Tue, 23 Mar 2021 23:51:07 +1300 Subject: [PATCH 09/52] #2205 - [oracle] Incorrect DDL generated for alter table add column --- .../ddlgeneration/platform/OracleDdl.java | 1 + .../platform/PlatformDdl_AlterColumnTest.java | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/OracleDdl.java b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/OracleDdl.java index ea7d50d62..740870b09 100644 --- a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/OracleDdl.java +++ b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/OracleDdl.java @@ -15,6 +15,7 @@ public class OracleDdl extends PlatformDdl { this.dropConstraintIfExists = "drop constraint"; this.dropIndexIfExists = "drop index "; this.dropTableCascade = " cascade constraints purge"; + this.addColumn = "add"; this.alterColumn = "modify"; this.columnSetNotnull = "not null"; this.columnSetNull = "null"; diff --git a/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl_AlterColumnTest.java b/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl_AlterColumnTest.java index 3a0a8d727..a696c4e62 100644 --- a/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl_AlterColumnTest.java +++ b/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl_AlterColumnTest.java @@ -9,11 +9,15 @@ import io.ebean.config.dbplatform.mysql.MySqlPlatform; import io.ebean.config.dbplatform.oracle.OraclePlatform; import io.ebean.config.dbplatform.postgres.PostgresPlatform; import io.ebean.config.dbplatform.sqlserver.SqlServer17Platform; +import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite; import io.ebeaninternal.dbmigration.ddlgeneration.PlatformDdlBuilder; import io.ebeaninternal.dbmigration.migration.AlterColumn; import io.ebeaninternal.dbmigration.migration.AlterForeignKey; +import io.ebeaninternal.dbmigration.migration.Column; import org.junit.Test; +import java.io.IOException; + import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; @@ -238,6 +242,22 @@ public class PlatformDdl_AlterColumnTest { assertTrue(exceptionCaught); } + @Test + public void oracle_alterTableAddColumn() throws IOException { + DdlWrite write = new DdlWrite(); + oraDdl.alterTableAddColumn(write.apply(), "my_table", simpleColumn(), false, "1"); + assertThat(write.apply().getBuffer()).isEqualTo("alter table my_table add my_column int default 1 not null;\n"); + } + + private Column simpleColumn() { + Column column = new Column(); + column.setName("my_column"); + column.setType("int"); + column.setNotnull(true); + column.setDefaultValue("1"); + return column; + } + @Test public void useIdentityType_h2() { assertEquals(h2Ddl.useIdentityType(null), IdType.IDENTITY); From f341ff0167cd6838b27039267c05558952d03723 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Tue, 23 Mar 2021 23:58:28 +1300 Subject: [PATCH 10/52] #2205 - [oracle] Incorrect DDL generated for alter table add column --- .../platform/BaseTableDdlTest.java | 2 +- .../dbmigration/migrationtest/oracle/1.1.sql | 28 +++++++++---------- .../dbmigration/migrationtest/oracle/1.3.sql | 10 +++---- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/BaseTableDdlTest.java b/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/BaseTableDdlTest.java index c0bbd4df6..c32d6ad80 100644 --- a/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/BaseTableDdlTest.java +++ b/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/BaseTableDdlTest.java @@ -61,7 +61,7 @@ public class BaseTableDdlTest { ddlGen.alterTableAddColumn(write.apply(), "mytable", column, false, false); String ddl = write.apply().getBuffer(); - assertThat(ddl).contains("alter table mytable add column col_name varchar2(20)"); + assertThat(ddl).contains("alter table mytable add col_name varchar2(20)"); } @Test diff --git a/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/oracle/1.1.sql b/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/oracle/1.1.sql index a7ebf50ef..7e6c98a90 100644 --- a/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/oracle/1.1.sql +++ b/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/oracle/1.1.sql @@ -17,11 +17,11 @@ create table migtest_mtm_m_migtest_mtm_c ( constraint pk_migtest_mtm_m_migtest_mtm_c primary key (migtest_mtm_m_id,migtest_mtm_c_id) ); -alter table migtest_ckey_detail add column one_key number(10); -alter table migtest_ckey_detail add column two_key varchar2(127); +alter table migtest_ckey_detail add one_key number(10); +alter table migtest_ckey_detail add two_key varchar2(127); alter table migtest_ckey_detail add constraint fk_migtest_ckey_detail_parent foreign key (one_key,two_key) references migtest_ckey_parent (one_key,two_key); -alter table migtest_ckey_parent add column assoc_id number(10); +alter table migtest_ckey_parent add assoc_id number(10); alter table migtest_fk_cascade drop constraint fk_migtest_fk_cascade_one_id; alter table migtest_fk_cascade add constraint fk_migtest_fk_cascade_one_id foreign key (one_id) references migtest_fk_cascade_one (id); @@ -46,14 +46,14 @@ alter table migtest_e_basic modify status2 null; insert into migtest_e_user (id) select distinct user_id from migtest_e_basic; alter table migtest_e_basic add constraint fk_migtest_e_basic_user_id foreign key (user_id) references migtest_e_user (id); alter table migtest_e_basic modify user_id null; -alter table migtest_e_basic add column new_string_field varchar2(255) default 'foo''bar' not null; -alter table migtest_e_basic add column new_boolean_field number(1) default 1 not null; +alter table migtest_e_basic add new_string_field varchar2(255) default 'foo''bar' not null; +alter table migtest_e_basic add new_boolean_field number(1) default 1 not null; update migtest_e_basic set new_boolean_field = old_boolean; -alter table migtest_e_basic add column new_boolean_field2 number(1) default 1 not null; -alter table migtest_e_basic add column progress number(10) default 0 not null; +alter table migtest_e_basic add new_boolean_field2 number(1) default 1 not null; +alter table migtest_e_basic add progress number(10) default 0 not null; alter table migtest_e_basic add constraint ck_migtest_e_basic_progress check ( progress in (0,1,2)); -alter table migtest_e_basic add column new_integer number(10) default 42 not null; +alter table migtest_e_basic add new_integer number(10) default 42 not null; alter table migtest_e_basic drop constraint uq_migtest_e_basic_indextest2; alter table migtest_e_basic drop constraint uq_migtest_e_basic_indextest6; @@ -70,12 +70,12 @@ comment on table migtest_e_history is 'We have history now'; update migtest_e_history2 set test_string = 'unknown' where test_string is null; alter table migtest_e_history2 modify test_string default 'unknown'; alter table migtest_e_history2 modify test_string not null; -alter table migtest_e_history2 add column test_string2 varchar2(255); -alter table migtest_e_history2 add column test_string3 varchar2(255) default 'unknown' not null; -alter table migtest_e_history2 add column new_column varchar2(20); +alter table migtest_e_history2 add test_string2 varchar2(255); +alter table migtest_e_history2 add test_string3 varchar2(255) default 'unknown' not null; +alter table migtest_e_history2 add new_column varchar2(20); alter table migtest_e_history4 modify test_number number(19); -alter table migtest_e_history5 add column test_boolean number(1) default 0 not null; +alter table migtest_e_history5 add test_boolean number(1) default 0 not null; -- NOTE: table has @History - special migration may be necessary @@ -83,9 +83,9 @@ update migtest_e_history6 set test_number1 = 42 where test_number1 is null; alter table migtest_e_history6 modify test_number1 default 42; alter table migtest_e_history6 modify test_number1 not null; alter table migtest_e_history6 modify test_number2 null; -alter table migtest_e_softdelete add column deleted number(1) default 0 not null; +alter table migtest_e_softdelete add deleted number(1) default 0 not null; -alter table migtest_oto_child add column master_id number(19); +alter table migtest_oto_child add master_id number(19); create index ix_migtest_e_basic_indextest3 on migtest_e_basic (indextest3); create index ix_migtest_e_basic_indextest6 on migtest_e_basic (indextest6); diff --git a/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/oracle/1.3.sql b/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/oracle/1.3.sql index 47a095e4e..ceafdbcff 100644 --- a/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/oracle/1.3.sql +++ b/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/oracle/1.3.sql @@ -31,9 +31,9 @@ update migtest_e_basic set user_id = 23 where user_id is null; alter table migtest_e_basic drop constraint fk_migtest_e_basic_user_id; alter table migtest_e_basic modify user_id default 23; alter table migtest_e_basic modify user_id not null; -alter table migtest_e_basic add column old_boolean number(1) default 0 not null; -alter table migtest_e_basic add column old_boolean2 number(1); -alter table migtest_e_basic add column eref_id number(10); +alter table migtest_e_basic add old_boolean number(1) default 0 not null; +alter table migtest_e_basic add old_boolean2 number(1); +alter table migtest_e_basic add eref_id number(10); alter table migtest_e_basic drop constraint uq_mgtst__bsc_stts_ndxtst1; alter table migtest_e_basic drop constraint uq_migtest_e_basic_name; @@ -47,8 +47,8 @@ comment on column migtest_e_history.test_string is ''; comment on table migtest_e_history is ''; alter table migtest_e_history2 modify test_string drop default; alter table migtest_e_history2 modify test_string null; -alter table migtest_e_history2 add column obsolete_string1 varchar2(255); -alter table migtest_e_history2 add column obsolete_string2 varchar2(255); +alter table migtest_e_history2 add obsolete_string1 varchar2(255); +alter table migtest_e_history2 add obsolete_string2 varchar2(255); alter table migtest_e_history4 modify test_number number(10); alter table migtest_e_history6 modify test_number1 drop default; From 8992980689d2fe7936acfe4d0fbeadf72bb676a8 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Thu, 25 Mar 2021 16:45:44 +1300 Subject: [PATCH 11/52] #2206 - Postgres DDL generation - for create index use "if not exists" clause --- .../ddlgeneration/platform/PlatformDdl.java | 5 +- .../ddlgeneration/platform/PostgresDdl.java | 1 + .../platform/WriteCreateIndex.java | 13 +++ .../platform/PlatformDdl_CreateIndexTest.java | 98 +++++++++++++++++++ 4 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl_CreateIndexTest.java diff --git a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl.java b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl.java index 648cfac83..59cf38e0d 100644 --- a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl.java +++ b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl.java @@ -3,7 +3,6 @@ package io.ebeaninternal.dbmigration.ddlgeneration.platform; import io.ebean.annotation.ConstraintMode; import io.ebean.config.DatabaseConfig; import io.ebean.config.DbConstraintNaming; -import io.ebean.config.ServerConfig; import io.ebean.config.dbplatform.DatabasePlatform; import io.ebean.config.dbplatform.DbDefaultValue; import io.ebean.config.dbplatform.DbIdentity; @@ -113,6 +112,7 @@ public class PlatformDdl { protected String uniqueIndex = "unique"; protected String indexConcurrent = ""; + protected String createIndexIfNotExists = ""; /** * Set false for MsSqlServer to allow multiple nulls for OneToOne mapping. @@ -414,6 +414,9 @@ public class PlatformDdl { if (create.isConcurrent()) { buffer.append(indexConcurrent); } + if (create.isNotExistsCheck()) { + buffer.append(createIndexIfNotExists); + } buffer.append(maxConstraintName(create.getIndexName())).append(" on ").append(create.getTableName()); appendColumns(create.getColumns(), buffer); return buffer.toString(); diff --git a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PostgresDdl.java b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PostgresDdl.java index daeaf57fb..807bec456 100644 --- a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PostgresDdl.java +++ b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PostgresDdl.java @@ -18,6 +18,7 @@ public class PostgresDdl extends PlatformDdl { this.dropTableCascade = " cascade"; this.columnSetType = "type "; this.alterTableIfExists = "if exists "; + this.createIndexIfNotExists = "if not exists "; this.columnSetNull = "drop not null"; this.addForeignKeySkipCheck = " not valid"; this.indexConcurrent = "concurrently "; diff --git a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/WriteCreateIndex.java b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/WriteCreateIndex.java index c743c979c..fbb7b72ce 100644 --- a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/WriteCreateIndex.java +++ b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/WriteCreateIndex.java @@ -12,7 +12,11 @@ class WriteCreateIndex { private final boolean unique; private final boolean concurrent; private final String definition; + private final boolean notExistsCheck; + /** + * Create index for foreign key. + */ WriteCreateIndex(String indexName, String tableName, String[] columns, boolean unique) { this.indexName = indexName; this.tableName = tableName; @@ -20,8 +24,12 @@ class WriteCreateIndex { this.unique = unique; this.concurrent = false; this.definition = null; + this.notExistsCheck = false; } + /** + * Create non-foreign key index. + */ public WriteCreateIndex(CreateIndex index) { this.indexName = index.getIndexName(); this.tableName = index.getTableName(); @@ -29,6 +37,7 @@ class WriteCreateIndex { this.unique = Boolean.TRUE.equals(index.isUnique()); this.concurrent = Boolean.TRUE.equals(index.isConcurrent()); this.definition = index.getDefinition(); + this.notExistsCheck = true; } public String getIndexName() { @@ -58,4 +67,8 @@ class WriteCreateIndex { public boolean useDefinition() { return definition != null && !definition.isEmpty(); } + + public boolean isNotExistsCheck() { + return notExistsCheck; + } } diff --git a/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl_CreateIndexTest.java b/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl_CreateIndexTest.java new file mode 100644 index 000000000..d7d33feae --- /dev/null +++ b/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl_CreateIndexTest.java @@ -0,0 +1,98 @@ +package io.ebeaninternal.dbmigration.ddlgeneration.platform; + +import io.ebean.DB; +import io.ebean.config.DatabaseConfig; +import io.ebean.config.dbplatform.h2.H2Platform; +import io.ebean.config.dbplatform.hana.HanaPlatform; +import io.ebean.config.dbplatform.mysql.MySqlPlatform; +import io.ebean.config.dbplatform.oracle.OraclePlatform; +import io.ebean.config.dbplatform.postgres.PostgresPlatform; +import io.ebean.config.dbplatform.sqlserver.SqlServer17Platform; +import io.ebeaninternal.dbmigration.ddlgeneration.PlatformDdlBuilder; +import io.ebeaninternal.dbmigration.migration.CreateIndex; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertEquals; + +public class PlatformDdl_CreateIndexTest { + + private final PlatformDdl h2Ddl = PlatformDdlBuilder.create(new H2Platform()); + private final PlatformDdl pgDdl = PlatformDdlBuilder.create(new PostgresPlatform()); + private final PlatformDdl mysqlDdl = PlatformDdlBuilder.create(new MySqlPlatform()); + private final PlatformDdl oraDdl = PlatformDdlBuilder.create(new OraclePlatform()); + private final PlatformDdl sqlServerDdl = PlatformDdlBuilder.create(new SqlServer17Platform()); + private final PlatformDdl hanaDdl = PlatformDdlBuilder.create(new HanaPlatform()); + + { + DatabaseConfig config = DB.getDefault().getPluginApi().getServerConfig(); + h2Ddl.configure(config); + pgDdl.configure(config); + mysqlDdl.configure(config); + oraDdl.configure(config); + sqlServerDdl.configure(config); + hanaDdl.configure(config); + } + + WriteCreateIndex writeCreateIndex() { + + return writeCreateIndex(true, true); + } + + WriteCreateIndex writeCreateIndex(boolean unique, boolean concurrent) { + CreateIndex createIndex = new CreateIndex(); + createIndex.setIndexName("ix_mytab_acol"); + createIndex.setTableName("mytab"); + createIndex.setColumns("acol"); + createIndex.setUnique(unique); + createIndex.setConcurrent(concurrent); + return new WriteCreateIndex(createIndex); + } + + WriteCreateIndex fkeyCreateIndex(boolean unique) { + return new WriteCreateIndex("ix_mytab_acol", "mytab", new String[]{"acol"}, unique); + } + + + @Test + public void createUniqueIndex() { + + WriteCreateIndex createIndex = writeCreateIndex(); + + String sql = h2Ddl.createIndex(createIndex); + assertEquals("create unique index ix_mytab_acol on mytab (acol)", sql); + sql = pgDdl.createIndex(createIndex); + assertEquals("create unique index concurrently if not exists ix_mytab_acol on mytab (acol)", sql); + sql = mysqlDdl.createIndex(createIndex); + assertEquals("create unique index ix_mytab_acol on mytab (acol)", sql); + sql = sqlServerDdl.createIndex(createIndex); + assertEquals("create unique index ix_mytab_acol on mytab (acol)", sql); + sql = oraDdl.createIndex(createIndex); + assertEquals("create unique index ix_mytab_acol on mytab (acol)", sql); + sql = hanaDdl.createIndex(createIndex); + assertThat(sql).isEqualTo("-- explicit index \"ix_mytab_acol\" for single column \"acol\" of table \"mytab\" is not necessary"); + } + + @Test + public void postgres_createIndex() { + + String sql = pgDdl.createIndex(writeCreateIndex(true, true)); + assertEquals("create unique index concurrently if not exists ix_mytab_acol on mytab (acol)", sql); + sql = pgDdl.createIndex(writeCreateIndex(false, false)); + assertEquals("create index if not exists ix_mytab_acol on mytab (acol)", sql); + sql = pgDdl.createIndex(writeCreateIndex(true, false)); + assertEquals("create unique index if not exists ix_mytab_acol on mytab (acol)", sql); + sql = pgDdl.createIndex(writeCreateIndex(false, true)); + assertEquals("create index concurrently if not exists ix_mytab_acol on mytab (acol)", sql); + } + + @Test + public void postgres_fkeyCreateIndex() { + String sql = pgDdl.createIndex(fkeyCreateIndex(true)); + assertEquals("create unique index ix_mytab_acol on mytab (acol)", sql); + + sql = pgDdl.createIndex(fkeyCreateIndex(false)); + assertEquals("create index ix_mytab_acol on mytab (acol)", sql); + } + +} From 57736185d0489b41e4dfdff4898e0ab9f950db2e Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Thu, 25 Mar 2021 23:13:15 +1300 Subject: [PATCH 12/52] #2206 - Postgres DDL generation - for create index use "if not exists" clause --- .../migrationtest/postgres/1.0__initial.sql | 8 ++++---- .../dbmigration/migrationtest/postgres/1.1.sql | 6 +++--- .../dbmigration/migrationtest/postgres/1.3.sql | 10 +++++----- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/postgres/1.0__initial.sql b/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/postgres/1.0__initial.sql index 5229ed032..af08de6d3 100644 --- a/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/postgres/1.0__initial.sql +++ b/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/postgres/1.0__initial.sql @@ -161,11 +161,11 @@ create table migtest_oto_master ( constraint pk_migtest_oto_master primary key (id) ); -create index ix_migtest_e_basic_indextest1 on migtest_e_basic (indextest1); -create index ix_migtest_e_basic_indextest5 on migtest_e_basic (indextest5); +create index if not exists ix_migtest_e_basic_indextest1 on migtest_e_basic (indextest1); +create index if not exists ix_migtest_e_basic_indextest5 on migtest_e_basic (indextest5); create index idxd_migtest_0 on migtest_oto_child using hash (upper(name)) where upper(name) = 'JIM'; -create index concurrently ix_migtest_oto_child_lowername_id on migtest_oto_child (lower(name),id); -create index ix_migtest_oto_child_lowername on migtest_oto_child (lower(name)); +create index concurrently if not exists ix_migtest_oto_child_lowername_id on migtest_oto_child (lower(name),id); +create index if not exists ix_migtest_oto_child_lowername on migtest_oto_child (lower(name)); create index ix_migtest_fk_cascade_one_id on migtest_fk_cascade (one_id); alter table migtest_fk_cascade add constraint fk_migtest_fk_cascade_one_id foreign key (one_id) references migtest_fk_cascade_one (id) on delete cascade on update restrict; diff --git a/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/postgres/1.1.sql b/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/postgres/1.1.sql index 6c97d734e..1c0ef5385 100644 --- a/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/postgres/1.1.sql +++ b/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/postgres/1.1.sql @@ -100,9 +100,9 @@ alter table migtest_e_softdelete add column deleted boolean default false not nu alter table migtest_oto_child add column master_id bigint; -create index ix_migtest_e_basic_indextest3 on migtest_e_basic (indextest3); -create index ix_migtest_e_basic_indextest6 on migtest_e_basic (indextest6); -create index ix_migtest_oto_child_name on migtest_oto_child (name); +create index if not exists ix_migtest_e_basic_indextest3 on migtest_e_basic (indextest3); +create index if not exists ix_migtest_e_basic_indextest6 on migtest_e_basic (indextest6); +create index if not exists ix_migtest_oto_child_name on migtest_oto_child (name); drop index if exists ix_migtest_e_basic_indextest1; drop index if exists ix_migtest_e_basic_indextest5; drop index if exists idxd_migtest_0; diff --git a/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/postgres/1.3.sql b/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/postgres/1.3.sql index a57b95ae2..dbcb50aac 100644 --- a/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/postgres/1.3.sql +++ b/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/postgres/1.3.sql @@ -66,11 +66,11 @@ alter table migtest_e_history6 alter column test_number1 drop not null; update migtest_e_history6 set test_number2 = 7 where test_number2 is null; alter table migtest_e_history6 alter column test_number2 set default 7; alter table migtest_e_history6 alter column test_number2 set not null; -create index ix_migtest_e_basic_indextest1 on migtest_e_basic (indextest1); -create index ix_migtest_e_basic_indextest5 on migtest_e_basic (indextest5); -create index ix_m12_otoc71 on migtest_oto_child (name); -create unique index uq_m12_otoc71 on migtest_oto_child (lower(name)); -create unique index ix_migtest_oto_master_lowername on migtest_oto_master (lower(name)); +create index if not exists ix_migtest_e_basic_indextest1 on migtest_e_basic (indextest1); +create index if not exists ix_migtest_e_basic_indextest5 on migtest_e_basic (indextest5); +create index if not exists ix_m12_otoc71 on migtest_oto_child (name); +create unique index if not exists uq_m12_otoc71 on migtest_oto_child (lower(name)); +create unique index if not exists ix_migtest_oto_master_lowername on migtest_oto_master (lower(name)); drop index if exists ix_migtest_e_basic_indextest3; drop index if exists ix_migtest_e_basic_indextest6; create index ix_migtest_e_basic_eref_id on migtest_e_basic (eref_id); From 91044d0a757c4586e07212b6bdf717f20dcbe3b4 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Thu, 25 Mar 2021 23:13:51 +1300 Subject: [PATCH 13/52] javadoc only - improve javadoc for DatabaseConfig.loadFromProperties() --- ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java b/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java index 8e65f9bb3..49c458743 100644 --- a/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java +++ b/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java @@ -2693,7 +2693,10 @@ public class DatabaseConfig { } /** - * Load settings from ebean.properties. + * Load settings from application.properties, application.yaml and other sources. + *

+ * Uses avaje-config to load configuration properties. Goto https://avaje.io/config + * for detail on how and where properties are loaded from. */ public void loadFromProperties() { this.properties = Config.asProperties(); From 1f0ed629a7a11413cbb81b504df976fc250930f5 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Fri, 26 Mar 2021 20:31:03 +1300 Subject: [PATCH 14/52] Bump java8-oss to 3.1 with removal of --illegal-access=permit argLine --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index dbd383225..297d5ab0a 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.avaje java8-oss - 2.3 + 3.1 io.ebean From 819d391495166faec2b54e60a382e1c35bc11910 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Fri, 26 Mar 2021 20:31:57 +1300 Subject: [PATCH 15/52] Bump agent maven plugin to 12.8.1 --- ebean-bom/pom.xml | 4 ++-- ebean-core/pom.xml | 2 +- ebean-ddl-generator/pom.xml | 3 +-- kotlin-querybean-generator/pom.xml | 2 +- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/ebean-bom/pom.xml b/ebean-bom/pom.xml index e96c248d7..665ea80be 100644 --- a/ebean-bom/pom.xml +++ b/ebean-bom/pom.xml @@ -18,8 +18,8 @@ 12.4.0 4.1 7.0 - 12.6.6 - 12.6.6 + 12.8.1 + 12.8.1 diff --git a/ebean-core/pom.xml b/ebean-core/pom.xml index 9d7f1e236..e8ecd9616 100644 --- a/ebean-core/pom.xml +++ b/ebean-core/pom.xml @@ -302,7 +302,7 @@ io.ebean ebean-maven-plugin - 12.6.6 + 12.8.1 test diff --git a/ebean-ddl-generator/pom.xml b/ebean-ddl-generator/pom.xml index 1ef8c0725..60300f7ce 100644 --- a/ebean-ddl-generator/pom.xml +++ b/ebean-ddl-generator/pom.xml @@ -10,7 +10,6 @@ ebean ddl generation DDL and DB Migration generation ebean-ddl-generator - @@ -77,7 +76,7 @@ io.ebean ebean-maven-plugin - 12.6.6 + 12.8.1 test diff --git a/kotlin-querybean-generator/pom.xml b/kotlin-querybean-generator/pom.xml index cf3dca074..588872181 100644 --- a/kotlin-querybean-generator/pom.xml +++ b/kotlin-querybean-generator/pom.xml @@ -146,7 +146,7 @@ io.ebean ebean-maven-plugin - 12.6.6 + 12.8.1 test From 5cb9b9b2372a4a8349837f6b70a43267fd61ab6d Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Mon, 29 Mar 2021 23:21:07 +1300 Subject: [PATCH 16/52] #2208 - When using fetchCache() with a single id / findOne ... doesn't hit L2 cache Plus #2207 ENH: Query beans add support for nested FetchGroup --- .../io/ebeaninternal/api/CacheIdLookup.java | 47 ++------ .../ebeaninternal/api/CacheIdLookupMany.java | 55 +++++++++ .../api/CacheIdLookupSingle.java | 38 ++++++ .../io/ebeaninternal/api/SpiQueryFetch.java | 5 + .../server/query/DefaultFetchGroupQuery.java | 5 + .../server/querydefn/DefaultOrmQuery.java | 15 ++- .../server/querydefn/OrmQueryProperties.java | 2 +- .../java/io/ebean/typequery/TQAssocBean.java | 32 ++++- .../test/java/org/querytest/QOrderTest.java | 112 ++++++++++++++++++ 9 files changed, 270 insertions(+), 41 deletions(-) create mode 100644 ebean-core/src/main/java/io/ebeaninternal/api/CacheIdLookupMany.java create mode 100644 ebean-core/src/main/java/io/ebeaninternal/api/CacheIdLookupSingle.java diff --git a/ebean-core/src/main/java/io/ebeaninternal/api/CacheIdLookup.java b/ebean-core/src/main/java/io/ebeaninternal/api/CacheIdLookup.java index 0ae791747..cf29cf6d5 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/api/CacheIdLookup.java +++ b/ebean-core/src/main/java/io/ebeaninternal/api/CacheIdLookup.java @@ -1,52 +1,25 @@ package io.ebeaninternal.api; -import io.ebeaninternal.server.expression.IdInExpression; - -import java.util.ArrayList; import java.util.Collection; -import java.util.HashSet; import java.util.List; -import java.util.Set; /** - * Used for bean cache lookup with where ids in expression. + * Process Cache lookup by Id(s). */ -public class CacheIdLookup { - - private final IdInExpression idInExpression; - - private int remaining; - - public CacheIdLookup(IdInExpression idInExpression) { - this.idInExpression = idInExpression; - } +public interface CacheIdLookup { /** - * Return the Id values for the in expression. + * Return the Id values to lookup against the L2 cache. */ - public Collection idValues() { - return idInExpression.idValues(); - } + Collection idValues(); /** - * Process the hits returning the beans fetched from cache and - * adjusting the in expression (to not fetch the hits). + * Remove the hits returning the beans fetched from L2 cache. */ - public List removeHits(BeanCacheResult cacheResult) { + List removeHits(BeanCacheResult cacheResult); - Set hitIds = new HashSet<>(); - List beans = new ArrayList<>(hitIds.size()); - - for (BeanCacheResult.Entry hit : cacheResult.hits()) { - hitIds.add(hit.getKey()); - beans.add(hit.getBean()); - } - - this.remaining = idInExpression.removeIds(hitIds); - return beans; - } - - public boolean allHits() { - return remaining == 0; - } + /** + * Return true if all beans where found in L2 cache. + */ + boolean allHits(); } diff --git a/ebean-core/src/main/java/io/ebeaninternal/api/CacheIdLookupMany.java b/ebean-core/src/main/java/io/ebeaninternal/api/CacheIdLookupMany.java new file mode 100644 index 000000000..bfe9d5b84 --- /dev/null +++ b/ebean-core/src/main/java/io/ebeaninternal/api/CacheIdLookupMany.java @@ -0,0 +1,55 @@ +package io.ebeaninternal.api; + +import io.ebeaninternal.server.expression.IdInExpression; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * Used for bean cache lookup with where ids in expression. + */ +public class CacheIdLookupMany implements CacheIdLookup { + + private final IdInExpression idInExpression; + + private int remaining; + + public CacheIdLookupMany(IdInExpression idInExpression) { + this.idInExpression = idInExpression; + } + + /** + * Return the Id values for the in expression. + */ + @Override + public Collection idValues() { + return idInExpression.idValues(); + } + + /** + * Process the hits returning the beans fetched from cache and + * adjusting the in expression (to not fetch the hits). + */ + @Override + public List removeHits(BeanCacheResult cacheResult) { + + Set hitIds = new HashSet<>(); + List beans = new ArrayList<>(hitIds.size()); + + for (BeanCacheResult.Entry hit : cacheResult.hits()) { + hitIds.add(hit.getKey()); + beans.add(hit.getBean()); + } + + this.remaining = idInExpression.removeIds(hitIds); + return beans; + } + + @Override + public boolean allHits() { + return remaining == 0; + } +} diff --git a/ebean-core/src/main/java/io/ebeaninternal/api/CacheIdLookupSingle.java b/ebean-core/src/main/java/io/ebeaninternal/api/CacheIdLookupSingle.java new file mode 100644 index 000000000..47ee89c4b --- /dev/null +++ b/ebean-core/src/main/java/io/ebeaninternal/api/CacheIdLookupSingle.java @@ -0,0 +1,38 @@ +package io.ebeaninternal.api; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +/** + * Used for bean cache lookup with a single id value. + */ +public class CacheIdLookupSingle implements CacheIdLookup { + + private final Object idValue; + private boolean found; + + public CacheIdLookupSingle(Object idValue) { + this.idValue = idValue; + } + + @Override + public Collection idValues() { + return Collections.singleton(idValue); + } + + @Override + public List removeHits(BeanCacheResult cacheResult) { + final List> hits = cacheResult.hits(); + if (hits.size() == 1) { + found = true; + return Collections.singletonList(hits.get(0).getBean()); + } + return Collections.emptyList(); + } + + @Override + public boolean allHits() { + return found; + } +} diff --git a/ebean-core/src/main/java/io/ebeaninternal/api/SpiQueryFetch.java b/ebean-core/src/main/java/io/ebeaninternal/api/SpiQueryFetch.java index 396827978..716dbc076 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/api/SpiQueryFetch.java +++ b/ebean-core/src/main/java/io/ebeaninternal/api/SpiQueryFetch.java @@ -1,6 +1,7 @@ package io.ebeaninternal.api; import io.ebean.FetchConfig; +import io.ebeaninternal.server.querydefn.OrmQueryDetail; import java.util.Set; @@ -19,4 +20,8 @@ public interface SpiQueryFetch { */ void fetchProperties(String name, Set properties, FetchConfig config); + /** + * Add a nested fetch graph. + */ + void addNested(String name, OrmQueryDetail nestedDetail, FetchConfig config); } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/DefaultFetchGroupQuery.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/DefaultFetchGroupQuery.java index 5b2ed841a..9f7cb9b7e 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/DefaultFetchGroupQuery.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/DefaultFetchGroupQuery.java @@ -644,4 +644,9 @@ class DefaultFetchGroupQuery implements SpiFetchGroupQuery, SpiQueryFetch public void fetchProperties(String property, Set columns, FetchConfig config) { detail.fetchProperties(property, columns, config); } + + @Override + public void addNested(String name, OrmQueryDetail nestedDetail, FetchConfig config) { + detail.addNested(name, nestedDetail, config); + } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java index 074f364bc..867e16dfa 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java @@ -35,6 +35,8 @@ import io.ebean.plugin.BeanType; import io.ebeaninternal.api.BindParams; import io.ebeaninternal.api.CQueryPlanKey; import io.ebeaninternal.api.CacheIdLookup; +import io.ebeaninternal.api.CacheIdLookupMany; +import io.ebeaninternal.api.CacheIdLookupSingle; import io.ebeaninternal.api.HashQuery; import io.ebeaninternal.api.ManyWhereJoins; import io.ebeaninternal.api.NaturalKeyQueryData; @@ -740,10 +742,14 @@ public class DefaultOrmQuery implements SpiQuery { return null; } List underlyingList = whereExpressions.getUnderlyingList(); - if (underlyingList.size() == 1) { + if (underlyingList.isEmpty()) { + if (id != null) { + return new CacheIdLookupSingle<>(id); + } + } else if (underlyingList.size() == 1) { SpiExpression singleExpression = underlyingList.get(0); if (singleExpression instanceof IdInExpression) { - return new CacheIdLookup<>((IdInExpression) singleExpression); + return new CacheIdLookupMany<>((IdInExpression) singleExpression); } } return null; @@ -1412,6 +1418,11 @@ public class DefaultOrmQuery implements SpiQuery { detail.fetchProperties(path, other); } + @Override + public void addNested(String name, OrmQueryDetail nestedDetail, FetchConfig config) { + detail.addNested(name, nestedDetail, config); + } + @Override public Query select(String columns) { detail.select(columns); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryProperties.java b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryProperties.java index d1a3aeafc..466bb3eb9 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryProperties.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryProperties.java @@ -120,8 +120,8 @@ public class OrmQueryProperties implements Serializable { this.parentPath = SplitName.parent(path); this.allProperties = other.allProperties; this.included = other.included; - this.cache = other.cache; this.fetchConfig = fetchConfig; + this.cache = fetchConfig.isCache(); } /** diff --git a/ebean-querybean/src/main/java/io/ebean/typequery/TQAssocBean.java b/ebean-querybean/src/main/java/io/ebean/typequery/TQAssocBean.java index c54862151..d5843a612 100644 --- a/ebean-querybean/src/main/java/io/ebean/typequery/TQAssocBean.java +++ b/ebean-querybean/src/main/java/io/ebean/typequery/TQAssocBean.java @@ -2,7 +2,10 @@ package io.ebean.typequery; import io.ebean.ExpressionList; import io.ebean.FetchConfig; +import io.ebean.FetchGroup; import io.ebeaninternal.api.SpiQueryFetch; +import io.ebeaninternal.server.querydefn.OrmQueryDetail; +import io.ebeaninternal.server.querydefn.SpiFetchGroup; import java.util.LinkedHashSet; import java.util.Set; @@ -142,7 +145,34 @@ public abstract class TQAssocBean extends TQProperty { return _root; } - private final SpiQueryFetch spiQuery() { + /** + * Fetch using the nested FetchGroup. + */ + public R fetch(FetchGroup nestedGroup) { + return fetchNested(nestedGroup, FETCH_DEFAULT); + } + + /** + * Fetch query using the nested FetchGroup. + */ + public R fetchQuery(FetchGroup nestedGroup) { + return fetchNested(nestedGroup, FETCH_QUERY); + } + + /** + * Fetch cache using the nested FetchGroup. + */ + public R fetchCache(FetchGroup nestedGroup) { + return fetchNested(nestedGroup, FETCH_CACHE); + } + + private R fetchNested(FetchGroup nestedGroup, FetchConfig fetchConfig) { + OrmQueryDetail nestedDetail = ((SpiFetchGroup) nestedGroup).underlying(); + spiQuery().addNested(_name, nestedDetail, fetchConfig); + return _root; + } + + private SpiQueryFetch spiQuery() { return (SpiQueryFetch)((TQRootBean) _root).query(); } diff --git a/ebean-querybean/src/test/java/org/querytest/QOrderTest.java b/ebean-querybean/src/test/java/org/querytest/QOrderTest.java index 2f470fdb5..db899549c 100644 --- a/ebean-querybean/src/test/java/org/querytest/QOrderTest.java +++ b/ebean-querybean/src/test/java/org/querytest/QOrderTest.java @@ -3,9 +3,13 @@ package org.querytest; import io.ebean.DB; import io.ebean.FetchGroup; import io.ebean.test.LoggedSql; +import org.example.domain.Customer; import org.example.domain.Order; +import org.example.domain.otherpackage.PhoneNumber; import org.example.domain.query.QCustomer; import org.example.domain.query.QOrder; +import org.junit.AfterClass; +import org.junit.BeforeClass; import org.junit.Test; import java.util.List; @@ -18,6 +22,26 @@ public class QOrderTest { private static final QOrder or = QOrder.alias(); + private static final FetchGroup fgC = QCustomer.forFetchGroup() + .select(cu.name, cu.phoneNumber) + .buildFetchGroup(); + + private static final FetchGroup fgNested1 = QOrder.forFetchGroup() + .select(or.status, or.shipDate) + .customer.fetch(fgC) + .buildFetchGroup(); + + private static final FetchGroup fgNested_fetchQuery = QOrder.forFetchGroup() + .select(or.status) + .customer.fetchQuery(fgC) + .buildFetchGroup(); + + private static final FetchGroup fgNested_fetchCache = QOrder.forFetchGroup() + .select(or.status) + .customer.fetchCache(fgC) + .buildFetchGroup(); + + private static final FetchGroup fg = QOrder.forFetchGroup() .select(or.status, or.shipDate) .customer.fetchCache(cu.name, cu.status, cu.registered, cu.comments) @@ -28,6 +52,20 @@ public class QOrderTest { .customer.fetch(cu.name) .buildFetchGroup(); + private static Order order; + private static Customer customer; + + @BeforeClass + public static void before() { + setupData(); + } + + @AfterClass + public static void after() { + DB.delete(order); + DB.delete(customer); + } + @Test public void fetchCache() { @@ -76,6 +114,69 @@ public class QOrderTest { assertThat(sql.get(0)).contains("select t0.id, t0.status, t1.id, t1.name from o_order t0 join be_customer t1 on t1.id = t0.customer_id where"); } + @Test + public void viaFetchGraph_withNested() { + + DB.getDefault(); + LoggedSql.start(); + + new QOrder() + .status.eq(Order.Status.NEW) + .select(fgNested1) + .findList(); + + final List sql = LoggedSql.stop(); + assertThat(sql).hasSize(1); + assertThat(sql.get(0)).contains("select t0.id, t0.status, t0.ship_date, t1.id, t1.name, t1.phone_number from o_order t0 join be_customer t1 on t1.id = t0.customer_id where"); + } + + @Test + public void viaFetchGraph_withNested_fetchQuery() { + + DB.getDefault(); + LoggedSql.start(); + + final Order found = new QOrder() + .id.eq(order.getId()) + .select(fgNested_fetchQuery) + .findOne(); + + final List sql = LoggedSql.stop(); + + // assert fetching customer via fetchQuery + assertThat(sql).hasSize(2); + assertThat(sql.get(0)).contains("select t0.id, t0.status, t0.customer_id from o_order t0 where t0.id = ?"); + assertThat(sql.get(1)).contains("select t0.id, t0.name, t0.phone_number from be_customer t0 where t0.id = ?"); + + assertThat(found.getCustomer().getPhoneNumber().getMsisdn()).isEqualTo("Ph1"); + } + + + @Test + public void viaFetchGraph_withNested_fetchCache() { + + DB.getDefault(); + + // ensure the customer is loaded in the L2 cache + new QCustomer().id.eq(customer.getId()).findOne(); + + LoggedSql.start(); + + final Order found = new QOrder() + .id.eq(order.getId()) + .select(fgNested_fetchCache) // cache hit for customer + .findOne(); + + final String msisdn = found.getCustomer().getPhoneNumber().getMsisdn(); + assertThat(msisdn).isEqualTo("Ph1"); + + final List sql = LoggedSql.stop(); + + // assert we only hit DB for order + assertThat(sql).hasSize(1); + assertThat(sql.get(0)).contains("select t0.id, t0.status, t0.customer_id from o_order t0 where t0.id = ?"); + } + @Test public void select_partial() { @@ -113,4 +214,15 @@ public class QOrderTest { } + private static void setupData() { + + customer = new Customer(); + customer.setName("Fred"); + customer.setPhoneNumber(new PhoneNumber("Ph1")); + customer.save(); + + order = new Order(); + order.setCustomer(customer); + order.save(); + } } From d988dbe69def32b5bdb3f185e9470df8bab3047a Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Tue, 30 Mar 2021 09:56:48 +1300 Subject: [PATCH 17/52] #2209 - Registering [default] as the default server but [default] is already registered as the default exception with hot-reload --- ebean-api/src/main/java/io/ebean/DatabaseFactory.java | 2 +- ebean-core/src/test/java/org/MainMemoryLeak.java | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ebean-api/src/main/java/io/ebean/DatabaseFactory.java b/ebean-api/src/main/java/io/ebean/DatabaseFactory.java index 6ad7b1d89..4aace866a 100644 --- a/ebean-api/src/main/java/io/ebean/DatabaseFactory.java +++ b/ebean-api/src/main/java/io/ebean/DatabaseFactory.java @@ -78,7 +78,7 @@ public class DatabaseFactory { Database server = createInternal(config); if (config.isRegister()) { if (config.isDefaultServer()) { - if (defaultServerName != null) { + if (defaultServerName != null && !defaultServerName.equals(config.getName())) { throw new IllegalStateException("Registering [" + config.getName() + "] as the default server but [" + defaultServerName + "] is already registered as the default"); } defaultServerName = config.getName(); diff --git a/ebean-core/src/test/java/org/MainMemoryLeak.java b/ebean-core/src/test/java/org/MainMemoryLeak.java index d3f085ef3..b659297b4 100644 --- a/ebean-core/src/test/java/org/MainMemoryLeak.java +++ b/ebean-core/src/test/java/org/MainMemoryLeak.java @@ -46,7 +46,12 @@ public class MainMemoryLeak { config.addClass(ECachedBean.class); config.loadFromProperties(); + Database server1 = DatabaseFactory.create(config); + assert server1 != null; + + // create again for #2193 Database server = DatabaseFactory.create(config); + assert server != null; // create a string with 10k chars char[] c = new char[10_000]; From f8c37772d4bc518c89a3ff26d3cc00ea7905466c Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Tue, 30 Mar 2021 10:23:28 +1300 Subject: [PATCH 18/52] Tidy internals of DefaultServer with @Nonnull, <>, Collections.singleton(), remove unused queryBatchSize --- .../server/core/DefaultServer.java | 39 +++++++++++-------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultServer.java b/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultServer.java index 34a094301..5e8db9c1c 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultServer.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultServer.java @@ -125,6 +125,7 @@ import io.ebeanservice.docstore.api.DocStoreIntegration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.annotation.Nonnull; import javax.persistence.NonUniqueResultException; import javax.persistence.OptimisticLockException; import javax.persistence.PersistenceException; @@ -137,7 +138,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; @@ -196,7 +196,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { private final SpiLogManager logManager; private final PersistenceContextScope defaultPersistenceContextScope; private final int lazyLoadBatchSize; - private final int queryBatchSize; private final boolean updateAllPropertiesInBatch; private final long slowQueryMicros; private final SlowQueryListener slowQueryListener; @@ -217,7 +216,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { this.extraMetrics = config.getExtraMetrics(); this.serverName = this.config.getName(); this.lazyLoadBatchSize = this.config.getLazyLoadBatchSize(); - this.queryBatchSize = this.config.getQueryBatchSize(); this.cqueryEngine = config.getCQueryEngine(); this.expressionFactory = config.getExpressionFactory(); this.encryptKeyManager = this.config.getEncryptKeyManager(); @@ -305,10 +303,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { return lazyLoadBatchSize; } - public int getQueryBatchSize() { - return queryBatchSize; - } - @Override public Object currentTenantId() { return currentTenantProvider == null ? null : currentTenantProvider.currentId(); @@ -1150,6 +1144,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { } } + @Nonnull @Override public Optional findOneOrEmpty(Query query, Transaction transaction) { return Optional.ofNullable(findOne(query, transaction)); @@ -1180,6 +1175,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { } } + @Nonnull @Override @SuppressWarnings({"unchecked", "rawtypes"}) public Set findSet(Query query, Transaction t) { @@ -1196,6 +1192,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { } } + @Nonnull @Override @SuppressWarnings({"unchecked", "rawtypes"}) public Map findMap(Query query, Transaction t) { @@ -1217,6 +1214,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { } } + @Nonnull @Override @SuppressWarnings("unchecked") public List findSingleAttributeList(Query query, Transaction t) { @@ -1227,7 +1225,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { } try { request.initTransIfRequired(); - return (List) request.findSingleAttributeList(); + return request.findSingleAttributeList(); } finally { request.endTransIfRequired(); } @@ -1277,6 +1275,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { } } + @Nonnull @Override public List findIds(Query query, Transaction t) { return findIdsWithCopy(((SpiQuery) query).copy(), t); @@ -1337,26 +1336,29 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { } } + @Nonnull @Override public FutureRowCount findFutureCount(Query q, Transaction t) { SpiQuery copy = ((SpiQuery) q).copy(); copy.setFutureFetch(true); Transaction newTxn = createTransaction(); - QueryFutureRowCount queryFuture = new QueryFutureRowCount<>(new CallableQueryCount(this, copy, newTxn)); + QueryFutureRowCount queryFuture = new QueryFutureRowCount<>(new CallableQueryCount<>(this, copy, newTxn)); backgroundExecutor.execute(queryFuture.getFutureTask()); return queryFuture; } + @Nonnull @Override public FutureIds findFutureIds(Query query, Transaction t) { SpiQuery copy = ((SpiQuery) query).copy(); copy.setFutureFetch(true); Transaction newTxn = createTransaction(); - QueryFutureIds queryFuture = new QueryFutureIds<>(new CallableQueryIds(this, copy, newTxn)); + QueryFutureIds queryFuture = new QueryFutureIds<>(new CallableQueryIds<>(this, copy, newTxn)); backgroundExecutor.execute(queryFuture.getFutureTask()); return queryFuture; } + @Nonnull @Override public FutureList findFutureList(Query query, Transaction t) { SpiQuery spiQuery = (SpiQuery) query; @@ -1369,11 +1371,12 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { } // Create a new transaction solely to execute the findList() at some future time Transaction newTxn = createTransaction(); - QueryFutureList queryFuture = new QueryFutureList<>(new CallableQueryList(this, spiQuery, newTxn)); + QueryFutureList queryFuture = new QueryFutureList<>(new CallableQueryList<>(this, spiQuery, newTxn)); backgroundExecutor.execute(queryFuture.getFutureTask()); return queryFuture; } + @Nonnull @Override public PagedList findPagedList(Query query, Transaction transaction) { SpiQuery spiQuery = (SpiQuery) query; @@ -1387,6 +1390,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { return new LimitOffsetPagedList<>(this, spiQuery); } + @Nonnull @Override public QueryIterator findIterate(Query query, Transaction t) { SpiOrmQueryRequest request = createQueryRequest(Type.ITERATE, query, t); @@ -1399,11 +1403,13 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { } } + @Nonnull @Override public Stream findLargeStream(Query query, Transaction transaction) { return findStream(query, transaction); } + @Nonnull @Override public Stream findStream(Query query, Transaction transaction) { SpiOrmQueryRequest request = createQueryRequest(Type.ITERATE, query, transaction); @@ -1470,6 +1476,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { // no try finally - findEachWhile guarantee's cleanup of the transaction if required } + @Nonnull @Override public List> findVersions(Query query, Transaction transaction) { SpiOrmQueryRequest request = createQueryRequest(Type.LIST, query, transaction); @@ -1481,6 +1488,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { } } + @Nonnull @Override public List findList(Query query, Transaction t) { return findList(query, t, false); @@ -1540,6 +1548,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { } } + @Nonnull @Override public List findList(SqlQuery query, Transaction t) { RelationalQueryRequest request = new RelationalQueryRequest(this, relationalQueryEngine, query, t); @@ -2241,6 +2250,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { return checkUniqueness(bean, null); } + @Nonnull @Override public Set checkUniqueness(Object bean, Transaction transaction) { EntityBean entityBean = checkEntityBean(bean); @@ -2252,14 +2262,11 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { } Object id = idProperty.getVal(entityBean); if (entityBean._ebean_getIntercept().isNew() && id != null) { - // Primary Key is changeable only on new models - so skip check if we are not - // new. + // Primary Key is changeable only on new models - so skip check if we are not new Query query = new DefaultOrmQuery<>(beanDesc, this, expressionFactory); query.setId(id); if (findCount(query, transaction) > 0) { - Set ret = new HashSet<>(); - ret.add(idProperty); - return ret; + return Collections.singleton(idProperty); } } for (BeanProperty[] props : beanDesc.getUniqueProps()) { From 2a5fd7f3a993909cf9a2a8c53a3b8d302a71d582 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Tue, 30 Mar 2021 16:02:27 +1300 Subject: [PATCH 19/52] #2210 - Improve query plan capture - ability to change default threshold micros --- .../java/io/ebean/meta/QueryPlanRequest.java | 7 +++++- .../api/NoopQueryPlanManager.java | 5 ++++ .../ebeaninternal/api/QueryPlanManager.java | 5 ++++ .../server/core/DefaultServer.java | 3 +++ .../server/query/CQueryPlanManager.java | 9 +++++-- .../query/finder/TestCustomerFinder.java | 24 +++++++++++++++---- 6 files changed, 46 insertions(+), 7 deletions(-) diff --git a/ebean-api/src/main/java/io/ebean/meta/QueryPlanRequest.java b/ebean-api/src/main/java/io/ebean/meta/QueryPlanRequest.java index 3510b30cc..c4a69b1aa 100644 --- a/ebean-api/src/main/java/io/ebean/meta/QueryPlanRequest.java +++ b/ebean-api/src/main/java/io/ebean/meta/QueryPlanRequest.java @@ -41,6 +41,9 @@ public class QueryPlanRequest { /** * Set the maximum number of plans to capture. + *

+ * Use this to limit how much query plan capturing is done as query + * plan capture is actual database load. */ public void setMaxCount(int maxCount) { this.maxCount = maxCount; @@ -58,7 +61,9 @@ public class QueryPlanRequest { /** * Set the maximum amount of time we want to use to capture plans. *

- * Query plan collection will stop once this time is exceeded. + * Query plan collection will stop once this time is exceeded. We use + * this to ensure the query plan capture does not use excessive amount + * of time - put too much load on the database. */ public void setMaxTimeMillis(long maxTimeMillis) { this.maxTimeMillis = maxTimeMillis; diff --git a/ebean-core/src/main/java/io/ebeaninternal/api/NoopQueryPlanManager.java b/ebean-core/src/main/java/io/ebeaninternal/api/NoopQueryPlanManager.java index e00ad57f1..813121f92 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/api/NoopQueryPlanManager.java +++ b/ebean-core/src/main/java/io/ebeaninternal/api/NoopQueryPlanManager.java @@ -8,6 +8,11 @@ import java.util.List; class NoopQueryPlanManager implements QueryPlanManager { + @Override + public void setDefaultThreshold(long thresholdMicros) { + // do nothing + } + @Override public SpiQueryBindCapture createBindCapture(SpiQueryPlan queryPlan) { return SpiQueryBindCapture.NOOP; diff --git a/ebean-core/src/main/java/io/ebeaninternal/api/QueryPlanManager.java b/ebean-core/src/main/java/io/ebeaninternal/api/QueryPlanManager.java index f9750c47a..da7ce2b43 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/api/QueryPlanManager.java +++ b/ebean-core/src/main/java/io/ebeaninternal/api/QueryPlanManager.java @@ -12,6 +12,11 @@ public interface QueryPlanManager { QueryPlanManager NOOP = new NoopQueryPlanManager(); + /** + * Update the global default threshold used when new query plans are created. + */ + void setDefaultThreshold(long thresholdMicros); + /** * Create the bind capture for the given query plan. */ diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultServer.java b/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultServer.java index 5e8db9c1c..0e4d22768 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultServer.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultServer.java @@ -2329,6 +2329,9 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { } List queryPlanInit(QueryPlanInit initRequest) { + if (initRequest.isAll()) { + queryPlanManager.setDefaultThreshold(initRequest.getThresholdMicros()); + } return beanDescriptorManager.queryPlanInit(initRequest); } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryPlanManager.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryPlanManager.java index c2e6aa358..4ff62f44d 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryPlanManager.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryPlanManager.java @@ -30,14 +30,14 @@ public class CQueryPlanManager implements QueryPlanManager { private final TransactionManager transactionManager; - private final long defaultThreshold; - private final QueryPlanLogger planLogger; private final TimedMetric timeCollection; private final TimedMetric timeBindCapture; + private long defaultThreshold; + public CQueryPlanManager(TransactionManager transactionManager, long defaultThreshold, QueryPlanLogger planLogger, ExtraMetrics extraMetrics) { this.transactionManager = transactionManager; this.defaultThreshold = defaultThreshold; @@ -46,6 +46,11 @@ public class CQueryPlanManager implements QueryPlanManager { this.timeBindCapture = extraMetrics.getBindCapture(); } + @Override + public void setDefaultThreshold(long thresholdMicros) { + this.defaultThreshold = thresholdMicros; + } + @Override public SpiQueryBindCapture createBindCapture(SpiQueryPlan queryPlan) { return new CQueryBindCapture(this, queryPlan, defaultThreshold); diff --git a/ebean-core/src/test/java/org/tests/query/finder/TestCustomerFinder.java b/ebean-core/src/test/java/org/tests/query/finder/TestCustomerFinder.java index 48cc264c6..8446f9d5b 100644 --- a/ebean-core/src/test/java/org/tests/query/finder/TestCustomerFinder.java +++ b/ebean-core/src/test/java/org/tests/query/finder/TestCustomerFinder.java @@ -175,17 +175,24 @@ public class TestCustomerFinder extends BaseTestCase { ResetBasicData.reset(); + // change default collect query plan threshold to 200 micros + QueryPlanInit init0 = new QueryPlanInit(); + init0.setAll(true); + init0.setThresholdMicros(200); + final List plans = server().getMetaInfoManager().queryPlanInit(init0); + assertThat(plans.size()).isGreaterThan(1); + // the server has some plans runQueries(); - // enable query plan bind capture on all plans threshold 100 micros + // change query plan threshold to 100 micros QueryPlanInit init = new QueryPlanInit(); init.setAll(true); init.setThresholdMicros(100); final List appliedToPlans = server().getMetaInfoManager().queryPlanInit(init); assertThat(appliedToPlans.size()).isGreaterThan(4); - // will collect bind captures + // run queries again runQueries(); ServerMetrics metrics = server().getMetaInfoManager().collectMetrics(); @@ -203,12 +210,21 @@ public class TestCustomerFinder extends BaseTestCase { // obtains db query plans ... QueryPlanRequest request = new QueryPlanRequest(); - List plans = server().getMetaInfoManager().queryPlanCollectNow(request); - assertThat(plans).isNotEmpty(); + // collect max 1000 plans (use something more like 10) + request.setMaxCount(1_000); + // don't collect any more plans if used 10 secs + request.setMaxTimeMillis(10_000); + List plans0 = server().getMetaInfoManager().queryPlanCollectNow(request); + assertThat(plans0).isNotEmpty(); for (MetaQueryPlan plan : plans) { + logger.info("queryplan label:{}, queryTimeMicros:{} loc:{} sql:{} bind:{} plan:{}", + plan.getLabel(), plan.getQueryTimeMicros(), plan.getProfileLocation(), + plan.getSql(), plan.getBind(), plan.getPlan()); System.out.println(plan); } + + //DB.getBackgroundExecutor().scheduleWithFixedDelay(...) } @Test From bcfd9cab1db0a5b81b9e71b2c07adc9bdfa2ed52 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Tue, 30 Mar 2021 16:05:42 +1300 Subject: [PATCH 20/52] #2210 - Improve query plan capture - bump threshold multiplier to 1.5 --- .../java/io/ebeaninternal/server/query/CQueryBindCapture.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryBindCapture.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryBindCapture.java index 713169640..e3a1a5e54 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryBindCapture.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryBindCapture.java @@ -9,7 +9,7 @@ import java.util.concurrent.locks.ReentrantLock; class CQueryBindCapture implements SpiQueryBindCapture { - private static final double multiplier = 1.3d; + private static final double multiplier = 1.5d; private final ReentrantLock lock = new ReentrantLock(); private final CQueryPlanManager manager; From ee8bb5ef751ccbc9cd9b1d6fdd0b561ec8e781a7 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Tue, 30 Mar 2021 23:19:21 +1300 Subject: [PATCH 21/52] #2211 - Improve query plan capture - Add default mechanism to log captured query plans --- .../java/io/ebean/config/DatabaseConfig.java | 94 ++++++++++++++++++- .../io/ebean/config/QueryPlanCapture.java | 34 +++++++ .../io/ebean/config/QueryPlanListener.java | 13 +++ .../server/core/DefaultQueryPlanListener.java | 25 +++++ .../server/core/DefaultServer.java | 33 +++++-- .../io/ebean/config/ServerConfigTest.java | 15 +++ 6 files changed, 206 insertions(+), 8 deletions(-) create mode 100644 ebean-api/src/main/java/io/ebean/config/QueryPlanCapture.java create mode 100644 ebean-api/src/main/java/io/ebean/config/QueryPlanListener.java create mode 100644 ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultQueryPlanListener.java diff --git a/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java b/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java index 49c458743..1cbfa9d3e 100644 --- a/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java +++ b/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java @@ -498,7 +498,7 @@ public class DatabaseConfig { private boolean notifyL2CacheInForeground; /** - * Set to true to support query plan capture. + * Set to true to enable bind capture required for query plan capture. */ private boolean collectQueryPlans; @@ -507,6 +507,15 @@ public class DatabaseConfig { */ private long collectQueryPlanThresholdMicros = Long.MAX_VALUE; + /** + * Set to true to enable automatic query plan capture. + */ + private boolean queryPlanCapture; + private long queryPlanCapturePeriodSecs = 60 * 10; // 10 minutes + private long queryPlanCaptureMaxTimeMillis = 10_000; // 10 seconds + private int queryPlanCaptureMaxCount = 10; + private QueryPlanListener queryPlanListener; + /** * The time in millis used to determine when a query is alerted for being slow. */ @@ -1045,7 +1054,6 @@ public class DatabaseConfig { * This is a performance optimisation to reduce the number times Ebean * requests a sequence to be used as an Id for a bean (aka reduce network * chatter). - */ public void setDatabaseSequenceBatchSize(int databaseSequenceBatchSize) { platformConfig.setDatabaseSequenceBatchSize(databaseSequenceBatchSize); @@ -2807,6 +2815,10 @@ public class DatabaseConfig { slowQueryMillis = p.getLong("slowQueryMillis", slowQueryMillis); collectQueryPlans = p.getBoolean("collectQueryPlans", collectQueryPlans); collectQueryPlanThresholdMicros = p.getLong("collectQueryPlanThresholdMicros", collectQueryPlanThresholdMicros); + queryPlanCapture = p.getBoolean("queryPlan.capture", queryPlanCapture); + queryPlanCapturePeriodSecs = p.getLong("queryPlan.capturePeriodSecs", queryPlanCapturePeriodSecs); + queryPlanCaptureMaxTimeMillis = p.getLong("queryPlan.captureMaxTimeMillis", queryPlanCaptureMaxTimeMillis); + queryPlanCaptureMaxCount = p.getInt("queryPlan.captureMaxCount", queryPlanCaptureMaxCount); docStoreOnly = p.getBoolean("docStoreOnly", docStoreOnly); disableL2Cache = p.getBoolean("disableL2Cache", disableL2Cache); localOnlyL2Cache = p.getBoolean("localOnlyL2Cache", localOnlyL2Cache); @@ -3201,6 +3213,84 @@ public class DatabaseConfig { this.collectQueryPlanThresholdMicros = collectQueryPlanThresholdMicros; } + /** + * Return true if periodic capture of query plans is enabled. + */ + public boolean isQueryPlanCapture() { + return queryPlanCapture; + } + + /** + * Set to true to turn on periodic capture of query plans. + */ + public void setQueryPlanCapture(boolean queryPlanCapture) { + this.queryPlanCapture = queryPlanCapture; + } + + /** + * Return the frequency to capture query plans. + */ + public long getQueryPlanCapturePeriodSecs() { + return queryPlanCapturePeriodSecs; + } + + /** + * Set the frequency in seconds to capture query plans. + */ + public void setQueryPlanCapturePeriodSecs(long queryPlanCapturePeriodSecs) { + this.queryPlanCapturePeriodSecs = queryPlanCapturePeriodSecs; + } + + /** + * Return the time after which a capture query plans request will + * stop capturing more query plans. + *

+ * Effectively this controls the amount of load/time we want to + * allow for query plan capture. + */ + public long getQueryPlanCaptureMaxTimeMillis() { + return queryPlanCaptureMaxTimeMillis; + } + + /** + * Set the time after which a capture query plans request will + * stop capturing more query plans. + *

+ * Effectively this controls the amount of load/time we want to + * allow for query plan capture. + */ + public void setQueryPlanCaptureMaxTimeMillis(long queryPlanCaptureMaxTimeMillis) { + this.queryPlanCaptureMaxTimeMillis = queryPlanCaptureMaxTimeMillis; + } + + /** + * Return the max number of query plans captured per request. + */ + public int getQueryPlanCaptureMaxCount() { + return queryPlanCaptureMaxCount; + } + + /** + * Set the max number of query plans captured per request. + */ + public void setQueryPlanCaptureMaxCount(int queryPlanCaptureMaxCount) { + this.queryPlanCaptureMaxCount = queryPlanCaptureMaxCount; + } + + /** + * Return the listener used to process captured query plans. + */ + public QueryPlanListener getQueryPlanListener() { + return queryPlanListener; + } + + /** + * Set the listener used to process captured query plans. + */ + public void setQueryPlanListener(QueryPlanListener queryPlanListener) { + this.queryPlanListener = queryPlanListener; + } + /** * Return true if metrics should be dumped when the server is shutdown. */ diff --git a/ebean-api/src/main/java/io/ebean/config/QueryPlanCapture.java b/ebean-api/src/main/java/io/ebean/config/QueryPlanCapture.java new file mode 100644 index 000000000..6f34097fe --- /dev/null +++ b/ebean-api/src/main/java/io/ebean/config/QueryPlanCapture.java @@ -0,0 +1,34 @@ +package io.ebean.config; + +import io.ebean.Database; +import io.ebean.meta.MetaQueryPlan; + +import java.util.List; + +/** + * The captured query plans. + */ +public class QueryPlanCapture { + + private final Database database; + private final List plans; + + public QueryPlanCapture(Database database, List plans) { + this.database = database; + this.plans = plans; + } + + /** + * Return the database the plans were captured for. + */ + public Database getDatabase() { + return database; + } + + /** + * Return the captured query plans. + */ + public List getPlans() { + return plans; + } +} diff --git a/ebean-api/src/main/java/io/ebean/config/QueryPlanListener.java b/ebean-api/src/main/java/io/ebean/config/QueryPlanListener.java new file mode 100644 index 000000000..8368186cf --- /dev/null +++ b/ebean-api/src/main/java/io/ebean/config/QueryPlanListener.java @@ -0,0 +1,13 @@ +package io.ebean.config; + +/** + * EXPERIMENTAL: Listener for captured query plans. + */ +@FunctionalInterface +public interface QueryPlanListener { + + /** + * Process the captured query plans. + */ + void process(QueryPlanCapture capture); +} diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultQueryPlanListener.java b/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultQueryPlanListener.java new file mode 100644 index 000000000..051d331ba --- /dev/null +++ b/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultQueryPlanListener.java @@ -0,0 +1,25 @@ +package io.ebeaninternal.server.core; + +import io.ebean.config.QueryPlanCapture; +import io.ebean.config.QueryPlanListener; +import io.ebean.meta.MetaQueryPlan; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +class DefaultQueryPlanListener implements QueryPlanListener { + + static final QueryPlanListener INSTANT = new DefaultQueryPlanListener(); + + private static final Logger log = LoggerFactory.getLogger("io.ebean.QUERYPLAN"); + + @Override + public void process(QueryPlanCapture capture) { + // better to log this in JSON form? + String dbName = capture.getDatabase().getName(); + for (MetaQueryPlan plan : capture.getPlans()) { + log.info("queryPlan db:{} label:{} queryTimeMicros:{} loc:{} sql:{} bind:{} plan:{}", + dbName, plan.getLabel(), plan.getQueryTimeMicros(), plan.getProfileLocation(), + plan.getSql(), plan.getBind(), plan.getPlan()); + } + } +} diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultServer.java b/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultServer.java index 0e4d22768..52b94bfb6 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultServer.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultServer.java @@ -45,12 +45,7 @@ import io.ebean.bean.PersistenceContext.WithOption; import io.ebean.bean.SingleBeanLoader; import io.ebean.cache.ServerCacheManager; import io.ebean.common.CopyOnFirstWriteList; -import io.ebean.config.CurrentTenantProvider; -import io.ebean.config.DatabaseConfig; -import io.ebean.config.EncryptKeyManager; -import io.ebean.config.SlowQueryEvent; -import io.ebean.config.SlowQueryListener; -import io.ebean.config.TenantMode; +import io.ebean.config.*; import io.ebean.config.dbplatform.DatabasePlatform; import io.ebean.event.BeanPersistController; import io.ebean.event.ShutdownManager; @@ -145,6 +140,7 @@ import java.util.Optional; import java.util.Set; import java.util.Spliterator; import java.util.concurrent.Callable; +import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; import java.util.function.Consumer; import java.util.function.Function; @@ -404,6 +400,31 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { migrationRunner.loadProperties(config.getProperties()); migrationRunner.run(config.getDataSource()); } + startQueryPlanCapture(); + } + + private void startQueryPlanCapture() { + if (config.isQueryPlanCapture()) { + long secs = config.getQueryPlanCapturePeriodSecs(); + if (secs > 10) { + logger.info("capture query plan enabled, every {}secs", secs); + backgroundExecutor.scheduleWithFixedDelay(this::collectQueryPlans, secs, secs, TimeUnit.SECONDS); + } + } + } + + private void collectQueryPlans() { + QueryPlanRequest request = new QueryPlanRequest(); + request.setMaxCount(config.getQueryPlanCaptureMaxCount()); + request.setMaxTimeMillis(config.getQueryPlanCaptureMaxTimeMillis()); + + // obtains query explain plans ... + List plans = metaInfoManager.queryPlanCollectNow(request); + QueryPlanListener listener = config.getQueryPlanListener(); + if (listener == null) { + listener = DefaultQueryPlanListener.INSTANT; + } + listener.process(new QueryPlanCapture(this, plans)); } @Override diff --git a/ebean-core/src/test/java/io/ebean/config/ServerConfigTest.java b/ebean-core/src/test/java/io/ebean/config/ServerConfigTest.java index 8fda93985..b23ccdbb6 100644 --- a/ebean-core/src/test/java/io/ebean/config/ServerConfigTest.java +++ b/ebean-core/src/test/java/io/ebean/config/ServerConfigTest.java @@ -76,6 +76,11 @@ public class ServerConfigTest { props.setProperty("forUpdateNoKey", "true"); props.setProperty("defaultServer", "false"); + props.setProperty("queryPlan.capture", "true"); + props.setProperty("queryPlan.capturePeriodSecs", "42"); + props.setProperty("queryPlan.captureMaxTimeMillis", "560"); + props.setProperty("queryPlan.captureMaxCount", "7"); + serverConfig.loadFromProperties(props); assertFalse(serverConfig.isDefaultServer()); @@ -106,6 +111,11 @@ public class ServerConfigTest { assertEquals(4, serverConfig.getBackgroundExecutorSchedulePoolSize()); assertEquals(98, serverConfig.getBackgroundExecutorShutdownSecs()); + assertTrue(serverConfig.isQueryPlanCapture()); + assertEquals(42, serverConfig.getQueryPlanCapturePeriodSecs()); + assertEquals(560, serverConfig.getQueryPlanCaptureMaxTimeMillis()); + assertEquals(7, serverConfig.getQueryPlanCaptureMaxCount()); + assertThat(serverConfig.getMappingLocations()).containsExactly("classpath:/foo","bar"); serverConfig.setPersistBatch(PersistBatch.NONE); @@ -146,6 +156,11 @@ public class ServerConfigTest { assertTrue(serverConfig.isAutoLoadModuleInfo()); assertEquals(Long.MAX_VALUE, serverConfig.getCollectQueryPlanThresholdMicros()); + assertFalse(serverConfig.isQueryPlanCapture()); + assertEquals(600, serverConfig.getQueryPlanCapturePeriodSecs()); + assertEquals(10000L, serverConfig.getQueryPlanCaptureMaxTimeMillis()); + assertEquals(10, serverConfig.getQueryPlanCaptureMaxCount()); + serverConfig.setLoadModuleInfo(false); assertFalse(serverConfig.isAutoLoadModuleInfo()); } From a8bf27da550e9438e8195c3162c91ed840c5cfc1 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Tue, 30 Mar 2021 23:44:30 +1300 Subject: [PATCH 22/52] #2211 - Improve query plan capture - Align config property names collectQueryPlans -> queryPlanEnable collectQueryPlanThresholdMicros -> queryPlanThresholdMicros properties keys: ebean.collectQueryPlans -> ebean.queryPlan.enable ebean.collectQueryPlanThresholdMicros -> ebean.queryPlan.thresholdMicros This then aligns all the queryPlan related properties together which is important in order to avoid confusion. --- .../java/io/ebean/config/DatabaseConfig.java | 29 ++++++++++--------- .../server/core/InternalConfiguration.java | 4 +-- .../io/ebean/config/ServerConfigTest.java | 9 ++++-- .../src/test/resources/ebean.properties | 4 +-- 4 files changed, 26 insertions(+), 20 deletions(-) diff --git a/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java b/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java index 1cbfa9d3e..c4195f0be 100644 --- a/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java +++ b/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java @@ -500,15 +500,15 @@ public class DatabaseConfig { /** * Set to true to enable bind capture required for query plan capture. */ - private boolean collectQueryPlans; + private boolean queryPlanEnable; /** * The default threshold in micros for collecting query plans. */ - private long collectQueryPlanThresholdMicros = Long.MAX_VALUE; + private long queryPlanThresholdMicros = Long.MAX_VALUE; /** - * Set to true to enable automatic query plan capture. + * Set to true to enable automatic periodic query plan capture. */ private boolean queryPlanCapture; private long queryPlanCapturePeriodSecs = 60 * 10; // 10 minutes @@ -2813,8 +2813,8 @@ public class DatabaseConfig { dumpMetricsOptions = p.get("dumpMetricsOptions", dumpMetricsOptions); queryPlanTTLSeconds = p.getInt("queryPlanTTLSeconds", queryPlanTTLSeconds); slowQueryMillis = p.getLong("slowQueryMillis", slowQueryMillis); - collectQueryPlans = p.getBoolean("collectQueryPlans", collectQueryPlans); - collectQueryPlanThresholdMicros = p.getLong("collectQueryPlanThresholdMicros", collectQueryPlanThresholdMicros); + queryPlanEnable = p.getBoolean("queryPlan.enable", queryPlanEnable); + queryPlanThresholdMicros = p.getLong("queryPlan.thresholdMicros", queryPlanThresholdMicros); queryPlanCapture = p.getBoolean("queryPlan.capture", queryPlanCapture); queryPlanCapturePeriodSecs = p.getLong("queryPlan.capturePeriodSecs", queryPlanCapturePeriodSecs); queryPlanCaptureMaxTimeMillis = p.getLong("queryPlan.captureMaxTimeMillis", queryPlanCaptureMaxTimeMillis); @@ -3188,29 +3188,32 @@ public class DatabaseConfig { /** * Return true if query plan capture is enabled. */ - public boolean isCollectQueryPlans() { - return collectQueryPlans; + public boolean isQueryPlanEnable() { + return queryPlanEnable; } /** * Set to true to enable query plan capture. */ - public void setCollectQueryPlans(boolean collectQueryPlans) { - this.collectQueryPlans = collectQueryPlans; + public void setQueryPlanEnable(boolean queryPlanEnable) { + this.queryPlanEnable = queryPlanEnable; } /** * Return the query plan collection threshold in microseconds. */ - public long getCollectQueryPlanThresholdMicros() { - return collectQueryPlanThresholdMicros; + public long getQueryPlanThresholdMicros() { + return queryPlanThresholdMicros; } /** * Set the query plan collection threshold in microseconds. + *

+ * Queries executing slower than this will have bind values captured such that later + * the query plan can be captured and reported. */ - public void setCollectQueryPlanThresholdMicros(long collectQueryPlanThresholdMicros) { - this.collectQueryPlanThresholdMicros = collectQueryPlanThresholdMicros; + public void setQueryPlanThresholdMicros(long queryPlanThresholdMicros) { + this.queryPlanThresholdMicros = queryPlanThresholdMicros; } /** diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java b/ebean-core/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java index 56ea7589a..8cbbbfa4b 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java @@ -617,10 +617,10 @@ public class InternalConfiguration { } public QueryPlanManager initQueryPlanManager(TransactionManager transactionManager) { - if (!config.isCollectQueryPlans()) { + if (!config.isQueryPlanEnable()) { return QueryPlanManager.NOOP; } - long threshold = config.getCollectQueryPlanThresholdMicros(); + long threshold = config.getQueryPlanThresholdMicros(); return new CQueryPlanManager(transactionManager, threshold, queryPlanLogger(databasePlatform.getPlatform()), extraMetrics); } diff --git a/ebean-core/src/test/java/io/ebean/config/ServerConfigTest.java b/ebean-core/src/test/java/io/ebean/config/ServerConfigTest.java index b23ccdbb6..f93c18d26 100644 --- a/ebean-core/src/test/java/io/ebean/config/ServerConfigTest.java +++ b/ebean-core/src/test/java/io/ebean/config/ServerConfigTest.java @@ -72,10 +72,11 @@ public class ServerConfigTest { props.setProperty("enabledL2Regions", "r0,users,orgs"); props.setProperty("caseSensitiveCollation", "false"); props.setProperty("loadModuleInfo", "true"); - props.setProperty("collectQueryPlanThresholdMicros", "10000"); props.setProperty("forUpdateNoKey", "true"); props.setProperty("defaultServer", "false"); + props.setProperty("queryPlan.enable", "true"); + props.setProperty("queryPlan.thresholdMicros", "10000"); props.setProperty("queryPlan.capture", "true"); props.setProperty("queryPlan.capturePeriodSecs", "42"); props.setProperty("queryPlan.captureMaxTimeMillis", "560"); @@ -102,7 +103,6 @@ public class ServerConfigTest { assertEquals(PlatformConfig.DbUuid.BINARY, serverConfig.getPlatformConfig().getDbUuid()); assertEquals(JsonConfig.DateTime.MILLIS, serverConfig.getJsonDateTime()); assertEquals(JsonConfig.Date.MILLIS, serverConfig.getJsonDate()); - assertEquals(10000, serverConfig.getCollectQueryPlanThresholdMicros()); assertEquals("r0,users,orgs", serverConfig.getEnabledL2Regions()); @@ -111,6 +111,8 @@ public class ServerConfigTest { assertEquals(4, serverConfig.getBackgroundExecutorSchedulePoolSize()); assertEquals(98, serverConfig.getBackgroundExecutorShutdownSecs()); + assertTrue(serverConfig.isQueryPlanEnable()); + assertEquals(10000, serverConfig.getQueryPlanThresholdMicros()); assertTrue(serverConfig.isQueryPlanCapture()); assertEquals(42, serverConfig.getQueryPlanCapturePeriodSecs()); assertEquals(560, serverConfig.getQueryPlanCaptureMaxTimeMillis()); @@ -154,8 +156,9 @@ public class ServerConfigTest { assertEquals(JsonConfig.Date.ISO8601, serverConfig.getJsonDate()); assertTrue(serverConfig.getPlatformConfig().isCaseSensitiveCollation()); assertTrue(serverConfig.isAutoLoadModuleInfo()); - assertEquals(Long.MAX_VALUE, serverConfig.getCollectQueryPlanThresholdMicros()); + assertFalse(serverConfig.isQueryPlanEnable()); + assertEquals(Long.MAX_VALUE, serverConfig.getQueryPlanThresholdMicros()); assertFalse(serverConfig.isQueryPlanCapture()); assertEquals(600, serverConfig.getQueryPlanCapturePeriodSecs()); assertEquals(10000L, serverConfig.getQueryPlanCaptureMaxTimeMillis()); diff --git a/ebean-core/src/test/resources/ebean.properties b/ebean-core/src/test/resources/ebean.properties index 953d2c720..aa1210739 100644 --- a/ebean-core/src/test/resources/ebean.properties +++ b/ebean-core/src/test/resources/ebean.properties @@ -27,8 +27,8 @@ datasource.default=h2 ebean.dumpMetricsOnShutdown=true ebean.dumpMetricsOptions=sql,hash -#ebean.collectQueryPlanThresholdMicros=1000 -ebean.collectQueryPlans=true +#ebean.queryPlan.thresholdMicros=1000 +ebean.queryPlan.enable=true ebean.autoReadOnlyDataSource=true #datasource.h2-ro.url=jdbc:h2:mem:tests From 1bf09ddd38c39f7814815ae88ee1072e994101a3 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Tue, 30 Mar 2021 23:49:44 +1300 Subject: [PATCH 23/52] #2211 - Improve javadoc for queryPlanTTLSeconds Hopefully people understand it is unrelated. Unfortunately we now have some properties with similar names so maybe we need a better name for this sometime in the future. --- .../src/main/java/io/ebean/config/DatabaseConfig.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java b/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java index c4195f0be..bf4c61675 100644 --- a/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java +++ b/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java @@ -3108,14 +3108,17 @@ public class DatabaseConfig { } /** - * Return the query plan time to live. + * Return the time to live for ebean's internal query plan. */ public int getQueryPlanTTLSeconds() { return queryPlanTTLSeconds; } /** - * Set the query plan time to live. + * Set the time to live for ebean's internal query plan. + *

+ * This is the plan that knows how to execute the query, read the result + * and collects execution metrics. By default this is set to 5 mins. */ public void setQueryPlanTTLSeconds(int queryPlanTTLSeconds) { this.queryPlanTTLSeconds = queryPlanTTLSeconds; From f7035eb2289c035c2f762166118c76c01a056051 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Wed, 31 Mar 2021 00:06:04 +1300 Subject: [PATCH 24/52] [maven-release-plugin] prepare release ebean-parent-12.8.1 --- ebean-api/pom.xml | 2 +- ebean-autotune/pom.xml | 6 +++--- ebean-bom/pom.xml | 30 +++++++++++++++--------------- ebean-core-type/pom.xml | 4 ++-- ebean-core/pom.xml | 10 +++++----- ebean-ddl-generator/pom.xml | 6 +++--- ebean-externalmapping-api/pom.xml | 2 +- ebean-externalmapping-xml/pom.xml | 10 +++++----- ebean-postgis/pom.xml | 6 +++--- ebean-querybean/pom.xml | 10 +++++----- ebean-redis/pom.xml | 12 ++++++------ ebean-test/pom.xml | 6 +++--- ebean/pom.xml | 8 ++++---- kotlin-querybean-generator/pom.xml | 8 ++++---- pom.xml | 4 ++-- querybean-generator/pom.xml | 2 +- 16 files changed, 63 insertions(+), 63 deletions(-) diff --git a/ebean-api/pom.xml b/ebean-api/pom.xml index ce3ba3688..d24999338 100644 --- a/ebean-api/pom.xml +++ b/ebean-api/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.1-SNAPSHOT + 12.8.1 ebean api diff --git a/ebean-autotune/pom.xml b/ebean-autotune/pom.xml index 5c081a9df..5897d06d5 100644 --- a/ebean-autotune/pom.xml +++ b/ebean-autotune/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.1-SNAPSHOT + 12.8.1 @@ -14,7 +14,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-parent-12.8.0 + ebean-parent-12.8.1 ebean autotune @@ -26,7 +26,7 @@ io.ebean ebean-core - 12.8.1-SNAPSHOT + 12.8.1 provided diff --git a/ebean-bom/pom.xml b/ebean-bom/pom.xml index 665ea80be..e30fff780 100644 --- a/ebean-bom/pom.xml +++ b/ebean-bom/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.1-SNAPSHOT + 12.8.1 ebean bom @@ -81,88 +81,88 @@ io.ebean ebean - 12.8.1-SNAPSHOT + 12.8.1 io.ebean ebean-api - 12.8.1-SNAPSHOT + 12.8.1 io.ebean ebean-core - 12.8.1-SNAPSHOT + 12.8.1 io.ebean ebean-core-type - 12.8.1-SNAPSHOT + 12.8.1 io.ebean ebean-ddl-generator - 12.8.1-SNAPSHOT + 12.8.1 io.ebean ebean-externalmapping-api - 12.8.1-SNAPSHOT + 12.8.1 io.ebean ebean-externalmapping-xml - 12.8.1-SNAPSHOT + 12.8.1 io.ebean ebean-autotune - 12.8.1-SNAPSHOT + 12.8.1 io.ebean ebean-querybean - 12.8.1-SNAPSHOT + 12.8.1 io.ebean querybean-generator - 12.8.1-SNAPSHOT + 12.8.1 provided io.ebean kotlin-querybean-generator - 12.8.1-SNAPSHOT + 12.8.1 provided io.ebean ebean-test - 12.8.1-SNAPSHOT + 12.8.1 test io.ebean ebean-postgis - 12.8.1-SNAPSHOT + 12.8.1 io.ebean ebean-redis - 12.8.1-SNAPSHOT + 12.8.1 diff --git a/ebean-core-type/pom.xml b/ebean-core-type/pom.xml index 386d6d511..0e5b3aa23 100644 --- a/ebean-core-type/pom.xml +++ b/ebean-core-type/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.1-SNAPSHOT + 12.8.1 ebean-core-type @@ -16,7 +16,7 @@ io.ebean ebean-api - 12.8.1-SNAPSHOT + 12.8.1 diff --git a/ebean-core/pom.xml b/ebean-core/pom.xml index e8ecd9616..da160656c 100644 --- a/ebean-core/pom.xml +++ b/ebean-core/pom.xml @@ -3,7 +3,7 @@ ebean-parent io.ebean - 12.8.1-SNAPSHOT + 12.8.1 ebean-core @@ -15,7 +15,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-parent-12.8.0 + ebean-parent-12.8.1 @@ -87,19 +87,19 @@ io.ebean ebean-api - 12.8.1-SNAPSHOT + 12.8.1 io.ebean ebean-core-type - 12.8.1-SNAPSHOT + 12.8.1 io.ebean ebean-externalmapping-api - 12.8.1-SNAPSHOT + 12.8.1 diff --git a/ebean-ddl-generator/pom.xml b/ebean-ddl-generator/pom.xml index 60300f7ce..7f2ea1c76 100644 --- a/ebean-ddl-generator/pom.xml +++ b/ebean-ddl-generator/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.1-SNAPSHOT + 12.8.1 ebean ddl generation @@ -28,14 +28,14 @@ io.ebean ebean-core-type - 12.8.1-SNAPSHOT + 12.8.1 provided io.ebean ebean-core - 12.8.1-SNAPSHOT + 12.8.1 provided diff --git a/ebean-externalmapping-api/pom.xml b/ebean-externalmapping-api/pom.xml index 4efce3a65..92440b9d6 100644 --- a/ebean-externalmapping-api/pom.xml +++ b/ebean-externalmapping-api/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.1-SNAPSHOT + 12.8.1 ebean external mapping api diff --git a/ebean-externalmapping-xml/pom.xml b/ebean-externalmapping-xml/pom.xml index cd885187e..68f5d50a4 100644 --- a/ebean-externalmapping-xml/pom.xml +++ b/ebean-externalmapping-xml/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.1-SNAPSHOT + 12.8.1 @@ -14,7 +14,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-parent-12.8.0 + ebean-parent-12.8.1 ebean external mapping xml @@ -33,7 +33,7 @@ io.ebean ebean-externalmapping-api - 12.8.1-SNAPSHOT + 12.8.1 @@ -59,14 +59,14 @@ io.ebean ebean-core - 12.8.1-SNAPSHOT + 12.8.1 test io.ebean ebean-ddl-generator - 12.8.1-SNAPSHOT + 12.8.1 test diff --git a/ebean-postgis/pom.xml b/ebean-postgis/pom.xml index 5b4bceec8..dd4967ee3 100644 --- a/ebean-postgis/pom.xml +++ b/ebean-postgis/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.1-SNAPSHOT + 12.8.1 ebean postgis @@ -23,7 +23,7 @@ io.ebean ebean-core - 12.8.1-SNAPSHOT + 12.8.1 provided @@ -74,7 +74,7 @@ io.ebean ebean-test - 12.8.1-SNAPSHOT + 12.8.1 test diff --git a/ebean-querybean/pom.xml b/ebean-querybean/pom.xml index 51f490b3b..8edf552ca 100644 --- a/ebean-querybean/pom.xml +++ b/ebean-querybean/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.1-SNAPSHOT + 12.8.1 ebean querybean @@ -17,7 +17,7 @@ io.ebean ebean-core - 12.8.1-SNAPSHOT + 12.8.1 provided @@ -57,21 +57,21 @@ io.ebean ebean-ddl-generator - 12.8.1-SNAPSHOT + 12.8.1 test io.ebean querybean-generator - 12.8.1-SNAPSHOT + 12.8.1 test io.ebean ebean-test - 12.8.1-SNAPSHOT + 12.8.1 test diff --git a/ebean-redis/pom.xml b/ebean-redis/pom.xml index 2a346b178..c258c4074 100644 --- a/ebean-redis/pom.xml +++ b/ebean-redis/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.1-SNAPSHOT + 12.8.1 ebean-redis @@ -22,35 +22,35 @@ io.ebean ebean-api - 12.8.1-SNAPSHOT + 12.8.1 provided io.ebean ebean-core - 12.8.1-SNAPSHOT + 12.8.1 provided io.ebean ebean-querybean - 12.8.1-SNAPSHOT + 12.8.1 test io.ebean querybean-generator - 12.8.1-SNAPSHOT + 12.8.1 test io.ebean ebean-test - 12.8.1-SNAPSHOT + 12.8.1 test diff --git a/ebean-test/pom.xml b/ebean-test/pom.xml index c32dab0c2..bccddf421 100644 --- a/ebean-test/pom.xml +++ b/ebean-test/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.1-SNAPSHOT + 12.8.1 ebean test @@ -29,14 +29,14 @@ io.ebean ebean-core - 12.8.1-SNAPSHOT + 12.8.1 provided io.ebean ebean-ddl-generator - 12.8.1-SNAPSHOT + 12.8.1 diff --git a/ebean/pom.xml b/ebean/pom.xml index 33c8aeb60..f8204d0cf 100644 --- a/ebean/pom.xml +++ b/ebean/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.1-SNAPSHOT + 12.8.1 ebean composite @@ -22,20 +22,20 @@ io.ebean ebean-api - 12.8.1-SNAPSHOT + 12.8.1 io.ebean ebean-core - 12.8.1-SNAPSHOT + 12.8.1 io.ebean ebean-querybean - 12.8.1-SNAPSHOT + 12.8.1 diff --git a/kotlin-querybean-generator/pom.xml b/kotlin-querybean-generator/pom.xml index 588872181..a9dda9dc6 100644 --- a/kotlin-querybean-generator/pom.xml +++ b/kotlin-querybean-generator/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.1-SNAPSHOT + 12.8.1 kotlin querybean generator @@ -29,7 +29,7 @@ io.ebean ebean-querybean - 12.8.1-SNAPSHOT + 12.8.1 test @@ -43,7 +43,7 @@ io.ebean ebean-core - 12.8.1-SNAPSHOT + 12.8.1 test @@ -64,7 +64,7 @@ io.ebean ebean-ddl-generator - 12.8.1-SNAPSHOT + 12.8.1 test diff --git a/pom.xml b/pom.xml index 297d5ab0a..4064eef48 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean-parent - 12.8.1-SNAPSHOT + 12.8.1 pom ebean parent @@ -18,7 +18,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-parent-12.8.0 + ebean-parent-12.8.1 diff --git a/querybean-generator/pom.xml b/querybean-generator/pom.xml index 6e7bf295f..7da5e03b1 100644 --- a/querybean-generator/pom.xml +++ b/querybean-generator/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.1-SNAPSHOT + 12.8.1 querybean generator From 09d772a5e53ab99c8a0148a1704fbd1312928618 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Wed, 31 Mar 2021 00:06:13 +1300 Subject: [PATCH 25/52] [maven-release-plugin] prepare for next development iteration --- ebean-api/pom.xml | 2 +- ebean-autotune/pom.xml | 6 +++--- ebean-bom/pom.xml | 30 +++++++++++++++--------------- ebean-core-type/pom.xml | 4 ++-- ebean-core/pom.xml | 10 +++++----- ebean-ddl-generator/pom.xml | 6 +++--- ebean-externalmapping-api/pom.xml | 2 +- ebean-externalmapping-xml/pom.xml | 10 +++++----- ebean-postgis/pom.xml | 6 +++--- ebean-querybean/pom.xml | 10 +++++----- ebean-redis/pom.xml | 12 ++++++------ ebean-test/pom.xml | 6 +++--- ebean/pom.xml | 8 ++++---- kotlin-querybean-generator/pom.xml | 8 ++++---- pom.xml | 4 ++-- querybean-generator/pom.xml | 2 +- 16 files changed, 63 insertions(+), 63 deletions(-) diff --git a/ebean-api/pom.xml b/ebean-api/pom.xml index d24999338..4fe1468ec 100644 --- a/ebean-api/pom.xml +++ b/ebean-api/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.1 + 12.8.2-SNAPSHOT ebean api diff --git a/ebean-autotune/pom.xml b/ebean-autotune/pom.xml index 5897d06d5..700861dd9 100644 --- a/ebean-autotune/pom.xml +++ b/ebean-autotune/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.1 + 12.8.2-SNAPSHOT @@ -14,7 +14,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-parent-12.8.1 + ebean-parent-12.8.0 ebean autotune @@ -26,7 +26,7 @@ io.ebean ebean-core - 12.8.1 + 12.8.2-SNAPSHOT provided diff --git a/ebean-bom/pom.xml b/ebean-bom/pom.xml index e30fff780..401f6dbdf 100644 --- a/ebean-bom/pom.xml +++ b/ebean-bom/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.1 + 12.8.2-SNAPSHOT ebean bom @@ -81,88 +81,88 @@ io.ebean ebean - 12.8.1 + 12.8.2-SNAPSHOT io.ebean ebean-api - 12.8.1 + 12.8.2-SNAPSHOT io.ebean ebean-core - 12.8.1 + 12.8.2-SNAPSHOT io.ebean ebean-core-type - 12.8.1 + 12.8.2-SNAPSHOT io.ebean ebean-ddl-generator - 12.8.1 + 12.8.2-SNAPSHOT io.ebean ebean-externalmapping-api - 12.8.1 + 12.8.2-SNAPSHOT io.ebean ebean-externalmapping-xml - 12.8.1 + 12.8.2-SNAPSHOT io.ebean ebean-autotune - 12.8.1 + 12.8.2-SNAPSHOT io.ebean ebean-querybean - 12.8.1 + 12.8.2-SNAPSHOT io.ebean querybean-generator - 12.8.1 + 12.8.2-SNAPSHOT provided io.ebean kotlin-querybean-generator - 12.8.1 + 12.8.2-SNAPSHOT provided io.ebean ebean-test - 12.8.1 + 12.8.2-SNAPSHOT test io.ebean ebean-postgis - 12.8.1 + 12.8.2-SNAPSHOT io.ebean ebean-redis - 12.8.1 + 12.8.2-SNAPSHOT diff --git a/ebean-core-type/pom.xml b/ebean-core-type/pom.xml index 0e5b3aa23..be8b15507 100644 --- a/ebean-core-type/pom.xml +++ b/ebean-core-type/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.1 + 12.8.2-SNAPSHOT ebean-core-type @@ -16,7 +16,7 @@ io.ebean ebean-api - 12.8.1 + 12.8.2-SNAPSHOT diff --git a/ebean-core/pom.xml b/ebean-core/pom.xml index da160656c..3652ba9a3 100644 --- a/ebean-core/pom.xml +++ b/ebean-core/pom.xml @@ -3,7 +3,7 @@ ebean-parent io.ebean - 12.8.1 + 12.8.2-SNAPSHOT ebean-core @@ -15,7 +15,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-parent-12.8.1 + ebean-parent-12.8.0 @@ -87,19 +87,19 @@ io.ebean ebean-api - 12.8.1 + 12.8.2-SNAPSHOT io.ebean ebean-core-type - 12.8.1 + 12.8.2-SNAPSHOT io.ebean ebean-externalmapping-api - 12.8.1 + 12.8.2-SNAPSHOT diff --git a/ebean-ddl-generator/pom.xml b/ebean-ddl-generator/pom.xml index 7f2ea1c76..421166e46 100644 --- a/ebean-ddl-generator/pom.xml +++ b/ebean-ddl-generator/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.1 + 12.8.2-SNAPSHOT ebean ddl generation @@ -28,14 +28,14 @@ io.ebean ebean-core-type - 12.8.1 + 12.8.2-SNAPSHOT provided io.ebean ebean-core - 12.8.1 + 12.8.2-SNAPSHOT provided diff --git a/ebean-externalmapping-api/pom.xml b/ebean-externalmapping-api/pom.xml index 92440b9d6..32a98a767 100644 --- a/ebean-externalmapping-api/pom.xml +++ b/ebean-externalmapping-api/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.1 + 12.8.2-SNAPSHOT ebean external mapping api diff --git a/ebean-externalmapping-xml/pom.xml b/ebean-externalmapping-xml/pom.xml index 68f5d50a4..029f345fc 100644 --- a/ebean-externalmapping-xml/pom.xml +++ b/ebean-externalmapping-xml/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.1 + 12.8.2-SNAPSHOT @@ -14,7 +14,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-parent-12.8.1 + ebean-parent-12.8.0 ebean external mapping xml @@ -33,7 +33,7 @@ io.ebean ebean-externalmapping-api - 12.8.1 + 12.8.2-SNAPSHOT @@ -59,14 +59,14 @@ io.ebean ebean-core - 12.8.1 + 12.8.2-SNAPSHOT test io.ebean ebean-ddl-generator - 12.8.1 + 12.8.2-SNAPSHOT test diff --git a/ebean-postgis/pom.xml b/ebean-postgis/pom.xml index dd4967ee3..6528624f3 100644 --- a/ebean-postgis/pom.xml +++ b/ebean-postgis/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.1 + 12.8.2-SNAPSHOT ebean postgis @@ -23,7 +23,7 @@ io.ebean ebean-core - 12.8.1 + 12.8.2-SNAPSHOT provided @@ -74,7 +74,7 @@ io.ebean ebean-test - 12.8.1 + 12.8.2-SNAPSHOT test diff --git a/ebean-querybean/pom.xml b/ebean-querybean/pom.xml index 8edf552ca..86d02f68a 100644 --- a/ebean-querybean/pom.xml +++ b/ebean-querybean/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.1 + 12.8.2-SNAPSHOT ebean querybean @@ -17,7 +17,7 @@ io.ebean ebean-core - 12.8.1 + 12.8.2-SNAPSHOT provided @@ -57,21 +57,21 @@ io.ebean ebean-ddl-generator - 12.8.1 + 12.8.2-SNAPSHOT test io.ebean querybean-generator - 12.8.1 + 12.8.2-SNAPSHOT test io.ebean ebean-test - 12.8.1 + 12.8.2-SNAPSHOT test diff --git a/ebean-redis/pom.xml b/ebean-redis/pom.xml index c258c4074..1d3a74a49 100644 --- a/ebean-redis/pom.xml +++ b/ebean-redis/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.1 + 12.8.2-SNAPSHOT ebean-redis @@ -22,35 +22,35 @@ io.ebean ebean-api - 12.8.1 + 12.8.2-SNAPSHOT provided io.ebean ebean-core - 12.8.1 + 12.8.2-SNAPSHOT provided io.ebean ebean-querybean - 12.8.1 + 12.8.2-SNAPSHOT test io.ebean querybean-generator - 12.8.1 + 12.8.2-SNAPSHOT test io.ebean ebean-test - 12.8.1 + 12.8.2-SNAPSHOT test diff --git a/ebean-test/pom.xml b/ebean-test/pom.xml index bccddf421..65e0d345c 100644 --- a/ebean-test/pom.xml +++ b/ebean-test/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.1 + 12.8.2-SNAPSHOT ebean test @@ -29,14 +29,14 @@ io.ebean ebean-core - 12.8.1 + 12.8.2-SNAPSHOT provided io.ebean ebean-ddl-generator - 12.8.1 + 12.8.2-SNAPSHOT diff --git a/ebean/pom.xml b/ebean/pom.xml index f8204d0cf..b293a20bc 100644 --- a/ebean/pom.xml +++ b/ebean/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.1 + 12.8.2-SNAPSHOT ebean composite @@ -22,20 +22,20 @@ io.ebean ebean-api - 12.8.1 + 12.8.2-SNAPSHOT io.ebean ebean-core - 12.8.1 + 12.8.2-SNAPSHOT io.ebean ebean-querybean - 12.8.1 + 12.8.2-SNAPSHOT diff --git a/kotlin-querybean-generator/pom.xml b/kotlin-querybean-generator/pom.xml index a9dda9dc6..70432f360 100644 --- a/kotlin-querybean-generator/pom.xml +++ b/kotlin-querybean-generator/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.1 + 12.8.2-SNAPSHOT kotlin querybean generator @@ -29,7 +29,7 @@ io.ebean ebean-querybean - 12.8.1 + 12.8.2-SNAPSHOT test @@ -43,7 +43,7 @@ io.ebean ebean-core - 12.8.1 + 12.8.2-SNAPSHOT test @@ -64,7 +64,7 @@ io.ebean ebean-ddl-generator - 12.8.1 + 12.8.2-SNAPSHOT test diff --git a/pom.xml b/pom.xml index 4064eef48..a0ce632a3 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean-parent - 12.8.1 + 12.8.2-SNAPSHOT pom ebean parent @@ -18,7 +18,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-parent-12.8.1 + ebean-parent-12.8.0 diff --git a/querybean-generator/pom.xml b/querybean-generator/pom.xml index 7da5e03b1..be174f512 100644 --- a/querybean-generator/pom.xml +++ b/querybean-generator/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.1 + 12.8.2-SNAPSHOT querybean generator From f9b55a06b81064e761c7abdef297f2c086c89f3e Mon Sep 17 00:00:00 2001 From: Tobias Date: Wed, 31 Mar 2021 12:45:48 +0200 Subject: [PATCH 26/52] Add bitwise operators to query beans --- .../java/io/ebean/typequery/PInteger.java | 66 +++++++++++++++++ .../main/java/io/ebean/typequery/PLong.java | 70 ++++++++++++++++++- .../main/java/io/ebean/typequery/PShort.java | 68 +++++++++++++++++- 3 files changed, 201 insertions(+), 3 deletions(-) diff --git a/ebean-querybean/src/main/java/io/ebean/typequery/PInteger.java b/ebean-querybean/src/main/java/io/ebean/typequery/PInteger.java index 3aefa8f46..8657461be 100644 --- a/ebean-querybean/src/main/java/io/ebean/typequery/PInteger.java +++ b/ebean-querybean/src/main/java/io/ebean/typequery/PInteger.java @@ -24,4 +24,70 @@ public class PInteger extends PBaseNumber { super(name, root, prefix); } + /** + * Add bitwise AND expression of the given bit flags to compare with the match/mask. + *

+ *

{@code
+   *
+   * // Flags Bulk + Size = Size
+   * // ... meaning Bulk is not set and Size is set
+   *
+   * int selectedFlags = BwFlags.HAS_BULK + BwFlags.HAS_SIZE;
+   * int mask = BwFlags.HAS_SIZE; // Only Size flag set
+   *
+   * bitwiseAnd(selectedFlags, mask)
+   *
+   * }
+ * + * @param flags The flags we are looking for + */ + public R bitwiseAnd(int flags, int mask) { + expr().bitwiseAnd(_name, flags, mask); + return _root; + } + + /** + * Add expression for ALL of the given bit flags to be set. + *
{@code
+   *
+   * bitwiseAll(BwFlags.HAS_BULK + BwFlags.HAS_COLOUR)
+   *
+   * }
+ * + * @param flags The flags we are looking for + */ + public R bitwiseAll(int flags) { + expr().bitwiseAll(_name, flags); + return _root; + } + + /** + * Add expression for ANY of the given bit flags to be set. + *
{@code
+   *
+   * bitwiseAny(BwFlags.HAS_BULK + BwFlags.HAS_COLOUR)
+   *
+   * }
+ * + * @param flags The flags we are looking for + */ + public R bitwiseAny(int flags) { + expr().bitwiseAny(_name, flags); + return _root; + } + + /** + * Add expression for the given bit flags to be NOT set. + *
{@code
+   *
+   * bitwiseNot(BwFlags.HAS_COLOUR)
+   *
+   * }
+ * + * @param flags The flags we are looking for + */ + public R bitwiseNot(int flags) { + expr().bitwiseNot(_name, flags); + return _root; + } } diff --git a/ebean-querybean/src/main/java/io/ebean/typequery/PLong.java b/ebean-querybean/src/main/java/io/ebean/typequery/PLong.java index e5869682c..d8e4cf58b 100644 --- a/ebean-querybean/src/main/java/io/ebean/typequery/PLong.java +++ b/ebean-querybean/src/main/java/io/ebean/typequery/PLong.java @@ -5,7 +5,7 @@ package io.ebean.typequery; * * @param the root query bean type */ -public class PLong extends PBaseNumber { +public class PLong extends PBaseNumber { /** * Construct with a property name and root instance. @@ -14,7 +14,7 @@ public class PLong extends PBaseNumber { * @param root the root query bean instance */ public PLong(String name, R root) { - super(name , root); + super(name, root); } /** @@ -24,4 +24,70 @@ public class PLong extends PBaseNumber { super(name, root, prefix); } + /** + * Add bitwise AND expression of the given bit flags to compare with the match/mask. + *

+ *

{@code
+   *
+   * // Flags Bulk + Size = Size
+   * // ... meaning Bulk is not set and Size is set
+   *
+   * long selectedFlags = BwFlags.HAS_BULK + BwFlags.HAS_SIZE;
+   * long mask = BwFlags.HAS_SIZE; // Only Size flag set
+   *
+   * bitwiseAnd(selectedFlags, mask)
+   *
+   * }
+ * + * @param flags The flags we are looking for + */ + public R bitwiseAnd(long flags, long mask) { + expr().bitwiseAnd(_name, flags, mask); + return _root; + } + + /** + * Add expression for ALL of the given bit flags to be set. + *
{@code
+   *
+   * bitwiseAll(BwFlags.HAS_BULK + BwFlags.HAS_COLOUR)
+   *
+   * }
+ * + * @param flags The flags we are looking for + */ + public R bitwiseAll(long flags) { + expr().bitwiseAll(_name, flags); + return _root; + } + + /** + * Add expression for ANY of the given bit flags to be set. + *
{@code
+   *
+   * bitwiseAny(BwFlags.HAS_BULK + BwFlags.HAS_COLOUR)
+   *
+   * }
+ * + * @param flags The flags we are looking for + */ + public R bitwiseAny(long flags) { + expr().bitwiseAny(_name, flags); + return _root; + } + + /** + * Add expression for the given bit flags to be NOT set. + *
{@code
+   *
+   * bitwiseNot(BwFlags.HAS_COLOUR)
+   *
+   * }
+ * + * @param flags The flags we are looking for + */ + public R bitwiseNot(long flags) { + expr().bitwiseNot(_name, flags); + return _root; + } } diff --git a/ebean-querybean/src/main/java/io/ebean/typequery/PShort.java b/ebean-querybean/src/main/java/io/ebean/typequery/PShort.java index 440a5ab4c..f8ee7bf8a 100644 --- a/ebean-querybean/src/main/java/io/ebean/typequery/PShort.java +++ b/ebean-querybean/src/main/java/io/ebean/typequery/PShort.java @@ -5,7 +5,7 @@ package io.ebean.typequery; * * @param the root query bean type */ -public class PShort extends PBaseNumber { +public class PShort extends PBaseNumber { /** * Construct with a property name and root instance. @@ -24,4 +24,70 @@ public class PShort extends PBaseNumber { super(name, root, prefix); } + /** + * Add bitwise AND expression of the given bit flags to compare with the match/mask. + *

+ *

{@code
+   *
+   * // Flags Bulk + Size = Size
+   * // ... meaning Bulk is not set and Size is set
+   *
+   * short selectedFlags = BwFlags.HAS_BULK + BwFlags.HAS_SIZE;
+   * short mask = BwFlags.HAS_SIZE; // Only Size flag set
+   *
+   * bitwiseAnd(selectedFlags, mask)
+   *
+   * }
+ * + * @param flags The flags we are looking for + */ + public R bitwiseAnd(short flags, short mask) { + expr().bitwiseAnd(_name, flags, mask); + return _root; + } + + /** + * Add expression for ALL of the given bit flags to be set. + *
{@code
+   *
+   * bitwiseAll(BwFlags.HAS_BULK + BwFlags.HAS_COLOUR)
+   *
+   * }
+ * + * @param flags The flags we are looking for + */ + public R bitwiseAll(short flags) { + expr().bitwiseAll(_name, flags); + return _root; + } + + /** + * Add expression for ANY of the given bit flags to be set. + *
{@code
+   *
+   * bitwiseAny(BwFlags.HAS_BULK + BwFlags.HAS_COLOUR)
+   *
+   * }
+ * + * @param flags The flags we are looking for + */ + public R bitwiseAny(short flags) { + expr().bitwiseAny(_name, flags); + return _root; + } + + /** + * Add expression for the given bit flags to be NOT set. + *
{@code
+   *
+   * bitwiseNot(BwFlags.HAS_COLOUR)
+   *
+   * }
+ * + * @param flags The flags we are looking for + */ + public R bitwiseNot(short flags) { + expr().bitwiseNot(_name, flags); + return _root; + } } From f53d31aa2e80f8e05663b99daa29ee4dd8fbccdd Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Thu, 1 Apr 2021 12:22:45 +1300 Subject: [PATCH 27/52] No functional change - final field for BatchControl --- .../main/java/io/ebeaninternal/server/persist/BatchControl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/persist/BatchControl.java b/ebean-core/src/main/java/io/ebeaninternal/server/persist/BatchControl.java index 10ba7f205..f276bb331 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/persist/BatchControl.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/persist/BatchControl.java @@ -81,7 +81,7 @@ public final class BatchControl { */ private int bufferMax; - private Queue[] queues = new Queue[3]; + private final Queue[] queues = new Queue[3]; /** * Create for a given transaction, PersistExecute, default size and getGeneratedKeys. From a617d5890203d445cbd33badcec33ddd3d9d5c0a Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Thu, 1 Apr 2021 14:47:54 +1300 Subject: [PATCH 28/52] Initial experimental support for "transparent persistence" In short, when this is turned on at flush() get any dirty beans held by the PersistenceContext and persist them (always update for these beans) --- .../src/main/java/io/ebean/Transaction.java | 8 + .../io/ebean/bean/PersistenceContext.java | 7 + .../ebeaninternal/api/ScopedTransaction.java | 5 + .../server/core/DefaultServer.java | 2 +- .../server/core/InternalConfiguration.java | 4 +- .../DefaultPersistenceContext.java | 31 ++- .../ImplicitReadOnlyTransaction.java | 5 + .../server/transaction/JdbcTransaction.java | 14 +- .../server/transaction/NoTransaction.java | 5 + .../transaction/SavepointTransaction.java | 5 + .../transaction/TransactionManager.java | 16 +- .../TransactionManagerOptions.java | 6 +- .../TestTransparentPersist.java | 204 ++++++++++++++++++ .../src/test/resources/logback-test.xml | 4 +- 14 files changed, 303 insertions(+), 13 deletions(-) create mode 100644 ebean-core/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java diff --git a/ebean-api/src/main/java/io/ebean/Transaction.java b/ebean-api/src/main/java/io/ebean/Transaction.java index d4918e84e..0cbfd6e3c 100644 --- a/ebean-api/src/main/java/io/ebean/Transaction.java +++ b/ebean-api/src/main/java/io/ebean/Transaction.java @@ -59,6 +59,14 @@ public interface Transaction extends AutoCloseable { */ void register(TransactionCallback callback); + /** + * EXPERIMENTAL - turn on transparent persistence and batchMode true. + *

+ * With this turned on beans that are dirty in the persistence context + * are automatically persisted on flush() and commit(). + */ + void setTransparentPersistence(boolean transparentPersistence); + /** * Set a label on the transaction. *

diff --git a/ebean-api/src/main/java/io/ebean/bean/PersistenceContext.java b/ebean-api/src/main/java/io/ebean/bean/PersistenceContext.java index a8a42e51b..8c861af1f 100644 --- a/ebean-api/src/main/java/io/ebean/bean/PersistenceContext.java +++ b/ebean-api/src/main/java/io/ebean/bean/PersistenceContext.java @@ -1,5 +1,7 @@ package io.ebean.bean; +import java.util.List; + /** * Holds entity beans by there type and id. *

@@ -77,6 +79,11 @@ public interface PersistenceContext { */ boolean resetLimit(); + /** + * Return the list of dirty beans held by this persistence context. + */ + List dirtyBeans(); + /** * Wrapper on a bean to also indicate if a bean has been deleted. *

diff --git a/ebean-core/src/main/java/io/ebeaninternal/api/ScopedTransaction.java b/ebean-core/src/main/java/io/ebeaninternal/api/ScopedTransaction.java index f5a1db07b..6e95a114e 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/api/ScopedTransaction.java +++ b/ebean-core/src/main/java/io/ebeaninternal/api/ScopedTransaction.java @@ -131,6 +131,11 @@ public class ScopedTransaction extends SpiTransactionProxy { } } + @Override + public void setTransparentPersistence(boolean transparentPersistence) { + current.getTransaction().setTransparentPersistence(transparentPersistence); + } + @Override public void setRollbackOnly() { current.setRollbackOnly(); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultServer.java b/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultServer.java index 52b94bfb6..6595d9816 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultServer.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultServer.java @@ -236,7 +236,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { this.clockService = config.getClockService(); DocStoreIntegration docStoreComponents = config.createDocStoreIntegration(this); - this.transactionManager = config.createTransactionManager(docStoreComponents.updateProcessor()); + this.transactionManager = config.createTransactionManager(this, docStoreComponents.updateProcessor()); this.documentStore = docStoreComponents.documentStore(); this.queryPlanManager = config.initQueryPlanManager(transactionManager); this.metaInfoManager = new DefaultMetaInfoManager(this); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java b/ebean-core/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java index 8cbbbfa4b..dca8e3059 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java @@ -423,13 +423,13 @@ public class InternalConfiguration { /** * Create the TransactionManager taking into account autoCommit mode. */ - TransactionManager createTransactionManager(DocStoreUpdateProcessor indexUpdateProcessor) { + TransactionManager createTransactionManager(SpiServer server, DocStoreUpdateProcessor indexUpdateProcessor) { TransactionScopeManager scopeManager = createTransactionScopeManager(); boolean notifyL2CacheInForeground = cacheManager.isLocalL2Caching() || config.isNotifyL2CacheInForeground(); TransactionManagerOptions options = - new TransactionManagerOptions(notifyL2CacheInForeground, config, scopeManager, clusterManager, backgroundExecutor, + new TransactionManagerOptions(server, notifyL2CacheInForeground, config, scopeManager, clusterManager, backgroundExecutor, indexUpdateProcessor, beanDescriptorManager, dataSource(), profileHandler(), logManager, tableModState, cacheNotify, clockService); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/DefaultPersistenceContext.java b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/DefaultPersistenceContext.java index df92246fa..27eea2e4c 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/DefaultPersistenceContext.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/DefaultPersistenceContext.java @@ -1,11 +1,9 @@ package io.ebeaninternal.server.transaction; +import io.ebean.bean.EntityBean; import io.ebean.bean.PersistenceContext; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.concurrent.locks.ReentrantLock; /** @@ -200,6 +198,20 @@ public final class DefaultPersistenceContext implements PersistenceContext { } } + @Override + public List dirtyBeans() { + lock.lock(); + try { + List list = new ArrayList<>(); + for (ClassContext classContext : typeCache.values()) { + classContext.dirtyBeans(list); + } + return list; + } finally { + lock.unlock(); + } + } + @Override public String toString() { lock.lock(); @@ -318,6 +330,17 @@ public final class DefaultPersistenceContext implements PersistenceContext { deleteSet.add(id); map.remove(id); } + + /** + * Add the dirty beans to the list. + */ + void dirtyBeans(List list) { + for (Object value : map.values()) { + if (((EntityBean) value)._ebean_getIntercept().isDirty()) { + list.add(value); + } + } + } } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/ImplicitReadOnlyTransaction.java b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/ImplicitReadOnlyTransaction.java index 79bf85335..04d7a83a5 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/ImplicitReadOnlyTransaction.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/ImplicitReadOnlyTransaction.java @@ -95,6 +95,11 @@ class ImplicitReadOnlyTransaction implements SpiTransaction, TxnProfileEventCode return startNanos; } + @Override + public void setTransparentPersistence(boolean transparentPersistence) { + // do nothing + } + @Override public void setLabel(String label) { // do nothing diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java index 8c1897ff5..2585c2b23 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java @@ -187,6 +187,8 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes { private final long startNanos; + private boolean transparentPersistence; + /** * Create a new JdbcTransaction. */ @@ -294,6 +296,12 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes { return sb.toString(); } + @Override + public void setTransparentPersistence(boolean transparentPersistence) { + this.transparentPersistence = transparentPersistence; + this.batchMode = true; + } + @Override public boolean isSkipCacheExplicit() { return (skipCache != null && !skipCache); @@ -774,6 +782,10 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes { * Flush the JDBC batch and execute derived relationship statements if necessary. */ private void internalBatchFlush() { + if (transparentPersistence) { + // Experimental - flush dirty beans held by the persistence context + manager.flushTransparent(persistenceContext, this); + } batchFlush(); if (deferredList != null) { for (PersistDeferredRelationship deferred : deferredList) { @@ -1042,7 +1054,7 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes { throw new IllegalStateException(illegalStateMessage); } try { - if (queryOnly) { + if (queryOnly && !transparentPersistence) { connectionEndForQueryOnly(); } else { flushCommitAndNotify(); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/NoTransaction.java b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/NoTransaction.java index 2ef3f2058..5d593302f 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/NoTransaction.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/NoTransaction.java @@ -25,6 +25,11 @@ class NoTransaction implements SpiTransaction { static final NoTransaction INSTANCE = new NoTransaction(); + @Override + public void setTransparentPersistence(boolean transparentPersistence) { + // do nothing + } + @Override public void setLabel(String label) { // do nothing diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/SavepointTransaction.java b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/SavepointTransaction.java index b50122f5c..7b596afec 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/SavepointTransaction.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/SavepointTransaction.java @@ -60,6 +60,11 @@ class SavepointTransaction extends SpiTransactionProxy { this.rollbackOnly = true; } + @Override + public void setTransparentPersistence(boolean transparentPersistence) { + throw new IllegalStateException("This is not handled yet. Need to review this case."); + } + @Override public void commit() { if (rollbackOnly) { diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java index e42ce2fe3..45885ad2a 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java @@ -5,6 +5,7 @@ import io.ebean.ProfileLocation; import io.ebean.TxScope; import io.ebean.annotation.PersistBatch; import io.ebean.annotation.TxType; +import io.ebean.bean.PersistenceContext; import io.ebean.cache.ServerCacheNotification; import io.ebean.cache.ServerCacheNotify; import io.ebean.config.CurrentTenantProvider; @@ -17,6 +18,7 @@ import io.ebean.meta.MetricVisitor; import io.ebean.metric.MetricFactory; import io.ebean.metric.TimedMetric; import io.ebean.metric.TimedMetricMap; +import io.ebean.plugin.SpiServer; import io.ebeaninternal.api.ScopeTrans; import io.ebeaninternal.api.ScopedTransaction; import io.ebeaninternal.api.SpiLogManager; @@ -59,6 +61,8 @@ public class TransactionManager implements SpiTransactionManager { private static final Logger clusterLogger = LoggerFactory.getLogger("io.ebean.Cluster"); + private final SpiServer server; + private final BeanDescriptorManager beanDescriptorManager; /** @@ -153,7 +157,7 @@ public class TransactionManager implements SpiTransactionManager { * Create the TransactionManager */ public TransactionManager(TransactionManagerOptions options) { - + this.server = options.server; this.logManager = options.logManager; this.txnLogger = logManager.txn(); this.txnDebug = txnLogger.isDebug(); @@ -786,4 +790,14 @@ public class TransactionManager implements SpiTransactionManager { public boolean isLogSummary() { return logManager.sum().isDebug(); } + + /** + * Experimental - find dirty beans in the persistence context and persist them. + */ + public void flushTransparent(PersistenceContext persistenceContext, SpiTransaction transaction) { + List dirtyBeans = persistenceContext.dirtyBeans(); + if (!dirtyBeans.isEmpty()) { + server.updateAll(dirtyBeans, transaction); + } + } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/TransactionManagerOptions.java b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/TransactionManagerOptions.java index 9a1b0139b..5d0c87794 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/TransactionManagerOptions.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/TransactionManagerOptions.java @@ -3,6 +3,7 @@ package io.ebeaninternal.server.transaction; import io.ebean.BackgroundExecutor; import io.ebean.cache.ServerCacheNotify; import io.ebean.config.DatabaseConfig; +import io.ebean.plugin.SpiServer; import io.ebeaninternal.api.SpiLogManager; import io.ebeaninternal.api.SpiProfileHandler; import io.ebeaninternal.server.cluster.ClusterManager; @@ -15,6 +16,7 @@ import io.ebeanservice.docstore.api.DocStoreUpdateProcessor; */ public class TransactionManagerOptions { + final SpiServer server; final boolean notifyL2CacheInForeground; final DatabaseConfig config; final ClusterManager clusterManager; @@ -31,11 +33,11 @@ public class TransactionManagerOptions { final ClockService clockService; - public TransactionManagerOptions(boolean notifyL2CacheInForeground, DatabaseConfig config, TransactionScopeManager scopeManager, ClusterManager clusterManager, + public TransactionManagerOptions(SpiServer server, boolean notifyL2CacheInForeground, DatabaseConfig config, TransactionScopeManager scopeManager, ClusterManager clusterManager, BackgroundExecutor backgroundExecutor, DocStoreUpdateProcessor docStoreUpdateProcessor, BeanDescriptorManager descMgr, DataSourceSupplier dataSourceSupplier, SpiProfileHandler profileHandler, SpiLogManager logManager, TableModState tableModState, ServerCacheNotify cacheNotify, ClockService clockService) { - + this.server = server; this.notifyL2CacheInForeground = notifyL2CacheInForeground; this.config = config; this.scopeManager = scopeManager; diff --git a/ebean-core/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java b/ebean-core/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java new file mode 100644 index 000000000..2922d20b2 --- /dev/null +++ b/ebean-core/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java @@ -0,0 +1,204 @@ +package org.tests.transparentpersist; + +import io.ebean.BaseTestCase; +import io.ebean.DB; +import io.ebean.Database; +import io.ebean.Transaction; +import io.ebeaninternal.api.SpiTransaction; +import io.ebeantest.LoggedSql; +import org.junit.Test; +import org.tests.model.basic.Customer; +import org.tests.model.basic.EBasicVer; +import org.tests.model.basic.Order; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TestTransparentPersist extends BaseTestCase { + + @Test + public void simpleInsertUpdateDelete_experimental() { + + EBasicVer b0 = new EBasicVer("simpleIUD_0"); + b0.save(); + EBasicVer b1 = new EBasicVer("simpleIUD_1"); + b1.save(); + EBasicVer b2 = new EBasicVer("simpleIUD_2"); + b2.save(); + + EBasicVer newBean; + try (Transaction transaction = DB.beginTransaction()) { + transaction.setTransparentPersistence(true); // EXPERIMENTAL feature + + EBasicVer found = DB.find(EBasicVer.class, b0.getId()); + found.setName("auto dirty"); + + // delete by id + DB.delete(EBasicVer.class, b1.getId()); + // find and delete, note the delete is batched up to execute later + DB.delete(DB.find(EBasicVer.class, b2.getId())); + + // insert is batched up to execute later + newBean = new EBasicVer("simpleIUD_New1"); + DB.save(newBean); + // can still mutate newBean before flush (but not after flush yet as new bean isn't put into Persistence context) + newBean.setName("simpleIUD_New2"); + + transaction.commit(); + } + + EBasicVer after = DB.find(EBasicVer.class, b0.getId()); + assertThat(after.getName()).isEqualTo("auto dirty"); + + EBasicVer wasInserted = DB.find(EBasicVer.class, newBean.getId()); + assertThat(wasInserted.getName()).isEqualTo("simpleIUD_New2"); + + assertThat(DB.find(EBasicVer.class, b1.getId())).isNull(); + assertThat(DB.find(EBasicVer.class, b2.getId())).isNull(); + + DB.delete(after); + DB.delete(wasInserted); + } + + @Test + public void simpleUpdate_experimental() { + + EBasicVer transPersist = new EBasicVer("simulate_simpleUpdate"); + transPersist.save(); + + try (Transaction transaction = DB.beginTransaction()) { + transaction.setTransparentPersistence(true); // EXPERIMENTAL feature + + EBasicVer found = DB.find(EBasicVer.class, transPersist.getId()); + found.setName("Persisted automatically as dirty"); + + transaction.commit(); + } + + EBasicVer after = DB.find(EBasicVer.class,transPersist.getId()); + assertThat(after.getName()).isEqualTo("Persisted automatically as dirty"); + DB.delete(after); + } + + @Test + public void updateWithPersistCascadeInsert() { + + // setup data + Customer c0 = new Customer(); + c0.setName("firstCust"); + Order order = new Order(); + order.setStatus(Order.Status.NEW); + order.setCustomer(c0); + DB.save(order); + + try (Transaction transaction = DB.beginTransaction()) { + transaction.setTransparentPersistence(true); // EXPERIMENTAL feature + + Order foundOrder = DB.find(Order.class, order.getId()); + foundOrder.setStatus(Order.Status.APPROVED); + // cascade persist will insert this customer (even though it isn't in the persistence context) + Customer c1 = new Customer(); + c1.setName("newCust CascadePersist"); + foundOrder.setCustomer(c1); + + transaction.commit(); + } + + Order checkOrder = DB.find(Order.class, order.getId()); + + assertThat(checkOrder.getStatus()).isEqualTo(Order.Status.APPROVED); + assertThat(checkOrder.getCustomer().getName()).isEqualTo("newCust CascadePersist"); + + DB.delete(checkOrder); + DB.delete(Customer.class, checkOrder.getCustomer().getId()); + DB.delete(Customer.class, c0.getId()); + } + + @Test + public void updateReferenceOnlyWithPersistCascade_Insert_andUpdateForeignKey() { + + // setup data + Customer c0 = new Customer(); + c0.setName("firstCust"); + Order order = new Order(); + order.setStatus(Order.Status.NEW); + order.setCustomer(c0); + DB.save(order); + + LoggedSql.start(); + + try (Transaction transaction = DB.beginTransaction()) { + transaction.setTransparentPersistence(true); // EXPERIMENTAL feature + + Order foundOrder = DB.find(Order.class, order.getId()); + // we ONLY mutate the foreign key + // cascade persist will insert this customer (even though it isn't in the persistence context) + Customer c1 = new Customer(); + c1.setName("newCust CascadePersist"); + foundOrder.setCustomer(c1); + + transaction.commit(); + } + + List sql = LoggedSql.stop(); + + Order checkOrder = DB.find(Order.class, order.getId()); + + assertThat(checkOrder.getStatus()).isEqualTo(Order.Status.NEW); + assertThat(checkOrder.getCustomer().getName()).isEqualTo("newCust CascadePersist"); + + assertThat(sql).hasSize(5); + assertThat(sql.get(0)).contains("select t0.id, t0.status, t0.order_date"); + assertThat(sql.get(1)).contains("insert into o_customer"); + assertThat(sql.get(2)).contains(" -- bind("); + assertThat(sql.get(3)).contains("update o_order set updtime=?, kcustomer_id=? where id=? and updtime=?"); + assertThat(sql.get(4)).contains(" -- bind("); + + DB.delete(checkOrder); + DB.delete(Customer.class, checkOrder.getCustomer().getId()); + DB.delete(Customer.class, c0.getId()); + } + + @Test + public void simulate_transparentPersistence_forSimpleUpdate() { + + EBasicVer transPersist = new EBasicVer("simulate_simpleUpdate"); + transPersist.save(); + + try (Transaction transaction = DB.beginTransaction()) { + transaction.setBatchMode(true); + transaction.setBatchSize(10); + + EBasicVer found = DB.find(EBasicVer.class, transPersist.getId()); + found.setName("Changed"); + + // simulate transparent persistence + List dirtyBeans = simulateTransparentPersist(transaction); + assertThat(dirtyBeans).hasSize(1); + assertThat(dirtyBeans).contains(found); + + // would occur as first part of flush + transaction.flush(); + transaction.commit(); + } + + EBasicVer after = DB.find(EBasicVer.class,transPersist.getId()); + assertThat(after.getName()).isEqualTo("Changed"); + DB.delete(after); + } + + private List simulateTransparentPersist(Transaction transaction) { + Database db = DB.getDefault(); + List dirtyBeans = getDirtyBeansFromPersistenceContext(transaction); + for (Object dirtyBean : dirtyBeans) { + db.update(dirtyBean, transaction); + } + return dirtyBeans; + } + + private List getDirtyBeansFromPersistenceContext(Transaction transaction) { + return ((SpiTransaction)transaction).getPersistenceContext().dirtyBeans(); + } + +} diff --git a/ebean-core/src/test/resources/logback-test.xml b/ebean-core/src/test/resources/logback-test.xml index 1b8a60a9b..164ff73d3 100644 --- a/ebean-core/src/test/resources/logback-test.xml +++ b/ebean-core/src/test/resources/logback-test.xml @@ -79,8 +79,8 @@ - - + + From ba397bbb0c383bb9be0d1174e3752b9db09c4ef5 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Thu, 1 Apr 2021 16:04:18 +1300 Subject: [PATCH 29/52] For experimental "transparent persistence" - Delete removes from PC early When delete bean executed with transparent persistence, this marks the bean as removed from the persistence context early. This avoids a "dirty" deleted bean from being seen as a "dirty" bean in the persistence context at flush() time. --- .../server/core/PersistRequestBean.java | 8 +++++++ .../server/persist/DefaultPersister.java | 1 + .../TestTransparentPersist.java | 23 +++++++++++++++++++ 3 files changed, 32 insertions(+) diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java b/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java index eb48fc2ef..c4d02cbf6 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java @@ -887,6 +887,14 @@ public final class PersistRequestBean extends PersistRequest implements BeanP } } + /** + * Remove deleted beans from the persistence context early. + */ + public void removeFromPersistenceContext() { + idValue = beanDescriptor.getId(entityBean); + beanDescriptor.contextDeleted(transaction.getPersistenceContext(), idValue); + } + /** * Aggressive L1 and L2 cache cleanup for deletes. */ diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java b/ebean-core/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java index a7b21f0c8..005e85d95 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java @@ -881,6 +881,7 @@ public final class DefaultPersister implements Persister { } int count = request.executeOrQueue(); + request.removeFromPersistenceContext(); if (request.isPersistCascade()) { deleteAssocOne(request); diff --git a/ebean-core/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java b/ebean-core/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java index 2922d20b2..be5d8329b 100644 --- a/ebean-core/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java +++ b/ebean-core/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java @@ -17,6 +17,29 @@ import static org.assertj.core.api.Assertions.assertThat; public class TestTransparentPersist extends BaseTestCase { + @Test + public void delete_expect_beanRemovedFromPersistenceContext() { + + EBasicVer b0 = new EBasicVer("simpleDelete"); + DB.save(b0); + + try (Transaction transaction = DB.beginTransaction()) { + transaction.setTransparentPersistence(true); // EXPERIMENTAL feature + + EBasicVer found = DB.find(EBasicVer.class, b0.getId()); + // make it dirty + found.setName("make it dirty"); + + // delete it, should remove it from the "live" part of persistence context + // with the expectation that no update is executed (no dirty in PC update) + DB.delete(found); + transaction.commit(); + } + + EBasicVer after = DB.find(EBasicVer.class, b0.getId()); + assertThat(after).isNull(); + } + @Test public void simpleInsertUpdateDelete_experimental() { From 0527f45f5a4e3b479296e051493cf536728bcc06 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Thu, 1 Apr 2021 16:59:03 +1300 Subject: [PATCH 30/52] For experimental "transparent persistence" - Inserts added to PC When inserting bean with transparent persistence the beans are registered with the persistence context. This is done to support the cases where the beans are inserted, a flush() occurs, the inserted bean is mutated and now dirty - we want that to be detected and get an update --- .../ebeaninternal/api/ScopedTransaction.java | 5 --- .../io/ebeaninternal/api/SpiTransaction.java | 5 +++ .../api/SpiTransactionProxy.java | 10 ++++++ .../server/core/PersistRequestBean.java | 4 +++ .../ImplicitReadOnlyTransaction.java | 5 +++ .../server/transaction/JdbcTransaction.java | 5 +++ .../server/transaction/NoTransaction.java | 5 +++ .../transaction/SavepointTransaction.java | 5 --- .../TestTransparentPersist.java | 36 +++++++++++++++++++ 9 files changed, 70 insertions(+), 10 deletions(-) diff --git a/ebean-core/src/main/java/io/ebeaninternal/api/ScopedTransaction.java b/ebean-core/src/main/java/io/ebeaninternal/api/ScopedTransaction.java index 6e95a114e..f5a1db07b 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/api/ScopedTransaction.java +++ b/ebean-core/src/main/java/io/ebeaninternal/api/ScopedTransaction.java @@ -131,11 +131,6 @@ public class ScopedTransaction extends SpiTransactionProxy { } } - @Override - public void setTransparentPersistence(boolean transparentPersistence) { - current.getTransaction().setTransparentPersistence(transparentPersistence); - } - @Override public void setRollbackOnly() { current.setRollbackOnly(); diff --git a/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransaction.java b/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransaction.java index 74faeccb0..8c520f79e 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransaction.java +++ b/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransaction.java @@ -147,6 +147,11 @@ public interface SpiTransaction extends Transaction { */ int depth(); + /** + * Return true if transparent persistence is turned on. + */ + boolean isTransparentPersistence(); + /** * Return true if this transaction was created explicitly via * Ebean.beginTransaction(). diff --git a/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransactionProxy.java b/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransactionProxy.java index fe5351ddc..1652b56f6 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransactionProxy.java +++ b/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransactionProxy.java @@ -43,6 +43,16 @@ public abstract class SpiTransactionProxy implements SpiTransaction { return transaction.getLabel(); } + @Override + public void setTransparentPersistence(boolean transparentPersistence) { + transaction.setTransparentPersistence(transparentPersistence); + } + + @Override + public boolean isTransparentPersistence() { + return transaction.isTransparentPersistence(); + } + @Override public void commitAndContinue() { transaction.commitAndContinue(); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java b/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java index c4d02cbf6..3f7d6e79a 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java @@ -1038,6 +1038,10 @@ public final class PersistRequestBean extends PersistRequest implements BeanP if (!publish) { beanDescriptor.setDraft(entityBean); } + if (transaction.isTransparentPersistence() && idValue != null) { + // with getGeneratedKeys off we will not have a idValue + beanDescriptor.contextPut(transaction.getPersistenceContext(), idValue, entityBean); + } } public boolean isReference() { diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/ImplicitReadOnlyTransaction.java b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/ImplicitReadOnlyTransaction.java index 04d7a83a5..a94260fb6 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/ImplicitReadOnlyTransaction.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/ImplicitReadOnlyTransaction.java @@ -100,6 +100,11 @@ class ImplicitReadOnlyTransaction implements SpiTransaction, TxnProfileEventCode // do nothing } + @Override + public boolean isTransparentPersistence() { + return false; + } + @Override public void setLabel(String label) { // do nothing diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java index 2585c2b23..bb672cd33 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java @@ -302,6 +302,11 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes { this.batchMode = true; } + @Override + public boolean isTransparentPersistence() { + return transparentPersistence; + } + @Override public boolean isSkipCacheExplicit() { return (skipCache != null && !skipCache); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/NoTransaction.java b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/NoTransaction.java index 5d593302f..92f0e1ca9 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/NoTransaction.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/NoTransaction.java @@ -30,6 +30,11 @@ class NoTransaction implements SpiTransaction { // do nothing } + @Override + public boolean isTransparentPersistence() { + return false; + } + @Override public void setLabel(String label) { // do nothing diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/SavepointTransaction.java b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/SavepointTransaction.java index 7b596afec..b50122f5c 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/SavepointTransaction.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/SavepointTransaction.java @@ -60,11 +60,6 @@ class SavepointTransaction extends SpiTransactionProxy { this.rollbackOnly = true; } - @Override - public void setTransparentPersistence(boolean transparentPersistence) { - throw new IllegalStateException("This is not handled yet. Need to review this case."); - } - @Override public void commit() { if (rollbackOnly) { diff --git a/ebean-core/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java b/ebean-core/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java index be5d8329b..a59ddda60 100644 --- a/ebean-core/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java +++ b/ebean-core/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java @@ -17,6 +17,42 @@ import static org.assertj.core.api.Assertions.assertThat; public class TestTransparentPersist extends BaseTestCase { + @Test + public void insertFlush_mutateFlush_expect_update() { + + LoggedSql.start(); + + EBasicVer newBean; + try (Transaction transaction = DB.beginTransaction()) { + transaction.setTransparentPersistence(true); // EXPERIMENTAL feature + + newBean = new EBasicVer("insertMe"); + DB.save(newBean); + + // flush - new bean needs to get registered into persistence context + transaction.flush(); + + // make it dirty, we expect it to execute an update on flush() + newBean.setName("make it dirty - auto save"); + + // flush again, auto persist dirty bean in persistence context + transaction.commit(); + } + + List sql = LoggedSql.stop(); + + EBasicVer found = DB.find(EBasicVer.class, newBean.getId()); + assertThat(found.getName()).isEqualTo("make it dirty - auto save"); + + assertThat(sql).hasSize(4); + assertThat(sql.get(0)).contains("insert into e_basicver"); + assertThat(sql.get(1)).contains(" -- bind("); + assertThat(sql.get(2)).contains("update e_basicver set name=?, last_update=? where id=? and last_update=?"); + assertThat(sql.get(3)).contains(" -- bind("); + + DB.delete(found); + } + @Test public void delete_expect_beanRemovedFromPersistenceContext() { From 6bcf5c6881e14b0156abaaf14fd4cff39dce8df1 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Thu, 1 Apr 2021 22:57:34 +1300 Subject: [PATCH 31/52] Add DatabaseConfig.autoPersistUpdates for experimental "transparent persistence" --- .../java/io/ebean/config/DatabaseConfig.java | 23 ++++++++++++++++++- .../server/transaction/JdbcTransaction.java | 5 ++-- .../transaction/TransactionManager.java | 11 +++++++-- .../io/ebean/config/ServerConfigTest.java | 3 +++ 4 files changed, 37 insertions(+), 5 deletions(-) diff --git a/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java b/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java index bf4c61675..be2ac6c1f 100644 --- a/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java +++ b/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java @@ -232,6 +232,12 @@ public class DatabaseConfig { */ private String historyTableSuffix = "_history"; + /** + * When true explicit transactions beans that have been made dirty will be + * automatically persisted via update on flush. + */ + private boolean autoPersistUpdates; + /** * Use for transaction scoped batch mode. */ @@ -905,6 +911,20 @@ public class DatabaseConfig { this.tenantCatalogProvider = tenantCatalogProvider; } + /** + * Return true if dirty beans are automatically persisted. + */ + public boolean isAutoPersistUpdates() { + return autoPersistUpdates; + } + + /** + * Set to true if dirty beans are automatically persisted. + */ + public void setAutoPersistUpdates(boolean autoPersistUpdates) { + this.autoPersistUpdates = autoPersistUpdates; + } + /** * Return the PersistBatch mode to use by default at the transaction level. *

@@ -2807,6 +2827,7 @@ public class DatabaseConfig { loadDocStoreSettings(p); defaultServer = p.getBoolean("defaultServer", defaultServer); + autoPersistUpdates = p.getBoolean("autoPersistUpdates", autoPersistUpdates); loadModuleInfo = p.getBoolean("loadModuleInfo", loadModuleInfo); maxCallStack = p.getInt("maxCallStack", maxCallStack); dumpMetricsOnShutdown = p.getBoolean("dumpMetricsOnShutdown", dumpMetricsOnShutdown); @@ -3348,7 +3369,7 @@ public class DatabaseConfig { this.loadModuleInfo = loadModuleInfo; } - public enum UuidVersion { + public enum UuidVersion { VERSION4, VERSION1, VERSION1RND diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java index bb672cd33..411331aef 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java @@ -211,11 +211,12 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes { this.batchOnCascadeMode = false; this.onQueryOnly = OnQueryOnly.ROLLBACK; } else { + this.transparentPersistence = explicit && manager.isAutoPersistUpdates(); this.logSql = manager.isLogSql(); this.logSummary = manager.isLogSummary(); this.skipCacheAfterWrite = manager.isSkipCacheAfterWrite(); - this.batchMode = manager.getPersistBatch(); - this.batchOnCascadeMode = manager.getPersistBatchOnCascade(); + this.batchMode = manager.isPersistBatch(); + this.batchOnCascadeMode = manager.isPersistBatchOnCascade(); this.onQueryOnly = manager.getOnQueryOnly(); } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java index 45885ad2a..b71868e5d 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java @@ -104,6 +104,8 @@ public class TransactionManager implements SpiTransactionManager { */ final DocStoreUpdateProcessor docStoreUpdateProcessor; + private final boolean autoPersistUpdates; + private final boolean persistBatch; private final boolean persistBatchOnCascade; @@ -165,6 +167,7 @@ public class TransactionManager implements SpiTransactionManager { this.supportsSavepointId = databasePlatform.isSupportsSavepointId(); this.skipCacheAfterWrite = options.config.isSkipCacheAfterWrite(); this.notifyL2CacheInForeground = options.notifyL2CacheInForeground; + this.autoPersistUpdates = options.config.isAutoPersistUpdates(); this.persistBatch = PersistBatch.ALL == options.config.getPersistBatch(); this.persistBatchOnCascade = PersistBatch.ALL == options.config.appliedPersistBatchOnCascade(); this.rollbackOnChecked = options.config.isTransactionRollbackOnChecked(); @@ -283,11 +286,15 @@ public class TransactionManager implements SpiTransactionManager { return bulkEventListenerMap; } - boolean getPersistBatch() { + boolean isAutoPersistUpdates() { + return autoPersistUpdates; + } + + boolean isPersistBatch() { return persistBatch; } - public boolean getPersistBatchOnCascade() { + boolean isPersistBatchOnCascade() { return persistBatchOnCascade; } diff --git a/ebean-core/src/test/java/io/ebean/config/ServerConfigTest.java b/ebean-core/src/test/java/io/ebean/config/ServerConfigTest.java index f93c18d26..4e92798d6 100644 --- a/ebean-core/src/test/java/io/ebean/config/ServerConfigTest.java +++ b/ebean-core/src/test/java/io/ebean/config/ServerConfigTest.java @@ -149,6 +149,7 @@ public class ServerConfigTest { ServerConfig serverConfig = new ServerConfig(); assertTrue(serverConfig.isIdGeneratorAutomatic()); assertTrue(serverConfig.isDefaultServer()); + assertFalse(serverConfig.isAutoPersistUpdates()); serverConfig.setIdGeneratorAutomatic(false); assertFalse(serverConfig.isIdGeneratorAutomatic()); @@ -166,6 +167,8 @@ public class ServerConfigTest { serverConfig.setLoadModuleInfo(false); assertFalse(serverConfig.isAutoLoadModuleInfo()); + serverConfig.setAutoPersistUpdates(true); + assertTrue(serverConfig.isAutoPersistUpdates()); } @Test From 303039735f1cbae070cced68706a64b2dddb3bc8 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Thu, 1 Apr 2021 23:04:22 +1300 Subject: [PATCH 32/52] Refactor rename transparentPersistence to autoPersistUpdates --- .../src/main/java/io/ebean/Transaction.java | 4 ++-- .../io/ebeaninternal/api/SpiTransaction.java | 4 ++-- .../ebeaninternal/api/SpiTransactionProxy.java | 8 ++++---- .../server/core/PersistRequestBean.java | 2 +- .../transaction/ImplicitReadOnlyTransaction.java | 4 ++-- .../server/transaction/JdbcTransaction.java | 16 ++++++++-------- .../server/transaction/NoTransaction.java | 4 ++-- .../TestTransparentPersist.java | 12 ++++++------ 8 files changed, 27 insertions(+), 27 deletions(-) diff --git a/ebean-api/src/main/java/io/ebean/Transaction.java b/ebean-api/src/main/java/io/ebean/Transaction.java index 0cbfd6e3c..9a391d654 100644 --- a/ebean-api/src/main/java/io/ebean/Transaction.java +++ b/ebean-api/src/main/java/io/ebean/Transaction.java @@ -60,12 +60,12 @@ public interface Transaction extends AutoCloseable { void register(TransactionCallback callback); /** - * EXPERIMENTAL - turn on transparent persistence and batchMode true. + * EXPERIMENTAL - turn on automatic persistence of dirty beans and batchMode true. *

* With this turned on beans that are dirty in the persistence context * are automatically persisted on flush() and commit(). */ - void setTransparentPersistence(boolean transparentPersistence); + void setAutoPersistUpdates(boolean autoPersistUpdates); /** * Set a label on the transaction. diff --git a/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransaction.java b/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransaction.java index 8c520f79e..8c59fa7dc 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransaction.java +++ b/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransaction.java @@ -148,9 +148,9 @@ public interface SpiTransaction extends Transaction { int depth(); /** - * Return true if transparent persistence is turned on. + * Return true if dirty beans are automatically persisted. */ - boolean isTransparentPersistence(); + boolean isAutoPersistUpdates(); /** * Return true if this transaction was created explicitly via diff --git a/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransactionProxy.java b/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransactionProxy.java index 1652b56f6..5fd2a3c6e 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransactionProxy.java +++ b/ebean-core/src/main/java/io/ebeaninternal/api/SpiTransactionProxy.java @@ -44,13 +44,13 @@ public abstract class SpiTransactionProxy implements SpiTransaction { } @Override - public void setTransparentPersistence(boolean transparentPersistence) { - transaction.setTransparentPersistence(transparentPersistence); + public void setAutoPersistUpdates(boolean autoPersistUpdates) { + transaction.setAutoPersistUpdates(autoPersistUpdates); } @Override - public boolean isTransparentPersistence() { - return transaction.isTransparentPersistence(); + public boolean isAutoPersistUpdates() { + return transaction.isAutoPersistUpdates(); } @Override diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java b/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java index 3f7d6e79a..31d92b0a0 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java @@ -1038,7 +1038,7 @@ public final class PersistRequestBean extends PersistRequest implements BeanP if (!publish) { beanDescriptor.setDraft(entityBean); } - if (transaction.isTransparentPersistence() && idValue != null) { + if (transaction.isAutoPersistUpdates() && idValue != null) { // with getGeneratedKeys off we will not have a idValue beanDescriptor.contextPut(transaction.getPersistenceContext(), idValue, entityBean); } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/ImplicitReadOnlyTransaction.java b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/ImplicitReadOnlyTransaction.java index a94260fb6..5f2b5d195 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/ImplicitReadOnlyTransaction.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/ImplicitReadOnlyTransaction.java @@ -96,12 +96,12 @@ class ImplicitReadOnlyTransaction implements SpiTransaction, TxnProfileEventCode } @Override - public void setTransparentPersistence(boolean transparentPersistence) { + public void setAutoPersistUpdates(boolean autoPersistUpdates) { // do nothing } @Override - public boolean isTransparentPersistence() { + public boolean isAutoPersistUpdates() { return false; } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java index 411331aef..7d3b3ddf1 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java @@ -187,7 +187,7 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes { private final long startNanos; - private boolean transparentPersistence; + private boolean autoPersistUpdates; /** * Create a new JdbcTransaction. @@ -211,7 +211,7 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes { this.batchOnCascadeMode = false; this.onQueryOnly = OnQueryOnly.ROLLBACK; } else { - this.transparentPersistence = explicit && manager.isAutoPersistUpdates(); + this.autoPersistUpdates = explicit && manager.isAutoPersistUpdates(); this.logSql = manager.isLogSql(); this.logSummary = manager.isLogSummary(); this.skipCacheAfterWrite = manager.isSkipCacheAfterWrite(); @@ -298,14 +298,14 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes { } @Override - public void setTransparentPersistence(boolean transparentPersistence) { - this.transparentPersistence = transparentPersistence; + public void setAutoPersistUpdates(boolean autoPersistUpdates) { + this.autoPersistUpdates = autoPersistUpdates; this.batchMode = true; } @Override - public boolean isTransparentPersistence() { - return transparentPersistence; + public boolean isAutoPersistUpdates() { + return autoPersistUpdates; } @Override @@ -788,7 +788,7 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes { * Flush the JDBC batch and execute derived relationship statements if necessary. */ private void internalBatchFlush() { - if (transparentPersistence) { + if (autoPersistUpdates) { // Experimental - flush dirty beans held by the persistence context manager.flushTransparent(persistenceContext, this); } @@ -1060,7 +1060,7 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes { throw new IllegalStateException(illegalStateMessage); } try { - if (queryOnly && !transparentPersistence) { + if (queryOnly && !autoPersistUpdates) { connectionEndForQueryOnly(); } else { flushCommitAndNotify(); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/NoTransaction.java b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/NoTransaction.java index 92f0e1ca9..0d3c82cd6 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/NoTransaction.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/NoTransaction.java @@ -26,12 +26,12 @@ class NoTransaction implements SpiTransaction { static final NoTransaction INSTANCE = new NoTransaction(); @Override - public void setTransparentPersistence(boolean transparentPersistence) { + public void setAutoPersistUpdates(boolean autoPersistUpdates) { // do nothing } @Override - public boolean isTransparentPersistence() { + public boolean isAutoPersistUpdates() { return false; } diff --git a/ebean-core/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java b/ebean-core/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java index a59ddda60..963cc1dcb 100644 --- a/ebean-core/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java +++ b/ebean-core/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java @@ -24,7 +24,7 @@ public class TestTransparentPersist extends BaseTestCase { EBasicVer newBean; try (Transaction transaction = DB.beginTransaction()) { - transaction.setTransparentPersistence(true); // EXPERIMENTAL feature + transaction.setAutoPersistUpdates(true); // EXPERIMENTAL feature newBean = new EBasicVer("insertMe"); DB.save(newBean); @@ -60,7 +60,7 @@ public class TestTransparentPersist extends BaseTestCase { DB.save(b0); try (Transaction transaction = DB.beginTransaction()) { - transaction.setTransparentPersistence(true); // EXPERIMENTAL feature + transaction.setAutoPersistUpdates(true); // EXPERIMENTAL feature EBasicVer found = DB.find(EBasicVer.class, b0.getId()); // make it dirty @@ -88,7 +88,7 @@ public class TestTransparentPersist extends BaseTestCase { EBasicVer newBean; try (Transaction transaction = DB.beginTransaction()) { - transaction.setTransparentPersistence(true); // EXPERIMENTAL feature + transaction.setAutoPersistUpdates(true); // EXPERIMENTAL feature EBasicVer found = DB.find(EBasicVer.class, b0.getId()); found.setName("auto dirty"); @@ -127,7 +127,7 @@ public class TestTransparentPersist extends BaseTestCase { transPersist.save(); try (Transaction transaction = DB.beginTransaction()) { - transaction.setTransparentPersistence(true); // EXPERIMENTAL feature + transaction.setAutoPersistUpdates(true); // EXPERIMENTAL feature EBasicVer found = DB.find(EBasicVer.class, transPersist.getId()); found.setName("Persisted automatically as dirty"); @@ -152,7 +152,7 @@ public class TestTransparentPersist extends BaseTestCase { DB.save(order); try (Transaction transaction = DB.beginTransaction()) { - transaction.setTransparentPersistence(true); // EXPERIMENTAL feature + transaction.setAutoPersistUpdates(true); // EXPERIMENTAL feature Order foundOrder = DB.find(Order.class, order.getId()); foundOrder.setStatus(Order.Status.APPROVED); @@ -188,7 +188,7 @@ public class TestTransparentPersist extends BaseTestCase { LoggedSql.start(); try (Transaction transaction = DB.beginTransaction()) { - transaction.setTransparentPersistence(true); // EXPERIMENTAL feature + transaction.setAutoPersistUpdates(true); // EXPERIMENTAL feature Order foundOrder = DB.find(Order.class, order.getId()); // we ONLY mutate the foreign key From 6d8a1c9398951b2bffe51e1e9d951b971bfbcb91 Mon Sep 17 00:00:00 2001 From: Vladimir Konkov Date: Mon, 5 Apr 2021 21:45:48 +0300 Subject: [PATCH 33/52] Explicit locking method withLock() is unaccessible on query beans --- .../src/main/java/io/ebean/typequery/TQRootBean.java | 4 ++-- .../src/test/java/org/querytest/QCustomerTest.java | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ebean-querybean/src/main/java/io/ebean/typequery/TQRootBean.java b/ebean-querybean/src/main/java/io/ebean/typequery/TQRootBean.java index 654e35e9d..728184cf4 100644 --- a/ebean-querybean/src/main/java/io/ebean/typequery/TQRootBean.java +++ b/ebean-querybean/src/main/java/io/ebean/typequery/TQRootBean.java @@ -679,7 +679,7 @@ public abstract class TQRootBean { * Provides us with the ability to explicitly use Postgres * SHARE, KEY SHARE, NO KEY UPDATE and UPDATE row locks. */ - R withLock(Query.LockType lockType) { + public R withLock(Query.LockType lockType) { query.withLock(lockType); return root; } @@ -693,7 +693,7 @@ public abstract class TQRootBean { * Provides us with the ability to explicitly use Postgres * SHARE, KEY SHARE, NO KEY UPDATE and UPDATE row locks. */ - R withLock(Query.LockType lockType, Query.LockWait lockWait) { + public R withLock(Query.LockType lockType, Query.LockWait lockWait) { query.withLock(lockType, lockWait); return root; } diff --git a/ebean-querybean/src/test/java/org/querytest/QCustomerTest.java b/ebean-querybean/src/test/java/org/querytest/QCustomerTest.java index 56aec1c51..867290e71 100644 --- a/ebean-querybean/src/test/java/org/querytest/QCustomerTest.java +++ b/ebean-querybean/src/test/java/org/querytest/QCustomerTest.java @@ -71,6 +71,7 @@ public class QCustomerTest { // not found using other transaction final Customer foundNot = new QCustomer() .name.eq("explicitTransaction") + .withLock(Query.LockType.SHARE) .findOne(); assertThat(foundNot).isNull(); From 9b04f20ed3a1c40de97826f682524d3a6757a77d Mon Sep 17 00:00:00 2001 From: Roman Parshikov Date: Tue, 6 Apr 2021 13:32:57 +0800 Subject: [PATCH 34/52] Fix copy/paste typo --- ebean-api/src/main/java/io/ebean/ExpressionList.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ebean-api/src/main/java/io/ebean/ExpressionList.java b/ebean-api/src/main/java/io/ebean/ExpressionList.java index 72f1c06f9..e91846e08 100644 --- a/ebean-api/src/main/java/io/ebean/ExpressionList.java +++ b/ebean-api/src/main/java/io/ebean/ExpressionList.java @@ -1671,7 +1671,7 @@ public interface ExpressionList { ExpressionList endAnd(); /** - * End a AND junction - synonym for endJunction(). + * End a OR junction - synonym for endJunction(). */ ExpressionList endOr(); From f7c1845f0c5dae997f27a799438fea02a7dadf2f Mon Sep 17 00:00:00 2001 From: rbygrave Date: Tue, 6 Apr 2021 19:58:02 +1200 Subject: [PATCH 35/52] #2177 - Fix where schema not provided by JDBC driver For @Table with schema, using findNative with a JDBC driver that does not provide the schema this fix matches by just using the table name. --- .../server/deploy/BeanDescriptor.java | 6 +-- .../server/deploy/BeanDescriptorTest.java | 53 ++++++++++++++++--- 2 files changed, 48 insertions(+), 11 deletions(-) diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java index a2d902f13..e05c636bb 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java @@ -2473,7 +2473,7 @@ public class BeanDescriptor implements BeanType, STreeType { * Return the property path given the db table and column. */ public String findBeanPath(String schemaName, String tableName, String columnName) { - if (matchBaseTable(schemaName, tableName)) { + if (matchBaseTable(tableName)) { return columnPath.get(columnName); } BeanPropertyAssoc assocProperty = tablePath.get(tableName); @@ -2489,10 +2489,10 @@ public class BeanDescriptor implements BeanType, STreeType { return null; } - private boolean matchBaseTable(String schemaName, String tableName) { + boolean matchBaseTable(String tableName) { return tableName.isEmpty() || baseTable.equalsIgnoreCase(tableName) - || baseTable.equalsIgnoreCase(schemaName + "." + tableName); + || baseTable.endsWith("." + tableName); } /** diff --git a/ebean-core/src/test/java/io/ebeaninternal/server/deploy/BeanDescriptorTest.java b/ebean-core/src/test/java/io/ebeaninternal/server/deploy/BeanDescriptorTest.java index d4cbcbfbf..ab8ae6a87 100644 --- a/ebean-core/src/test/java/io/ebeaninternal/server/deploy/BeanDescriptorTest.java +++ b/ebean-core/src/test/java/io/ebeaninternal/server/deploy/BeanDescriptorTest.java @@ -4,21 +4,22 @@ import io.ebean.BaseTestCase; import io.ebean.Ebean; import io.ebean.bean.EntityBean; import io.ebean.plugin.Property; +import io.ebeaninternal.server.core.CacheOptions; +import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor; +import io.ebeaninternal.server.deploy.meta.DeployIdentityMode; +import io.ebeanservice.docstore.api.DocStoreBeanAdapter; import org.junit.Test; -import org.tests.model.basic.Animal; -import org.tests.model.basic.AnimalShelter; -import org.tests.model.basic.Cat; -import org.tests.model.basic.Contact; -import org.tests.model.basic.Country; -import org.tests.model.basic.Customer; -import org.tests.model.basic.Dog; -import org.tests.model.basic.Order; +import org.tests.model.basic.*; import org.tests.model.bridge.BSite; import org.tests.model.bridge.BUser; import java.util.Collection; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class BeanDescriptorTest extends BaseTestCase { @@ -88,6 +89,42 @@ public class BeanDescriptorTest extends BaseTestCase { assertThat(props).extracting("name").contains("id", "status", "orderDate", "shipDate"); } + @Test + public void matchBaseTable() { + BeanDescriptor desc = getBeanDescriptor(Customer.class); + assertTrue(desc.matchBaseTable("o_customer")); + } + + @Test + public void matchBaseTable_whenTableHasSchema_expect_matchRegardlessOfSchema() { + + DeployBeanDescriptor deploy = mockDeployCustomer(); + + when(deploy.getBaseTable()).thenReturn("foo.o_customer"); + BeanDescriptor desc1 = new BeanDescriptor<>(mockOwner(), deploy); + assertTrue(desc1.matchBaseTable("o_customer")); + + when(deploy.getBaseTable()).thenReturn("bar.o_customer"); + BeanDescriptor desc2 = new BeanDescriptor<>(mockOwner(), deploy); + assertTrue(desc2.matchBaseTable("o_customer")); + } + + @SuppressWarnings("unchecked") + private DeployBeanDescriptor mockDeployCustomer() { + DeployBeanDescriptor deploy = mock(DeployBeanDescriptor.class); + when(deploy.getBeanType()).thenReturn(Customer.class); + when(deploy.getIdentityMode()).thenReturn(DeployIdentityMode.auto()); + when(deploy.buildIdentityMode()).thenReturn(IdentityMode.NONE); + when(deploy.getCacheOptions()).thenReturn(CacheOptions.NO_CACHING); + return deploy; + } + + private BeanDescriptorMap mockOwner() { + BeanDescriptorMap owner = mock(BeanDescriptorMap.class); + when(owner.createDocStoreBeanAdapter(any(), any())).thenReturn(mock(DocStoreBeanAdapter.class)); + return owner; + } + @Test public void merge_when_empty() { From 3e97a4005ab34abbac6829ac7e8d70550427c96f Mon Sep 17 00:00:00 2001 From: rbygrave Date: Tue, 6 Apr 2021 20:09:09 +1200 Subject: [PATCH 36/52] Change TestCustomerFinder drop query plan threshold for tests only --- .../java/org/tests/query/finder/TestCustomerFinder.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ebean-core/src/test/java/org/tests/query/finder/TestCustomerFinder.java b/ebean-core/src/test/java/org/tests/query/finder/TestCustomerFinder.java index 8446f9d5b..468b165bb 100644 --- a/ebean-core/src/test/java/org/tests/query/finder/TestCustomerFinder.java +++ b/ebean-core/src/test/java/org/tests/query/finder/TestCustomerFinder.java @@ -55,7 +55,6 @@ public class TestCustomerFinder extends BaseTestCase { assertThat(json1).contains("\"name\":\"txn.main\""); assertThat(json1).contains("\"name\":\"orm.Customer.findList\""); assertThat(json1).doesNotContain("\"sql\":\"select t0.id, t0.status, t0.name"); - } @Test @@ -85,7 +84,6 @@ public class TestCustomerFinder extends BaseTestCase { assertThat(customer.getName()).isEqualTo(customer1.getName()); assertThat(Customer.find.db().getName()).isEqualTo(DB.getDefault().getName()); - } @Test @@ -178,7 +176,7 @@ public class TestCustomerFinder extends BaseTestCase { // change default collect query plan threshold to 200 micros QueryPlanInit init0 = new QueryPlanInit(); init0.setAll(true); - init0.setThresholdMicros(200); + init0.setThresholdMicros(2); final List plans = server().getMetaInfoManager().queryPlanInit(init0); assertThat(plans.size()).isGreaterThan(1); @@ -188,7 +186,7 @@ public class TestCustomerFinder extends BaseTestCase { // change query plan threshold to 100 micros QueryPlanInit init = new QueryPlanInit(); init.setAll(true); - init.setThresholdMicros(100); + init.setThresholdMicros(1); final List appliedToPlans = server().getMetaInfoManager().queryPlanInit(init); assertThat(appliedToPlans.size()).isGreaterThan(4); From bb1275f4f95aa43c34b392791b419f2e673bb6dc Mon Sep 17 00:00:00 2001 From: rbygrave Date: Tue, 6 Apr 2021 21:13:59 +1200 Subject: [PATCH 37/52] #2217 - Inserting an entity bean is skipped with a String @Id property and no other properties set --- .../server/core/PersistRequestBean.java | 7 ++ .../server/deploy/BeanDescriptor.java | 2 +- .../server/persist/DefaultPersister.java | 2 +- .../cache/personinfo/PersonCacheEmail.java | 4 + .../tests/cache/personinfo/PersonOther.java | 73 +++++++++++++++++++ .../cache/personinfo/TestStringIdOnly.java | 30 ++++++++ 6 files changed, 116 insertions(+), 2 deletions(-) create mode 100644 ebean-core/src/test/java/org/tests/cache/personinfo/PersonOther.java create mode 100644 ebean-core/src/test/java/org/tests/cache/personinfo/TestStringIdOnly.java diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java b/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java index eb48fc2ef..01c27fa0f 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java @@ -1032,6 +1032,13 @@ public final class PersistRequestBean extends PersistRequest implements BeanP } } + /** + * Return if persist can be skipped on the reference only bean. + */ + public boolean isSkipReference() { + return intercept.isReference() || (Flags.isRecurse(flags) && beanDescriptor.referenceIdPropertyOnly(intercept)); + } + public boolean isReference() { return beanDescriptor.isReference(intercept); } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java index a2d902f13..2e0e00b65 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java @@ -3134,7 +3134,7 @@ public class BeanDescriptor implements BeanType, STreeType { return ebi.isReference() || referenceIdPropertyOnly(ebi); } - boolean referenceIdPropertyOnly(EntityBeanIntercept ebi) { + public boolean referenceIdPropertyOnly(EntityBeanIntercept ebi) { return idOnlyReference && ebi.hasIdOnly(idPropertyIndex); } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java b/ebean-core/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java index a7b21f0c8..935fbb6b8 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java @@ -447,7 +447,7 @@ public final class DefaultPersister implements Persister { public void insert(EntityBean bean, Transaction t) { PersistRequestBean req = createRequest(bean, t, PersistRequest.Type.INSERT); - if (req.isReference()) { + if (req.isSkipReference()) { // skip insert on reference bean return; } diff --git a/ebean-core/src/test/java/org/tests/cache/personinfo/PersonCacheEmail.java b/ebean-core/src/test/java/org/tests/cache/personinfo/PersonCacheEmail.java index 58ddea0a2..144253edf 100644 --- a/ebean-core/src/test/java/org/tests/cache/personinfo/PersonCacheEmail.java +++ b/ebean-core/src/test/java/org/tests/cache/personinfo/PersonCacheEmail.java @@ -25,6 +25,10 @@ public class PersonCacheEmail { this.email = email; } + public PersonCacheEmail(String id) { + this.id = id; + } + public String getId() { return id; } diff --git a/ebean-core/src/test/java/org/tests/cache/personinfo/PersonOther.java b/ebean-core/src/test/java/org/tests/cache/personinfo/PersonOther.java new file mode 100644 index 000000000..b4b505125 --- /dev/null +++ b/ebean-core/src/test/java/org/tests/cache/personinfo/PersonOther.java @@ -0,0 +1,73 @@ +package org.tests.cache.personinfo; + +import io.ebean.annotation.WhenCreated; +import io.ebean.annotation.WhenModified; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Version; +import javax.validation.constraints.Size; +import java.time.Instant; + +@Entity +public class PersonOther { + + @Id + @Size(max=128) + private String id; + + private String email; + + @WhenCreated + private Instant whenCreated; + + @WhenModified + private Instant whenModified; + + @Version + private long version; + + public PersonOther(String id) { + this.id = id; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public Instant getWhenCreated() { + return whenCreated; + } + + public void setWhenCreated(Instant whenCreated) { + this.whenCreated = whenCreated; + } + + public Instant getWhenModified() { + return whenModified; + } + + public void setWhenModified(Instant whenModified) { + this.whenModified = whenModified; + } + + public long getVersion() { + return version; + } + + public void setVersion(long version) { + this.version = version; + } +} diff --git a/ebean-core/src/test/java/org/tests/cache/personinfo/TestStringIdOnly.java b/ebean-core/src/test/java/org/tests/cache/personinfo/TestStringIdOnly.java new file mode 100644 index 000000000..6379491ff --- /dev/null +++ b/ebean-core/src/test/java/org/tests/cache/personinfo/TestStringIdOnly.java @@ -0,0 +1,30 @@ +package org.tests.cache.personinfo; + +import io.ebean.BaseTestCase; +import io.ebean.DB; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TestStringIdOnly extends BaseTestCase { + + @Test + public void insert() { + + PersonCacheEmail b0 = new PersonCacheEmail("IdOnly"); + DB.save(b0); + + PersonCacheEmail found = DB.find(PersonCacheEmail.class, b0.getId()); + assertThat(found).isNotNull(); + } + + @Test + public void insert_whenIdOnly() { + + PersonOther b0 = new PersonOther("IdOnly"); + DB.save(b0); + + PersonOther found = DB.find(PersonOther.class, b0.getId()); + assertThat(found).isNotNull(); + } +} From f7f383d8f303682368096a9fdb52da50bcaf7e50 Mon Sep 17 00:00:00 2001 From: rbygrave Date: Wed, 7 Apr 2021 13:38:34 +1200 Subject: [PATCH 38/52] No effective change - tidy tests TestRawSqlPositionedParams, TestRawSqlUnparsedQuery --- .../rawsql/TestRawSqlPositionedParams.java | 54 +++++++++---------- .../tests/rawsql/TestRawSqlUnparsedQuery.java | 29 +++++----- 2 files changed, 42 insertions(+), 41 deletions(-) diff --git a/ebean-core/src/test/java/org/tests/rawsql/TestRawSqlPositionedParams.java b/ebean-core/src/test/java/org/tests/rawsql/TestRawSqlPositionedParams.java index f1c3ef4fd..75d678fd6 100644 --- a/ebean-core/src/test/java/org/tests/rawsql/TestRawSqlPositionedParams.java +++ b/ebean-core/src/test/java/org/tests/rawsql/TestRawSqlPositionedParams.java @@ -1,38 +1,42 @@ package org.tests.rawsql; import io.ebean.BaseTestCase; -import io.ebean.Ebean; -import io.ebean.Query; +import io.ebean.DB; import io.ebean.RawSql; import io.ebean.RawSqlBuilder; +import org.junit.Test; import org.tests.model.basic.Customer; import org.tests.model.basic.ResetBasicData; -import org.junit.Test; import java.util.List; -import static org.junit.Assert.assertNotNull; +import static org.assertj.core.api.Assertions.assertThat; public class TestRawSqlPositionedParams extends BaseTestCase { + private static final RawSql RAWSQL_1 = RawSqlBuilder + .parse("select r.id, r.name from o_customer r where r.id >= ? and r.name like ?") + .create(); + + private static final RawSql RAW_SQL_2 = RawSqlBuilder + .unparsed("select r.id, r.name from o_customer r where r.id >= ? and r.name like ?") + .columnMapping("r.id", "id") + .columnMapping("r.name", "name") + .create(); + @Test public void test() { ResetBasicData.reset(); - RawSql rawSql = RawSqlBuilder - .parse("select r.id, r.name from o_customer r where r.id >= ? and r.name like ?") - .create(); + List list = DB.find(Customer.class) + .setRawSql(RAWSQL_1) + .setParameter(1) + .setParameter("R%") + .where().lt("id", 2001) + .findList(); - Query query = Ebean.find(Customer.class); - query.setRawSql(rawSql); - query.setParameter(1, 1); - query.setParameter(2, "R%"); - query.where().lt("id", 2001); - - List list = query.findList(); - - assertNotNull(list); + assertThat(list).isNotNull(); } @Test @@ -40,18 +44,12 @@ public class TestRawSqlPositionedParams extends BaseTestCase { ResetBasicData.reset(); - RawSql rawSql = RawSqlBuilder - .unparsed("select r.id, r.name from o_customer r where r.id >= ? and r.name like ?") - .columnMapping("r.id", "id") - .columnMapping("r.name", "name").create(); + List list = DB.find(Customer.class) + .setRawSql(RAW_SQL_2) + .setParameter(1) + .setParameter("R%") + .findList(); - Query query = Ebean.find(Customer.class); - query.setRawSql(rawSql); - query.setParameter(1, 1); - query.setParameter(2, "R%"); - - List list = query.findList(); - - assertNotNull(list); + assertThat(list).isNotNull(); } } diff --git a/ebean-core/src/test/java/org/tests/rawsql/TestRawSqlUnparsedQuery.java b/ebean-core/src/test/java/org/tests/rawsql/TestRawSqlUnparsedQuery.java index 8d900b15f..1e576f0b7 100644 --- a/ebean-core/src/test/java/org/tests/rawsql/TestRawSqlUnparsedQuery.java +++ b/ebean-core/src/test/java/org/tests/rawsql/TestRawSqlUnparsedQuery.java @@ -1,19 +1,25 @@ package org.tests.rawsql; import io.ebean.BaseTestCase; -import io.ebean.Ebean; -import io.ebean.Query; +import io.ebean.DB; import io.ebean.RawSql; import io.ebean.RawSqlBuilder; +import org.junit.Test; import org.tests.model.basic.Customer; import org.tests.model.basic.ResetBasicData; -import org.junit.Assert; -import org.junit.Test; import java.util.List; +import static org.assertj.core.api.Assertions.assertThat; + public class TestRawSqlUnparsedQuery extends BaseTestCase { + private static final RawSql rawSql = RawSqlBuilder + .unparsed("select r.id, r.name from o_customer r where r.id >= :a and r.name like :b") + .columnMapping("r.id", "id") + .columnMapping("r.name", "name") + .create(); + @Test public void testDoubleUnparsedQuery() { @@ -25,17 +31,14 @@ public class TestRawSqlUnparsedQuery extends BaseTestCase { } private static void test() { - RawSql rawSql = RawSqlBuilder - .unparsed("select r.id, r.name from o_customer r where r.id >= :a and r.name like :b") - .columnMapping("r.id", "id").columnMapping("r.name", "name").create(); - Query query = Ebean.find(Customer.class); - query.setRawSql(rawSql); - query.setParameter("a", 1); - query.setParameter("b", "R%"); + List list = DB.find(Customer.class) + .setRawSql(rawSql) + .setParameter("a", 1) + .setParameter("b", "R%") + .findList(); - List list = query.findList(); - Assert.assertNotNull(list); + assertThat(list).isNotNull(); } } From 59793f3c018e1291ec4bf6d869dba4117aa1ca7c Mon Sep 17 00:00:00 2001 From: rbygrave Date: Wed, 7 Apr 2021 15:50:04 +1200 Subject: [PATCH 39/52] Improve javadoc for Transaction#setGetGeneratedKeys More clearly document the limitation that we can't update beans that don't have id values --- .../src/main/java/io/ebean/Transaction.java | 30 ++++++------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/ebean-api/src/main/java/io/ebean/Transaction.java b/ebean-api/src/main/java/io/ebean/Transaction.java index d4918e84e..d3e918c0d 100644 --- a/ebean-api/src/main/java/io/ebean/Transaction.java +++ b/ebean-api/src/main/java/io/ebean/Transaction.java @@ -339,15 +339,12 @@ public interface Transaction extends AutoCloseable { * The batch is automatically flushed when it hits the batch size and also when we * execute queries or when we mix UpdateSql and CallableSql with save and delete of * beans. - *

*

* We use {@link #flush()} to explicitly flush the batch and we can use * {@link #setFlushOnQuery(boolean)} and {@link #setFlushOnMixed(boolean)} * to control the automatic flushing behaviour. - *

*

* Example: batch processing of CallableSql executing every 10 rows - *

* *
{@code
    *
@@ -392,14 +389,11 @@ public interface Transaction extends AutoCloseable {
    * 

* This only takes effect when batch mode on the transaction has not already meant that * JDBC batch mode is being used. - *

*

* This is useful when the single save() or delete() cascades. For example, inserting a 'master' cascades * and inserts a collection of 'detail' beans. The detail beans can be inserted using JDBC batch. - *

*

* This is effectively already turned on for all platforms apart from older Sql Server. - *

* * @param batchMode the batch mode to use per save(), insert(), update() or delete() * @see io.ebean.config.DatabaseConfig#setPersistBatchOnCascade(PersistBatch) @@ -422,15 +416,19 @@ public interface Transaction extends AutoCloseable { int getBatchSize(); /** - * Specify if you want batched inserts to use getGeneratedKeys. + * Specify if we want batched inserts to use getGeneratedKeys. *

* By default batched inserts will try to use getGeneratedKeys if it is * supported by the underlying jdbc driver and database. - *

*

- * You may want to turn getGeneratedKeys off when you are inserting a large - * number of objects and you don't care about getting back the ids. - *

+ * We want to turn off getGeneratedKeys when we are inserting a large + * number of objects and we don't care about getting back the ids. In this + * way we avoid the extra cost of getting back the generated id values + * from the database. + *

+ * Note that when we do turn off getGeneratedKeys then we have the limitation + * that after a bean has been inserted we are unable to then mutate the bean + * and update it in the same transaction as we have not obtained it's id value. */ void setGetGeneratedKeys(boolean getGeneratedKeys); @@ -449,13 +447,11 @@ public interface Transaction extends AutoCloseable { *

* If you want to execute both WITHOUT having the batch automatically flush * you need to call this with batchFlushOnMixed = false. - *

*

* Note that UpdateSql and CallableSql are ALWAYS executed first (before the * beans are executed). This is because the UpdateSql and CallableSql have * already been bound to their PreparedStatements. The beans on the other hand * have a 2 step process (delayed binding). - *

*/ void setFlushOnMixed(boolean batchFlushOnMixed); @@ -473,7 +469,6 @@ public interface Transaction extends AutoCloseable { *

* Calling this method with batchFlushOnQuery = false means that you can * execute a query and the batch will not be automatically flushed. - *

*/ void setFlushOnQuery(boolean batchFlushOnQuery); @@ -490,7 +485,6 @@ public interface Transaction extends AutoCloseable { * should be flushed prior to executing a query. *

* The default is for this to be true. - *

*/ boolean isFlushOnQuery(); @@ -507,7 +501,6 @@ public interface Transaction extends AutoCloseable { * flush the batch if you like. *

* Flushing occurs automatically when: - *

*
    *
  • the batch size is reached
  • *
  • A query is executed on the same transaction
  • @@ -533,11 +526,9 @@ public interface Transaction extends AutoCloseable { * commit() rollback() and end() methods on the Transaction should still be * used. Calling these methods on the Connection would be a big no no unless * you know what you are doing. - *

    *

    * Examples of when a developer may wish to use the connection directly are: * Savepoints, advanced CLOB BLOB use and advanced stored procedure calls. - *

    */ Connection getConnection(); @@ -545,17 +536,14 @@ public interface Transaction extends AutoCloseable { * Add table modification information to the TransactionEvent. *

    * Use this in conjunction with getConnection() and raw JDBC. - *

    *

    * This effectively informs Ebean of the data that has been changed by the * transaction and this information is normally automatically handled by Ebean * when you save entity beans or use UpdateSql etc. - *

    *

    * If you use raw JDBC then you can use this method to inform Ebean for the * tables that have been modified. Ebean uses this information to keep its * caches in synch and maintain text indexes. - *

    */ void addModification(String tableName, boolean inserts, boolean updates, boolean deletes); From 4ee8d647b7ee91dd1e1c0dada43e70c3355f9421 Mon Sep 17 00:00:00 2001 From: rbygrave Date: Wed, 7 Apr 2021 23:28:53 +1200 Subject: [PATCH 40/52] No effective change - tidy test TestCustomerFinder --- .../java/org/tests/query/finder/TestCustomerFinder.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ebean-core/src/test/java/org/tests/query/finder/TestCustomerFinder.java b/ebean-core/src/test/java/org/tests/query/finder/TestCustomerFinder.java index 468b165bb..eeefe42c2 100644 --- a/ebean-core/src/test/java/org/tests/query/finder/TestCustomerFinder.java +++ b/ebean-core/src/test/java/org/tests/query/finder/TestCustomerFinder.java @@ -31,7 +31,7 @@ public class TestCustomerFinder extends BaseTestCase { runQueries(); StringBuilder buffer0 = new StringBuilder(); - server().getMetaInfoManager() + DB.getDefault().getMetaInfoManager() .collectMetricsAsJson() .withHeader(false) .write(buffer0); @@ -45,7 +45,7 @@ public class TestCustomerFinder extends BaseTestCase { runQueries(); StringBuilder buffer1 = new StringBuilder(); - server().getMetaInfoManager() + DB.getDefault().getMetaInfoManager() .collectMetricsAsJson() .withHeader(false) .write(buffer1); @@ -193,7 +193,7 @@ public class TestCustomerFinder extends BaseTestCase { // run queries again runQueries(); - ServerMetrics metrics = server().getMetaInfoManager().collectMetrics(); + ServerMetrics metrics = DB.getDefault().getMetaInfoManager().collectMetrics(); List planStats = metrics.getQueryMetrics(); assertThat(planStats.size()).isGreaterThan(4); From 7f13ac9e5e7354954492ef23041435c5e4fa3b4d Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Thu, 8 Apr 2021 23:15:49 +1200 Subject: [PATCH 41/52] #2213 - Support autoPersistUpdates via TxScope --- ebean-api/pom.xml | 2 +- ebean-api/src/main/java/io/ebean/TxScope.java | 18 ++++++++ ebean-core/pom.xml | 2 +- .../java/io/ebeaninternal/api/ScopeTrans.java | 4 ++ .../TestTransparentPersist.java | 43 +++++++++++++++++-- .../src/test/resources/logback-test.xml | 4 +- 6 files changed, 65 insertions(+), 8 deletions(-) diff --git a/ebean-api/pom.xml b/ebean-api/pom.xml index 4fe1468ec..cb8c1d67e 100644 --- a/ebean-api/pom.xml +++ b/ebean-api/pom.xml @@ -50,7 +50,7 @@ io.ebean ebean-annotation - 6.15 + 7.0 diff --git a/ebean-api/src/main/java/io/ebean/TxScope.java b/ebean-api/src/main/java/io/ebean/TxScope.java index ee9fdca7b..59d9f6971 100644 --- a/ebean-api/src/main/java/io/ebean/TxScope.java +++ b/ebean-api/src/main/java/io/ebean/TxScope.java @@ -2,6 +2,7 @@ package io.ebean; import io.ebean.annotation.PersistBatch; import io.ebean.annotation.TxIsolation; +import io.ebean.annotation.TxOption; import io.ebean.annotation.TxType; import java.util.ArrayList; @@ -33,6 +34,8 @@ public final class TxScope { private TxIsolation isolation; + private TxOption autoPersistUpdates; + private PersistBatch batch; private PersistBatch batchOnCascade; @@ -123,6 +126,13 @@ public final class TxScope { + "] serverName[" + serverName + "] rollbackFor[" + rollbackFor + "] noRollbackFor[" + noRollbackFor + "]"; } + /** + * Return the AutoPersistUpdates mode as a nullable Boolean. + */ + public Boolean getAutoPersistUpdates() { + return autoPersistUpdates == null ? null : autoPersistUpdates.asBoolean(); + } + /** * Return true if PersistBatch has been set. */ @@ -176,6 +186,14 @@ public final class TxScope { return this; } + /** + * Set the autoPersistUpdates mode. + */ + public TxScope setAutoPersistUpdates(TxOption autoPersistUpdates) { + this.autoPersistUpdates = autoPersistUpdates; + return this; + } + /** * Return the transaction profile id. */ diff --git a/ebean-core/pom.xml b/ebean-core/pom.xml index 3652ba9a3..4b37905a9 100644 --- a/ebean-core/pom.xml +++ b/ebean-core/pom.xml @@ -302,7 +302,7 @@ io.ebean ebean-maven-plugin - 12.8.1 + 12.8.2-SNAPSHOT test diff --git a/ebean-core/src/main/java/io/ebeaninternal/api/ScopeTrans.java b/ebean-core/src/main/java/io/ebeaninternal/api/ScopeTrans.java index 5fbb03f25..631b6dfb8 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/api/ScopeTrans.java +++ b/ebean-core/src/main/java/io/ebeaninternal/api/ScopeTrans.java @@ -73,6 +73,10 @@ public class ScopeTrans { restoreBatchGeneratedKeys = transaction.getBatchGetGeneratedKeys(); restoreBatchFlushOnQuery = transaction.isFlushOnQuery(); } + Boolean autoPersistUpdates = txScope.getAutoPersistUpdates(); + if (autoPersistUpdates != null) { + transaction.setAutoPersistUpdates(autoPersistUpdates); + } if (txScope.isBatchSet()) { transaction.setBatchMode(txScope.isBatchMode()); } diff --git a/ebean-core/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java b/ebean-core/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java index 963cc1dcb..a169145eb 100644 --- a/ebean-core/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java +++ b/ebean-core/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java @@ -1,9 +1,7 @@ package org.tests.transparentpersist; -import io.ebean.BaseTestCase; -import io.ebean.DB; -import io.ebean.Database; -import io.ebean.Transaction; +import io.ebean.*; +import io.ebean.annotation.*; import io.ebeaninternal.api.SpiTransaction; import io.ebeantest.LoggedSql; import org.junit.Test; @@ -219,6 +217,43 @@ public class TestTransparentPersist extends BaseTestCase { DB.delete(Customer.class, c0.getId()); } + @Test + public void txScope_setAutoPersistUpdates() { + + EBasicVer b0 = new EBasicVer("txScopeUpdate"); + b0.save(); + + DB.execute(TxScope.required().setAutoPersistUpdates(TxOption.ON), () -> { + EBasicVer found = DB.find(EBasicVer.class, b0.getId()); + found.setName("mutable txScope bean"); + }); + + EBasicVer after = DB.find(EBasicVer.class, b0.getId()); + assertThat(after.getName()).isEqualTo("mutable txScope bean"); + + DB.delete(after); + } + +// @Test +// public void txn_setAutoPersistUpdates() { +// +// EBasicVer b0 = new EBasicVer("txn autoPersistUpdates ON"); +// b0.save(); +// +// performUpdate(b0); +// +// EBasicVer after = DB.find(EBasicVer.class, b0.getId()); +// assertThat(after.getName()).isEqualTo("mutated with autoPersistUpdates ON"); +// +// DB.delete(after); +// } +// +// @Transactional(autoPersistUpdates = TxOption.ON) +// private void performUpdate(EBasicVer b0) { +// EBasicVer found = DB.find(EBasicVer.class, b0.getId()); +// found.setName("mutated with autoPersistUpdates ON"); +// } + @Test public void simulate_transparentPersistence_forSimpleUpdate() { diff --git a/ebean-core/src/test/resources/logback-test.xml b/ebean-core/src/test/resources/logback-test.xml index 164ff73d3..1b8a60a9b 100644 --- a/ebean-core/src/test/resources/logback-test.xml +++ b/ebean-core/src/test/resources/logback-test.xml @@ -79,8 +79,8 @@ - - + + From 06802896ef0b9412c8fb153365dc1866c7fb588d Mon Sep 17 00:00:00 2001 From: rbygrave Date: Fri, 9 Apr 2021 16:17:58 +1200 Subject: [PATCH 42/52] #2213 Bump agent for @Transactional(autoPersistUpdates = TxOption.ON) --- ebean-bom/pom.xml | 4 +- ebean-core/pom.xml | 2 +- .../TestTransparentPersist.java | 38 +++++++++---------- ebean-ddl-generator/pom.xml | 2 +- kotlin-querybean-generator/pom.xml | 2 +- 5 files changed, 24 insertions(+), 24 deletions(-) diff --git a/ebean-bom/pom.xml b/ebean-bom/pom.xml index 401f6dbdf..7ab7bb0e9 100644 --- a/ebean-bom/pom.xml +++ b/ebean-bom/pom.xml @@ -18,8 +18,8 @@ 12.4.0 4.1 7.0 - 12.8.1 - 12.8.1 + 12.8.2 + 12.8.2 diff --git a/ebean-core/pom.xml b/ebean-core/pom.xml index 4b37905a9..2e403ef17 100644 --- a/ebean-core/pom.xml +++ b/ebean-core/pom.xml @@ -302,7 +302,7 @@ io.ebean ebean-maven-plugin - 12.8.2-SNAPSHOT + 12.8.2 test diff --git a/ebean-core/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java b/ebean-core/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java index a169145eb..75d767b3b 100644 --- a/ebean-core/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java +++ b/ebean-core/src/test/java/org/tests/transparentpersist/TestTransparentPersist.java @@ -234,25 +234,25 @@ public class TestTransparentPersist extends BaseTestCase { DB.delete(after); } -// @Test -// public void txn_setAutoPersistUpdates() { -// -// EBasicVer b0 = new EBasicVer("txn autoPersistUpdates ON"); -// b0.save(); -// -// performUpdate(b0); -// -// EBasicVer after = DB.find(EBasicVer.class, b0.getId()); -// assertThat(after.getName()).isEqualTo("mutated with autoPersistUpdates ON"); -// -// DB.delete(after); -// } -// -// @Transactional(autoPersistUpdates = TxOption.ON) -// private void performUpdate(EBasicVer b0) { -// EBasicVer found = DB.find(EBasicVer.class, b0.getId()); -// found.setName("mutated with autoPersistUpdates ON"); -// } + @Test + public void txn_setAutoPersistUpdates() { + + EBasicVer b0 = new EBasicVer("txn autoPersistUpdates ON"); + b0.save(); + + performUpdate(b0); + + EBasicVer after = DB.find(EBasicVer.class, b0.getId()); + assertThat(after.getName()).isEqualTo("mutated with autoPersistUpdates ON"); + + DB.delete(after); + } + + @Transactional(autoPersistUpdates = TxOption.ON) + private void performUpdate(EBasicVer b0) { + EBasicVer found = DB.find(EBasicVer.class, b0.getId()); + found.setName("mutated with autoPersistUpdates ON"); + } @Test public void simulate_transparentPersistence_forSimpleUpdate() { diff --git a/ebean-ddl-generator/pom.xml b/ebean-ddl-generator/pom.xml index 421166e46..edabcce4f 100644 --- a/ebean-ddl-generator/pom.xml +++ b/ebean-ddl-generator/pom.xml @@ -76,7 +76,7 @@ io.ebean ebean-maven-plugin - 12.8.1 + 12.8.2 test diff --git a/kotlin-querybean-generator/pom.xml b/kotlin-querybean-generator/pom.xml index 70432f360..40d38fe36 100644 --- a/kotlin-querybean-generator/pom.xml +++ b/kotlin-querybean-generator/pom.xml @@ -146,7 +146,7 @@ io.ebean ebean-maven-plugin - 12.8.1 + 12.8.2 test From fc174c8988f7eb47989c0d84b701e225919578e3 Mon Sep 17 00:00:00 2001 From: rbygrave Date: Fri, 9 Apr 2021 17:49:07 +1200 Subject: [PATCH 43/52] [maven-release-plugin] prepare release ebean-parent-12.8.2 --- ebean-api/pom.xml | 2 +- ebean-autotune/pom.xml | 6 +++--- ebean-bom/pom.xml | 30 +++++++++++++++--------------- ebean-core-type/pom.xml | 4 ++-- ebean-core/pom.xml | 10 +++++----- ebean-ddl-generator/pom.xml | 6 +++--- ebean-externalmapping-api/pom.xml | 2 +- ebean-externalmapping-xml/pom.xml | 10 +++++----- ebean-postgis/pom.xml | 6 +++--- ebean-querybean/pom.xml | 10 +++++----- ebean-redis/pom.xml | 12 ++++++------ ebean-test/pom.xml | 6 +++--- ebean/pom.xml | 8 ++++---- kotlin-querybean-generator/pom.xml | 8 ++++---- pom.xml | 4 ++-- querybean-generator/pom.xml | 2 +- 16 files changed, 63 insertions(+), 63 deletions(-) diff --git a/ebean-api/pom.xml b/ebean-api/pom.xml index cb8c1d67e..27641ad7e 100644 --- a/ebean-api/pom.xml +++ b/ebean-api/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.2-SNAPSHOT + 12.8.2 ebean api diff --git a/ebean-autotune/pom.xml b/ebean-autotune/pom.xml index 700861dd9..5d855889e 100644 --- a/ebean-autotune/pom.xml +++ b/ebean-autotune/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.2-SNAPSHOT + 12.8.2 @@ -14,7 +14,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-parent-12.8.0 + ebean-parent-12.8.2 ebean autotune @@ -26,7 +26,7 @@ io.ebean ebean-core - 12.8.2-SNAPSHOT + 12.8.2 provided diff --git a/ebean-bom/pom.xml b/ebean-bom/pom.xml index 7ab7bb0e9..37d9aba2c 100644 --- a/ebean-bom/pom.xml +++ b/ebean-bom/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.2-SNAPSHOT + 12.8.2 ebean bom @@ -81,88 +81,88 @@ io.ebean ebean - 12.8.2-SNAPSHOT + 12.8.2 io.ebean ebean-api - 12.8.2-SNAPSHOT + 12.8.2 io.ebean ebean-core - 12.8.2-SNAPSHOT + 12.8.2 io.ebean ebean-core-type - 12.8.2-SNAPSHOT + 12.8.2 io.ebean ebean-ddl-generator - 12.8.2-SNAPSHOT + 12.8.2 io.ebean ebean-externalmapping-api - 12.8.2-SNAPSHOT + 12.8.2 io.ebean ebean-externalmapping-xml - 12.8.2-SNAPSHOT + 12.8.2 io.ebean ebean-autotune - 12.8.2-SNAPSHOT + 12.8.2 io.ebean ebean-querybean - 12.8.2-SNAPSHOT + 12.8.2 io.ebean querybean-generator - 12.8.2-SNAPSHOT + 12.8.2 provided io.ebean kotlin-querybean-generator - 12.8.2-SNAPSHOT + 12.8.2 provided io.ebean ebean-test - 12.8.2-SNAPSHOT + 12.8.2 test io.ebean ebean-postgis - 12.8.2-SNAPSHOT + 12.8.2 io.ebean ebean-redis - 12.8.2-SNAPSHOT + 12.8.2 diff --git a/ebean-core-type/pom.xml b/ebean-core-type/pom.xml index be8b15507..f57b0876e 100644 --- a/ebean-core-type/pom.xml +++ b/ebean-core-type/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.2-SNAPSHOT + 12.8.2 ebean-core-type @@ -16,7 +16,7 @@ io.ebean ebean-api - 12.8.2-SNAPSHOT + 12.8.2 diff --git a/ebean-core/pom.xml b/ebean-core/pom.xml index 2e403ef17..cfd18d306 100644 --- a/ebean-core/pom.xml +++ b/ebean-core/pom.xml @@ -3,7 +3,7 @@ ebean-parent io.ebean - 12.8.2-SNAPSHOT + 12.8.2 ebean-core @@ -15,7 +15,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-parent-12.8.0 + ebean-parent-12.8.2 @@ -87,19 +87,19 @@ io.ebean ebean-api - 12.8.2-SNAPSHOT + 12.8.2 io.ebean ebean-core-type - 12.8.2-SNAPSHOT + 12.8.2 io.ebean ebean-externalmapping-api - 12.8.2-SNAPSHOT + 12.8.2 diff --git a/ebean-ddl-generator/pom.xml b/ebean-ddl-generator/pom.xml index edabcce4f..f6efd42b5 100644 --- a/ebean-ddl-generator/pom.xml +++ b/ebean-ddl-generator/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.2-SNAPSHOT + 12.8.2 ebean ddl generation @@ -28,14 +28,14 @@ io.ebean ebean-core-type - 12.8.2-SNAPSHOT + 12.8.2 provided io.ebean ebean-core - 12.8.2-SNAPSHOT + 12.8.2 provided diff --git a/ebean-externalmapping-api/pom.xml b/ebean-externalmapping-api/pom.xml index 32a98a767..a5fc4063a 100644 --- a/ebean-externalmapping-api/pom.xml +++ b/ebean-externalmapping-api/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.2-SNAPSHOT + 12.8.2 ebean external mapping api diff --git a/ebean-externalmapping-xml/pom.xml b/ebean-externalmapping-xml/pom.xml index 029f345fc..2b70daecf 100644 --- a/ebean-externalmapping-xml/pom.xml +++ b/ebean-externalmapping-xml/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.2-SNAPSHOT + 12.8.2 @@ -14,7 +14,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-parent-12.8.0 + ebean-parent-12.8.2 ebean external mapping xml @@ -33,7 +33,7 @@ io.ebean ebean-externalmapping-api - 12.8.2-SNAPSHOT + 12.8.2 @@ -59,14 +59,14 @@ io.ebean ebean-core - 12.8.2-SNAPSHOT + 12.8.2 test io.ebean ebean-ddl-generator - 12.8.2-SNAPSHOT + 12.8.2 test diff --git a/ebean-postgis/pom.xml b/ebean-postgis/pom.xml index 6528624f3..376235aef 100644 --- a/ebean-postgis/pom.xml +++ b/ebean-postgis/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.2-SNAPSHOT + 12.8.2 ebean postgis @@ -23,7 +23,7 @@ io.ebean ebean-core - 12.8.2-SNAPSHOT + 12.8.2 provided @@ -74,7 +74,7 @@ io.ebean ebean-test - 12.8.2-SNAPSHOT + 12.8.2 test diff --git a/ebean-querybean/pom.xml b/ebean-querybean/pom.xml index 86d02f68a..a213b74b7 100644 --- a/ebean-querybean/pom.xml +++ b/ebean-querybean/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.2-SNAPSHOT + 12.8.2 ebean querybean @@ -17,7 +17,7 @@ io.ebean ebean-core - 12.8.2-SNAPSHOT + 12.8.2 provided @@ -57,21 +57,21 @@ io.ebean ebean-ddl-generator - 12.8.2-SNAPSHOT + 12.8.2 test io.ebean querybean-generator - 12.8.2-SNAPSHOT + 12.8.2 test io.ebean ebean-test - 12.8.2-SNAPSHOT + 12.8.2 test diff --git a/ebean-redis/pom.xml b/ebean-redis/pom.xml index 1d3a74a49..35689ff88 100644 --- a/ebean-redis/pom.xml +++ b/ebean-redis/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.2-SNAPSHOT + 12.8.2 ebean-redis @@ -22,35 +22,35 @@ io.ebean ebean-api - 12.8.2-SNAPSHOT + 12.8.2 provided io.ebean ebean-core - 12.8.2-SNAPSHOT + 12.8.2 provided io.ebean ebean-querybean - 12.8.2-SNAPSHOT + 12.8.2 test io.ebean querybean-generator - 12.8.2-SNAPSHOT + 12.8.2 test io.ebean ebean-test - 12.8.2-SNAPSHOT + 12.8.2 test diff --git a/ebean-test/pom.xml b/ebean-test/pom.xml index 65e0d345c..0f9670dc6 100644 --- a/ebean-test/pom.xml +++ b/ebean-test/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.2-SNAPSHOT + 12.8.2 ebean test @@ -29,14 +29,14 @@ io.ebean ebean-core - 12.8.2-SNAPSHOT + 12.8.2 provided io.ebean ebean-ddl-generator - 12.8.2-SNAPSHOT + 12.8.2 diff --git a/ebean/pom.xml b/ebean/pom.xml index b293a20bc..fb3fce888 100644 --- a/ebean/pom.xml +++ b/ebean/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.2-SNAPSHOT + 12.8.2 ebean composite @@ -22,20 +22,20 @@ io.ebean ebean-api - 12.8.2-SNAPSHOT + 12.8.2 io.ebean ebean-core - 12.8.2-SNAPSHOT + 12.8.2 io.ebean ebean-querybean - 12.8.2-SNAPSHOT + 12.8.2 diff --git a/kotlin-querybean-generator/pom.xml b/kotlin-querybean-generator/pom.xml index 40d38fe36..c8a470b11 100644 --- a/kotlin-querybean-generator/pom.xml +++ b/kotlin-querybean-generator/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.2-SNAPSHOT + 12.8.2 kotlin querybean generator @@ -29,7 +29,7 @@ io.ebean ebean-querybean - 12.8.2-SNAPSHOT + 12.8.2 test @@ -43,7 +43,7 @@ io.ebean ebean-core - 12.8.2-SNAPSHOT + 12.8.2 test @@ -64,7 +64,7 @@ io.ebean ebean-ddl-generator - 12.8.2-SNAPSHOT + 12.8.2 test diff --git a/pom.xml b/pom.xml index a0ce632a3..87457c583 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean-parent - 12.8.2-SNAPSHOT + 12.8.2 pom ebean parent @@ -18,7 +18,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-parent-12.8.0 + ebean-parent-12.8.2 diff --git a/querybean-generator/pom.xml b/querybean-generator/pom.xml index be174f512..569bd963f 100644 --- a/querybean-generator/pom.xml +++ b/querybean-generator/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.2-SNAPSHOT + 12.8.2 querybean generator From 65b282a056492f096794e80189cff9d743558464 Mon Sep 17 00:00:00 2001 From: rbygrave Date: Fri, 9 Apr 2021 17:49:16 +1200 Subject: [PATCH 44/52] [maven-release-plugin] prepare for next development iteration --- ebean-api/pom.xml | 2 +- ebean-autotune/pom.xml | 6 +++--- ebean-bom/pom.xml | 30 +++++++++++++++--------------- ebean-core-type/pom.xml | 4 ++-- ebean-core/pom.xml | 10 +++++----- ebean-ddl-generator/pom.xml | 6 +++--- ebean-externalmapping-api/pom.xml | 2 +- ebean-externalmapping-xml/pom.xml | 10 +++++----- ebean-postgis/pom.xml | 6 +++--- ebean-querybean/pom.xml | 10 +++++----- ebean-redis/pom.xml | 12 ++++++------ ebean-test/pom.xml | 6 +++--- ebean/pom.xml | 8 ++++---- kotlin-querybean-generator/pom.xml | 8 ++++---- pom.xml | 4 ++-- querybean-generator/pom.xml | 2 +- 16 files changed, 63 insertions(+), 63 deletions(-) diff --git a/ebean-api/pom.xml b/ebean-api/pom.xml index 27641ad7e..92c01ccfb 100644 --- a/ebean-api/pom.xml +++ b/ebean-api/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.2 + 12.8.3-SNAPSHOT ebean api diff --git a/ebean-autotune/pom.xml b/ebean-autotune/pom.xml index 5d855889e..e3b77f33e 100644 --- a/ebean-autotune/pom.xml +++ b/ebean-autotune/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.2 + 12.8.3-SNAPSHOT @@ -14,7 +14,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-parent-12.8.2 + ebean-parent-12.8.0 ebean autotune @@ -26,7 +26,7 @@ io.ebean ebean-core - 12.8.2 + 12.8.3-SNAPSHOT provided diff --git a/ebean-bom/pom.xml b/ebean-bom/pom.xml index 37d9aba2c..488bce1cd 100644 --- a/ebean-bom/pom.xml +++ b/ebean-bom/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.2 + 12.8.3-SNAPSHOT ebean bom @@ -81,88 +81,88 @@ io.ebean ebean - 12.8.2 + 12.8.3-SNAPSHOT io.ebean ebean-api - 12.8.2 + 12.8.3-SNAPSHOT io.ebean ebean-core - 12.8.2 + 12.8.3-SNAPSHOT io.ebean ebean-core-type - 12.8.2 + 12.8.3-SNAPSHOT io.ebean ebean-ddl-generator - 12.8.2 + 12.8.3-SNAPSHOT io.ebean ebean-externalmapping-api - 12.8.2 + 12.8.3-SNAPSHOT io.ebean ebean-externalmapping-xml - 12.8.2 + 12.8.3-SNAPSHOT io.ebean ebean-autotune - 12.8.2 + 12.8.3-SNAPSHOT io.ebean ebean-querybean - 12.8.2 + 12.8.3-SNAPSHOT io.ebean querybean-generator - 12.8.2 + 12.8.3-SNAPSHOT provided io.ebean kotlin-querybean-generator - 12.8.2 + 12.8.3-SNAPSHOT provided io.ebean ebean-test - 12.8.2 + 12.8.3-SNAPSHOT test io.ebean ebean-postgis - 12.8.2 + 12.8.3-SNAPSHOT io.ebean ebean-redis - 12.8.2 + 12.8.3-SNAPSHOT diff --git a/ebean-core-type/pom.xml b/ebean-core-type/pom.xml index f57b0876e..41b6d4c6d 100644 --- a/ebean-core-type/pom.xml +++ b/ebean-core-type/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.2 + 12.8.3-SNAPSHOT ebean-core-type @@ -16,7 +16,7 @@ io.ebean ebean-api - 12.8.2 + 12.8.3-SNAPSHOT diff --git a/ebean-core/pom.xml b/ebean-core/pom.xml index cfd18d306..94820c06d 100644 --- a/ebean-core/pom.xml +++ b/ebean-core/pom.xml @@ -3,7 +3,7 @@ ebean-parent io.ebean - 12.8.2 + 12.8.3-SNAPSHOT ebean-core @@ -15,7 +15,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-parent-12.8.2 + ebean-parent-12.8.0 @@ -87,19 +87,19 @@ io.ebean ebean-api - 12.8.2 + 12.8.3-SNAPSHOT io.ebean ebean-core-type - 12.8.2 + 12.8.3-SNAPSHOT io.ebean ebean-externalmapping-api - 12.8.2 + 12.8.3-SNAPSHOT diff --git a/ebean-ddl-generator/pom.xml b/ebean-ddl-generator/pom.xml index f6efd42b5..77feacd15 100644 --- a/ebean-ddl-generator/pom.xml +++ b/ebean-ddl-generator/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.2 + 12.8.3-SNAPSHOT ebean ddl generation @@ -28,14 +28,14 @@ io.ebean ebean-core-type - 12.8.2 + 12.8.3-SNAPSHOT provided io.ebean ebean-core - 12.8.2 + 12.8.3-SNAPSHOT provided diff --git a/ebean-externalmapping-api/pom.xml b/ebean-externalmapping-api/pom.xml index a5fc4063a..79278c962 100644 --- a/ebean-externalmapping-api/pom.xml +++ b/ebean-externalmapping-api/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.2 + 12.8.3-SNAPSHOT ebean external mapping api diff --git a/ebean-externalmapping-xml/pom.xml b/ebean-externalmapping-xml/pom.xml index 2b70daecf..9c948ce06 100644 --- a/ebean-externalmapping-xml/pom.xml +++ b/ebean-externalmapping-xml/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.2 + 12.8.3-SNAPSHOT @@ -14,7 +14,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-parent-12.8.2 + ebean-parent-12.8.0 ebean external mapping xml @@ -33,7 +33,7 @@ io.ebean ebean-externalmapping-api - 12.8.2 + 12.8.3-SNAPSHOT @@ -59,14 +59,14 @@ io.ebean ebean-core - 12.8.2 + 12.8.3-SNAPSHOT test io.ebean ebean-ddl-generator - 12.8.2 + 12.8.3-SNAPSHOT test diff --git a/ebean-postgis/pom.xml b/ebean-postgis/pom.xml index 376235aef..8c841697c 100644 --- a/ebean-postgis/pom.xml +++ b/ebean-postgis/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.2 + 12.8.3-SNAPSHOT ebean postgis @@ -23,7 +23,7 @@ io.ebean ebean-core - 12.8.2 + 12.8.3-SNAPSHOT provided @@ -74,7 +74,7 @@ io.ebean ebean-test - 12.8.2 + 12.8.3-SNAPSHOT test diff --git a/ebean-querybean/pom.xml b/ebean-querybean/pom.xml index a213b74b7..798ccf976 100644 --- a/ebean-querybean/pom.xml +++ b/ebean-querybean/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.2 + 12.8.3-SNAPSHOT ebean querybean @@ -17,7 +17,7 @@ io.ebean ebean-core - 12.8.2 + 12.8.3-SNAPSHOT provided @@ -57,21 +57,21 @@ io.ebean ebean-ddl-generator - 12.8.2 + 12.8.3-SNAPSHOT test io.ebean querybean-generator - 12.8.2 + 12.8.3-SNAPSHOT test io.ebean ebean-test - 12.8.2 + 12.8.3-SNAPSHOT test diff --git a/ebean-redis/pom.xml b/ebean-redis/pom.xml index 35689ff88..793fab680 100644 --- a/ebean-redis/pom.xml +++ b/ebean-redis/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.2 + 12.8.3-SNAPSHOT ebean-redis @@ -22,35 +22,35 @@ io.ebean ebean-api - 12.8.2 + 12.8.3-SNAPSHOT provided io.ebean ebean-core - 12.8.2 + 12.8.3-SNAPSHOT provided io.ebean ebean-querybean - 12.8.2 + 12.8.3-SNAPSHOT test io.ebean querybean-generator - 12.8.2 + 12.8.3-SNAPSHOT test io.ebean ebean-test - 12.8.2 + 12.8.3-SNAPSHOT test diff --git a/ebean-test/pom.xml b/ebean-test/pom.xml index 0f9670dc6..d7f7c563a 100644 --- a/ebean-test/pom.xml +++ b/ebean-test/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.2 + 12.8.3-SNAPSHOT ebean test @@ -29,14 +29,14 @@ io.ebean ebean-core - 12.8.2 + 12.8.3-SNAPSHOT provided io.ebean ebean-ddl-generator - 12.8.2 + 12.8.3-SNAPSHOT diff --git a/ebean/pom.xml b/ebean/pom.xml index fb3fce888..8881210b6 100644 --- a/ebean/pom.xml +++ b/ebean/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.2 + 12.8.3-SNAPSHOT ebean composite @@ -22,20 +22,20 @@ io.ebean ebean-api - 12.8.2 + 12.8.3-SNAPSHOT io.ebean ebean-core - 12.8.2 + 12.8.3-SNAPSHOT io.ebean ebean-querybean - 12.8.2 + 12.8.3-SNAPSHOT diff --git a/kotlin-querybean-generator/pom.xml b/kotlin-querybean-generator/pom.xml index c8a470b11..4b957878f 100644 --- a/kotlin-querybean-generator/pom.xml +++ b/kotlin-querybean-generator/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.2 + 12.8.3-SNAPSHOT kotlin querybean generator @@ -29,7 +29,7 @@ io.ebean ebean-querybean - 12.8.2 + 12.8.3-SNAPSHOT test @@ -43,7 +43,7 @@ io.ebean ebean-core - 12.8.2 + 12.8.3-SNAPSHOT test @@ -64,7 +64,7 @@ io.ebean ebean-ddl-generator - 12.8.2 + 12.8.3-SNAPSHOT test diff --git a/pom.xml b/pom.xml index 87457c583..10f7d260d 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean-parent - 12.8.2 + 12.8.3-SNAPSHOT pom ebean parent @@ -18,7 +18,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-parent-12.8.2 + ebean-parent-12.8.0 diff --git a/querybean-generator/pom.xml b/querybean-generator/pom.xml index 569bd963f..5d6d29dc6 100644 --- a/querybean-generator/pom.xml +++ b/querybean-generator/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.2 + 12.8.3-SNAPSHOT querybean generator From 9d54b264ad536ed8564afe3d337af693de3e713d Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Mon, 19 Apr 2021 17:04:57 +1200 Subject: [PATCH 45/52] #2219 - Compile error with ZonedDateTime and query beans - type argument java.time.ZonedDateTime is not within bounds of type-variable D --- .../io/ebean/typequery/PZonedDateTime.java | 50 +++++++++++++++++++ .../test/java/org/example/domain/Contact.java | 29 +++++++---- .../test/java/org/querytest/QContactTest.java | 4 +- .../querybean/generator/PropertyTypeMap.java | 6 +-- .../querybean/generator/PropertyTypeMap.java | 6 +-- 5 files changed, 77 insertions(+), 18 deletions(-) create mode 100644 ebean-querybean/src/main/java/io/ebean/typequery/PZonedDateTime.java diff --git a/ebean-querybean/src/main/java/io/ebean/typequery/PZonedDateTime.java b/ebean-querybean/src/main/java/io/ebean/typequery/PZonedDateTime.java new file mode 100644 index 000000000..e233449ef --- /dev/null +++ b/ebean-querybean/src/main/java/io/ebean/typequery/PZonedDateTime.java @@ -0,0 +1,50 @@ +package io.ebean.typequery; + +import java.time.ZonedDateTime; + +/** + * ZonedDateTime property. + * + * @param the root query bean type + */ +public class PZonedDateTime extends PBaseCompareable { + + /** + * Construct with a property name and root instance. + * + * @param name property name + * @param root the root query bean instance + */ + public PZonedDateTime(String name, R root) { + super(name, root); + } + + /** + * Construct with additional path prefix. + */ + public PZonedDateTime(String name, R root, String prefix) { + super(name, root, prefix); + } + + /** + * Same as greater than. + * + * @param value the equal to bind value + * @return the root query bean instance + */ + public R after(ZonedDateTime value) { + expr().gt(_name, value); + return _root; + } + + /** + * Same as less than. + * + * @param value the equal to bind value + * @return the root query bean instance + */ + public R before(ZonedDateTime value) { + expr().lt(_name, value); + return _root; + } +} diff --git a/ebean-querybean/src/test/java/org/example/domain/Contact.java b/ebean-querybean/src/test/java/org/example/domain/Contact.java index 00035d80a..2b5fe9f53 100644 --- a/ebean-querybean/src/test/java/org/example/domain/Contact.java +++ b/ebean-querybean/src/test/java/org/example/domain/Contact.java @@ -3,6 +3,7 @@ package org.example.domain; import io.ebean.annotation.DbArray; import javax.persistence.*; +import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -11,33 +12,35 @@ import java.util.Map; * Contact entity bean. */ @Entity -@Table(name="be_contact") +@Table(name = "be_contact") public class Contact extends BaseModel { @DbArray - List phoneNumbers = new ArrayList(); + List phoneNumbers = new ArrayList<>(); - @Column(length=50) + @Column(length = 50) String firstName; - @Column(length=50) + @Column(length = 50) String lastName; - @Column(length=200) + @Column(length = 200) String email; - @Column(length=20) + @Column(length = 20) String phone; - @ManyToOne(optional=false) + ZonedDateTime zoneDateTime; + + @ManyToOne(optional = false) Customer customer; @OneToMany(mappedBy = "contact") List notes; @OneToMany(cascade = CascadeType.PERSIST) - @MapKey(name="key") - Map others; + @MapKey(name = "key") + Map others; /** * Default constructor. @@ -85,6 +88,14 @@ public class Contact extends BaseModel { this.phone = phone; } + public ZonedDateTime getZoneDateTime() { + return zoneDateTime; + } + + public void setZoneDateTime(ZonedDateTime zoneDateTime) { + this.zoneDateTime = zoneDateTime; + } + public Customer getCustomer() { return customer; } diff --git a/ebean-querybean/src/test/java/org/querytest/QContactTest.java b/ebean-querybean/src/test/java/org/querytest/QContactTest.java index ff37f789e..ef0d5a01b 100644 --- a/ebean-querybean/src/test/java/org/querytest/QContactTest.java +++ b/ebean-querybean/src/test/java/org/querytest/QContactTest.java @@ -3,13 +3,15 @@ package org.querytest; import org.example.domain.query.QContact; import org.junit.Test; +import java.time.ZonedDateTime; + public class QContactTest { @Test public void test_oneToManyMap() { - new QContact() .others.fetch() + .zoneDateTime.before(ZonedDateTime.now()) .findList(); } } diff --git a/kotlin-querybean-generator/src/main/java/io/ebean/querybean/generator/PropertyTypeMap.java b/kotlin-querybean-generator/src/main/java/io/ebean/querybean/generator/PropertyTypeMap.java index f5676f060..6afc8a6e3 100644 --- a/kotlin-querybean-generator/src/main/java/io/ebean/querybean/generator/PropertyTypeMap.java +++ b/kotlin-querybean-generator/src/main/java/io/ebean/querybean/generator/PropertyTypeMap.java @@ -25,10 +25,9 @@ class PropertyTypeMap { */ private final PropertyType dbJsonType = new PropertyType("PJson"); - private Map map = new HashMap<>(); + private final Map map = new HashMap<>(); PropertyTypeMap() { - map.put("boolean", new PropertyType("PBoolean")); map.put("short", new PropertyType("PShort")); map.put("int", new PropertyType("PInteger")); @@ -57,7 +56,6 @@ class PropertyTypeMap { addType(Locale.class); addType(File.class); addType(InetAddress.class); - map.put(URI.class.getName(), new PropertyType("PUri")); map.put(URL.class.getName(), new PropertyType("PUrl")); map.put(UUID.class.getName(), new PropertyType("PUuid")); @@ -74,7 +72,6 @@ class PropertyTypeMap { } private void addJava8Types() { - try { Class.forName("java.time.Instant"); } catch (ClassNotFoundException e) { @@ -94,6 +91,7 @@ class PropertyTypeMap { addType(java.time.YearMonth.class); addType(java.time.ZoneId.class); addType(java.time.ZoneOffset.class); + addType(java.time.ZonedDateTime.class); } private void addJodaTypes() { diff --git a/querybean-generator/src/main/java/io/ebean/querybean/generator/PropertyTypeMap.java b/querybean-generator/src/main/java/io/ebean/querybean/generator/PropertyTypeMap.java index b60a42cd7..fa35c72fa 100644 --- a/querybean-generator/src/main/java/io/ebean/querybean/generator/PropertyTypeMap.java +++ b/querybean-generator/src/main/java/io/ebean/querybean/generator/PropertyTypeMap.java @@ -25,10 +25,9 @@ class PropertyTypeMap { */ private final PropertyType dbJsonType = new PropertyType("PJson"); - private Map map = new HashMap<>(); + private final Map map = new HashMap<>(); PropertyTypeMap() { - map.put("boolean", new PropertyType("PBoolean")); map.put("short", new PropertyType("PShort")); map.put("int", new PropertyType("PInteger")); @@ -57,7 +56,6 @@ class PropertyTypeMap { map.put("java.lang.Class", new PropertyType("PClass")); addType(File.class); addType(InetAddress.class); - map.put(URI.class.getName(), new PropertyType("PUri")); map.put(URL.class.getName(), new PropertyType("PUrl")); map.put(UUID.class.getName(), new PropertyType("PUuid")); @@ -73,7 +71,6 @@ class PropertyTypeMap { } private void addJava8Types() { - try { Class.forName("java.time.Instant"); } catch (ClassNotFoundException e) { @@ -93,6 +90,7 @@ class PropertyTypeMap { addType(java.time.YearMonth.class); addType(java.time.ZoneId.class); addType(java.time.ZoneOffset.class); + addType(java.time.ZonedDateTime.class); } private void addJodaTypes() { From 2d719c5b37f18c8ba2cc2189fd459d73c858dcf7 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Mon, 19 Apr 2021 20:08:38 +1200 Subject: [PATCH 46/52] #2218 - @Encrypted columns on Oracle. The identifier alias starts with an underscore (ORA-00911) Change to use zx__ for the encryption column alias prefix rather than _e_ --- .../io/ebeaninternal/server/core/DtoQueryRequest.java | 7 +++++-- .../java/io/ebeaninternal/server/core/EncryptAlias.java | 8 ++++++++ .../java/io/ebeaninternal/server/deploy/BeanProperty.java | 5 ++++- .../io/ebeaninternal/server/core/DtoQueryRequestTest.java | 8 ++++---- 4 files changed, 21 insertions(+), 7 deletions(-) create mode 100644 ebean-core/src/main/java/io/ebeaninternal/server/core/EncryptAlias.java diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/core/DtoQueryRequest.java b/ebean-core/src/main/java/io/ebeaninternal/server/core/DtoQueryRequest.java index 120e98a27..2372ed7c3 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/core/DtoQueryRequest.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/core/DtoQueryRequest.java @@ -23,6 +23,9 @@ import java.util.function.Predicate; */ public final class DtoQueryRequest extends AbstractSqlQueryRequest { + private static final String ENC_PREFIX = EncryptAlias.PREFIX; + private static final String ENC_PREFIX_UPPER = EncryptAlias.PREFIX.toUpperCase(); + private final SpiDtoQuery query; private final DtoQueryEngine queryEngine; @@ -133,9 +136,9 @@ public final class DtoQueryRequest extends AbstractSqlQueryRequest { } static String parseColumn(String columnLabel) { - if (columnLabel.startsWith("_e_") || columnLabel.startsWith("_E_")) { + if (columnLabel.startsWith(ENC_PREFIX) || columnLabel.startsWith(ENC_PREFIX_UPPER)) { // encrypted column alias in the form _e__ - final int pos = columnLabel.indexOf("_", 3); + final int pos = columnLabel.indexOf("_", 4); if (pos > -1) { return columnLabel.substring(pos + 1); } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/core/EncryptAlias.java b/ebean-core/src/main/java/io/ebeaninternal/server/core/EncryptAlias.java new file mode 100644 index 000000000..e73a2a9e9 --- /dev/null +++ b/ebean-core/src/main/java/io/ebeaninternal/server/core/EncryptAlias.java @@ -0,0 +1,8 @@ +package io.ebeaninternal.server.core; + +/** + * Used to create column alias for encrypted columns. + */ +public interface EncryptAlias { + String PREFIX = "zx__"; +} diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java index d3b1f429b..270415a22 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java @@ -18,6 +18,7 @@ import io.ebeaninternal.api.SpiExpressionRequest; import io.ebeaninternal.api.SpiQuery; import io.ebeaninternal.api.json.SpiJsonReader; import io.ebeaninternal.api.json.SpiJsonWriter; +import io.ebeaninternal.server.core.EncryptAlias; import io.ebeaninternal.server.core.InternString; import io.ebeaninternal.server.deploy.generatedproperty.GeneratedProperty; import io.ebeaninternal.server.deploy.generatedproperty.GeneratedWhenCreated; @@ -65,6 +66,8 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty { private static final Logger logger = LoggerFactory.getLogger(BeanProperty.class); + private static final String ENC_PREFIX = " " + EncryptAlias.PREFIX; + /** * Flag to mark this is the id property. */ @@ -531,7 +534,7 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty { * Return the SQL for the column including decryption function and column alias. */ private String getDecryptSqlWithColumnAlias(String tableAlias) { - return dbEncryptFunction.getDecryptSql(tableAlias + "." + this.getDbColumn()) + " _e_" + tableAlias + "_" + this.getDbColumn(); + return dbEncryptFunction.getDecryptSql(tableAlias + "." + this.getDbColumn()) + ENC_PREFIX + tableAlias + "_" + this.getDbColumn(); } @Override diff --git a/ebean-core/src/test/java/io/ebeaninternal/server/core/DtoQueryRequestTest.java b/ebean-core/src/test/java/io/ebeaninternal/server/core/DtoQueryRequestTest.java index f8bdd66bd..4b85f18f1 100644 --- a/ebean-core/src/test/java/io/ebeaninternal/server/core/DtoQueryRequestTest.java +++ b/ebean-core/src/test/java/io/ebeaninternal/server/core/DtoQueryRequestTest.java @@ -11,10 +11,10 @@ public class DtoQueryRequestTest { public void testParse() { assertEquals("foo", DtoQueryRequest.parseColumn("foo")); - assertEquals("bar", DtoQueryRequest.parseColumn("_e_t0_bar")); - assertEquals("BAR", DtoQueryRequest.parseColumn("_E_T0_BAR")); - assertEquals("baz", DtoQueryRequest.parseColumn("_e_t42_baz")); - assertEquals("BAZ", DtoQueryRequest.parseColumn("_E_T42_BAZ")); + assertEquals("bar", DtoQueryRequest.parseColumn("zx__t0_bar")); + assertEquals("BAR", DtoQueryRequest.parseColumn("ZX__T0_BAR")); + assertEquals("baz", DtoQueryRequest.parseColumn("zx__t42_baz")); + assertEquals("BAZ", DtoQueryRequest.parseColumn("ZX__T42_BAZ")); assertEquals("e_t42_nope", DtoQueryRequest.parseColumn("e_t42_nope")); assertEquals("_f_t42_nope", DtoQueryRequest.parseColumn("_f_t42_nope")); From bb6ff866c76e068fd6030189e1df01f834b442d1 Mon Sep 17 00:00:00 2001 From: rbygrave Date: Mon, 19 Apr 2021 21:37:05 +1200 Subject: [PATCH 47/52] #2220 - DDL generation of nullable columns expected with nullable Embedded containing non null properties --- ebean-core/pom.xml | 2 +- .../server/deploy/BeanPropertyAssocManySqlHelp.java | 6 +++--- .../server/deploy/visitor/BaseTablePropertyVisitor.java | 6 ++++-- .../server/deploy/visitor/BeanPropertyVisitor.java | 4 ++-- .../server/deploy/visitor/VisitProperties.java | 2 +- .../java/org/tests/model/embedded/EEmbDatePeriod.java | 4 ++++ .../model/build/ModelBuildPropertyVisitor.java | 8 ++++---- 7 files changed, 19 insertions(+), 13 deletions(-) diff --git a/ebean-core/pom.xml b/ebean-core/pom.xml index 94820c06d..c07b3062c 100644 --- a/ebean-core/pom.xml +++ b/ebean-core/pom.xml @@ -72,7 +72,7 @@ io.ebean ebean-ddl-generator - 12.6.1 + 12.8.4a test diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocManySqlHelp.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocManySqlHelp.java index 398713a18..06a2a2145 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocManySqlHelp.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocManySqlHelp.java @@ -81,18 +81,18 @@ class BeanPropertyAssocManySqlHelp { @Override public void visitOneImported(BeanPropertyAssocOne p) { - + // do nothing } @Override - public void visitScalar(BeanProperty p) { + public void visitScalar(BeanProperty p, boolean allowNonNull) { sb.append(",").append(p.getDbColumn()); colCount++; } @Override public void visitEnd() { - + // do nothing } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/visitor/BaseTablePropertyVisitor.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/visitor/BaseTablePropertyVisitor.java index cc23a5c1f..e6741d12a 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/visitor/BaseTablePropertyVisitor.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/visitor/BaseTablePropertyVisitor.java @@ -44,9 +44,11 @@ public abstract class BaseTablePropertyVisitor implements BeanPropertyVisitor { public abstract void visitOneImported(BeanPropertyAssocOne p); /** - * Override this method for normal scalar property. + * Override this method for normal scalar property. With allowNonNull + * used with properties of Embedded beans that can only be Nonnull when + * the Embedded bean is Nonnull. */ @Override - public abstract void visitScalar(BeanProperty p); + public abstract void visitScalar(BeanProperty p, boolean allowNonNull); } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/visitor/BeanPropertyVisitor.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/visitor/BeanPropertyVisitor.java index 1cadc2b1b..dd0dd7c6e 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/visitor/BeanPropertyVisitor.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/visitor/BeanPropertyVisitor.java @@ -40,8 +40,8 @@ public interface BeanPropertyVisitor { void visitEmbeddedScalar(BeanProperty p, BeanPropertyAssocOne embedded); /** - * Visit a scalar property. + * Visit a scalar property specify allowing non-null (e.g. embedded bean scalar properties). */ - void visitScalar(BeanProperty p); + void visitScalar(BeanProperty p, boolean allowNonNull); } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/visitor/VisitProperties.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/visitor/VisitProperties.java index deab1104c..5363b0add 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/visitor/VisitProperties.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/visitor/VisitProperties.java @@ -72,7 +72,7 @@ public class VisitProperties { } else { // simple scalar type - pv.visitScalar(p); + pv.visitScalar(p, true); } } diff --git a/ebean-core/src/test/java/org/tests/model/embedded/EEmbDatePeriod.java b/ebean-core/src/test/java/org/tests/model/embedded/EEmbDatePeriod.java index 50cb225a3..2542a066b 100644 --- a/ebean-core/src/test/java/org/tests/model/embedded/EEmbDatePeriod.java +++ b/ebean-core/src/test/java/org/tests/model/embedded/EEmbDatePeriod.java @@ -1,12 +1,16 @@ package org.tests.model.embedded; +import io.ebean.annotation.NotNull; + import javax.persistence.Embeddable; import java.util.Date; @Embeddable public class EEmbDatePeriod { + @NotNull Date date1; + @NotNull Date date2; public Date getDate1() { diff --git a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildPropertyVisitor.java b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildPropertyVisitor.java index 7b13cf581..3a7457a56 100644 --- a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildPropertyVisitor.java +++ b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildPropertyVisitor.java @@ -175,7 +175,8 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor { if (p instanceof BeanPropertyAssocOne) { visitOneImported((BeanPropertyAssocOne)p); } else { - visitScalar(p); + // only allow Nonnull if embedded is Nonnull + visitScalar(p, !embedded.isNullable()); } if (embedded.isId()) { // compound primary key @@ -259,8 +260,7 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor { } @Override - public void visitScalar(BeanProperty p) { - + public void visitScalar(BeanProperty p, boolean allowNonNull) { if (p.isSecondaryTable()) { lastColumn = null; return; @@ -292,7 +292,7 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor { } } else { col.setDefaultValue(p.getDbColumnDefault()); - if (!p.isNullable() || p.isDDLNotNull()) { + if (allowNonNull && (!p.isNullable() || p.isDDLNotNull())) { col.setNotnull(true); } } From 9eb54da2dc29e03e495abedd84a97590ece3bc6e Mon Sep 17 00:00:00 2001 From: rbygrave Date: Mon, 19 Apr 2021 21:40:07 +1200 Subject: [PATCH 48/52] [maven-release-plugin] prepare release ebean-parent-12.8.3 --- ebean-api/pom.xml | 2 +- ebean-autotune/pom.xml | 6 +++--- ebean-bom/pom.xml | 30 +++++++++++++++--------------- ebean-core-type/pom.xml | 4 ++-- ebean-core/pom.xml | 10 +++++----- ebean-ddl-generator/pom.xml | 6 +++--- ebean-externalmapping-api/pom.xml | 2 +- ebean-externalmapping-xml/pom.xml | 10 +++++----- ebean-postgis/pom.xml | 6 +++--- ebean-querybean/pom.xml | 10 +++++----- ebean-redis/pom.xml | 12 ++++++------ ebean-test/pom.xml | 6 +++--- ebean/pom.xml | 8 ++++---- kotlin-querybean-generator/pom.xml | 8 ++++---- pom.xml | 4 ++-- querybean-generator/pom.xml | 2 +- 16 files changed, 63 insertions(+), 63 deletions(-) diff --git a/ebean-api/pom.xml b/ebean-api/pom.xml index 92c01ccfb..1dfb09ea5 100644 --- a/ebean-api/pom.xml +++ b/ebean-api/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.3-SNAPSHOT + 12.8.3 ebean api diff --git a/ebean-autotune/pom.xml b/ebean-autotune/pom.xml index e3b77f33e..d02ceb219 100644 --- a/ebean-autotune/pom.xml +++ b/ebean-autotune/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.3-SNAPSHOT + 12.8.3 @@ -14,7 +14,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-parent-12.8.0 + ebean-parent-12.8.3 ebean autotune @@ -26,7 +26,7 @@ io.ebean ebean-core - 12.8.3-SNAPSHOT + 12.8.3 provided diff --git a/ebean-bom/pom.xml b/ebean-bom/pom.xml index 488bce1cd..01aff5126 100644 --- a/ebean-bom/pom.xml +++ b/ebean-bom/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.3-SNAPSHOT + 12.8.3 ebean bom @@ -81,88 +81,88 @@ io.ebean ebean - 12.8.3-SNAPSHOT + 12.8.3 io.ebean ebean-api - 12.8.3-SNAPSHOT + 12.8.3 io.ebean ebean-core - 12.8.3-SNAPSHOT + 12.8.3 io.ebean ebean-core-type - 12.8.3-SNAPSHOT + 12.8.3 io.ebean ebean-ddl-generator - 12.8.3-SNAPSHOT + 12.8.3 io.ebean ebean-externalmapping-api - 12.8.3-SNAPSHOT + 12.8.3 io.ebean ebean-externalmapping-xml - 12.8.3-SNAPSHOT + 12.8.3 io.ebean ebean-autotune - 12.8.3-SNAPSHOT + 12.8.3 io.ebean ebean-querybean - 12.8.3-SNAPSHOT + 12.8.3 io.ebean querybean-generator - 12.8.3-SNAPSHOT + 12.8.3 provided io.ebean kotlin-querybean-generator - 12.8.3-SNAPSHOT + 12.8.3 provided io.ebean ebean-test - 12.8.3-SNAPSHOT + 12.8.3 test io.ebean ebean-postgis - 12.8.3-SNAPSHOT + 12.8.3 io.ebean ebean-redis - 12.8.3-SNAPSHOT + 12.8.3 diff --git a/ebean-core-type/pom.xml b/ebean-core-type/pom.xml index 41b6d4c6d..1bee819fd 100644 --- a/ebean-core-type/pom.xml +++ b/ebean-core-type/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.3-SNAPSHOT + 12.8.3 ebean-core-type @@ -16,7 +16,7 @@ io.ebean ebean-api - 12.8.3-SNAPSHOT + 12.8.3 diff --git a/ebean-core/pom.xml b/ebean-core/pom.xml index c07b3062c..c395097e6 100644 --- a/ebean-core/pom.xml +++ b/ebean-core/pom.xml @@ -3,7 +3,7 @@ ebean-parent io.ebean - 12.8.3-SNAPSHOT + 12.8.3 ebean-core @@ -15,7 +15,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-parent-12.8.0 + ebean-parent-12.8.3 @@ -87,19 +87,19 @@ io.ebean ebean-api - 12.8.3-SNAPSHOT + 12.8.3 io.ebean ebean-core-type - 12.8.3-SNAPSHOT + 12.8.3 io.ebean ebean-externalmapping-api - 12.8.3-SNAPSHOT + 12.8.3 diff --git a/ebean-ddl-generator/pom.xml b/ebean-ddl-generator/pom.xml index 77feacd15..959230160 100644 --- a/ebean-ddl-generator/pom.xml +++ b/ebean-ddl-generator/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.3-SNAPSHOT + 12.8.3 ebean ddl generation @@ -28,14 +28,14 @@ io.ebean ebean-core-type - 12.8.3-SNAPSHOT + 12.8.3 provided io.ebean ebean-core - 12.8.3-SNAPSHOT + 12.8.3 provided diff --git a/ebean-externalmapping-api/pom.xml b/ebean-externalmapping-api/pom.xml index 79278c962..3031bebb8 100644 --- a/ebean-externalmapping-api/pom.xml +++ b/ebean-externalmapping-api/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.3-SNAPSHOT + 12.8.3 ebean external mapping api diff --git a/ebean-externalmapping-xml/pom.xml b/ebean-externalmapping-xml/pom.xml index 9c948ce06..311a6f776 100644 --- a/ebean-externalmapping-xml/pom.xml +++ b/ebean-externalmapping-xml/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.3-SNAPSHOT + 12.8.3 @@ -14,7 +14,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-parent-12.8.0 + ebean-parent-12.8.3 ebean external mapping xml @@ -33,7 +33,7 @@ io.ebean ebean-externalmapping-api - 12.8.3-SNAPSHOT + 12.8.3 @@ -59,14 +59,14 @@ io.ebean ebean-core - 12.8.3-SNAPSHOT + 12.8.3 test io.ebean ebean-ddl-generator - 12.8.3-SNAPSHOT + 12.8.3 test diff --git a/ebean-postgis/pom.xml b/ebean-postgis/pom.xml index 8c841697c..a254289cf 100644 --- a/ebean-postgis/pom.xml +++ b/ebean-postgis/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.3-SNAPSHOT + 12.8.3 ebean postgis @@ -23,7 +23,7 @@ io.ebean ebean-core - 12.8.3-SNAPSHOT + 12.8.3 provided @@ -74,7 +74,7 @@ io.ebean ebean-test - 12.8.3-SNAPSHOT + 12.8.3 test diff --git a/ebean-querybean/pom.xml b/ebean-querybean/pom.xml index 798ccf976..252e28c54 100644 --- a/ebean-querybean/pom.xml +++ b/ebean-querybean/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.3-SNAPSHOT + 12.8.3 ebean querybean @@ -17,7 +17,7 @@ io.ebean ebean-core - 12.8.3-SNAPSHOT + 12.8.3 provided @@ -57,21 +57,21 @@ io.ebean ebean-ddl-generator - 12.8.3-SNAPSHOT + 12.8.3 test io.ebean querybean-generator - 12.8.3-SNAPSHOT + 12.8.3 test io.ebean ebean-test - 12.8.3-SNAPSHOT + 12.8.3 test diff --git a/ebean-redis/pom.xml b/ebean-redis/pom.xml index 793fab680..c238e7c7d 100644 --- a/ebean-redis/pom.xml +++ b/ebean-redis/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.3-SNAPSHOT + 12.8.3 ebean-redis @@ -22,35 +22,35 @@ io.ebean ebean-api - 12.8.3-SNAPSHOT + 12.8.3 provided io.ebean ebean-core - 12.8.3-SNAPSHOT + 12.8.3 provided io.ebean ebean-querybean - 12.8.3-SNAPSHOT + 12.8.3 test io.ebean querybean-generator - 12.8.3-SNAPSHOT + 12.8.3 test io.ebean ebean-test - 12.8.3-SNAPSHOT + 12.8.3 test diff --git a/ebean-test/pom.xml b/ebean-test/pom.xml index d7f7c563a..9b13477da 100644 --- a/ebean-test/pom.xml +++ b/ebean-test/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.3-SNAPSHOT + 12.8.3 ebean test @@ -29,14 +29,14 @@ io.ebean ebean-core - 12.8.3-SNAPSHOT + 12.8.3 provided io.ebean ebean-ddl-generator - 12.8.3-SNAPSHOT + 12.8.3 diff --git a/ebean/pom.xml b/ebean/pom.xml index 8881210b6..ddd0b9574 100644 --- a/ebean/pom.xml +++ b/ebean/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.3-SNAPSHOT + 12.8.3 ebean composite @@ -22,20 +22,20 @@ io.ebean ebean-api - 12.8.3-SNAPSHOT + 12.8.3 io.ebean ebean-core - 12.8.3-SNAPSHOT + 12.8.3 io.ebean ebean-querybean - 12.8.3-SNAPSHOT + 12.8.3 diff --git a/kotlin-querybean-generator/pom.xml b/kotlin-querybean-generator/pom.xml index 4b957878f..545078f3c 100644 --- a/kotlin-querybean-generator/pom.xml +++ b/kotlin-querybean-generator/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.3-SNAPSHOT + 12.8.3 kotlin querybean generator @@ -29,7 +29,7 @@ io.ebean ebean-querybean - 12.8.3-SNAPSHOT + 12.8.3 test @@ -43,7 +43,7 @@ io.ebean ebean-core - 12.8.3-SNAPSHOT + 12.8.3 test @@ -64,7 +64,7 @@ io.ebean ebean-ddl-generator - 12.8.3-SNAPSHOT + 12.8.3 test diff --git a/pom.xml b/pom.xml index 10f7d260d..61571ff85 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean-parent - 12.8.3-SNAPSHOT + 12.8.3 pom ebean parent @@ -18,7 +18,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-parent-12.8.0 + ebean-parent-12.8.3 diff --git a/querybean-generator/pom.xml b/querybean-generator/pom.xml index 5d6d29dc6..996feff79 100644 --- a/querybean-generator/pom.xml +++ b/querybean-generator/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.3-SNAPSHOT + 12.8.3 querybean generator From 5e893dd2ade2aac9c74ecb7234750bb859401fed Mon Sep 17 00:00:00 2001 From: rbygrave Date: Mon, 19 Apr 2021 21:40:16 +1200 Subject: [PATCH 49/52] [maven-release-plugin] prepare for next development iteration --- ebean-api/pom.xml | 2 +- ebean-autotune/pom.xml | 6 +++--- ebean-bom/pom.xml | 30 +++++++++++++++--------------- ebean-core-type/pom.xml | 4 ++-- ebean-core/pom.xml | 10 +++++----- ebean-ddl-generator/pom.xml | 6 +++--- ebean-externalmapping-api/pom.xml | 2 +- ebean-externalmapping-xml/pom.xml | 10 +++++----- ebean-postgis/pom.xml | 6 +++--- ebean-querybean/pom.xml | 10 +++++----- ebean-redis/pom.xml | 12 ++++++------ ebean-test/pom.xml | 6 +++--- ebean/pom.xml | 8 ++++---- kotlin-querybean-generator/pom.xml | 8 ++++---- pom.xml | 4 ++-- querybean-generator/pom.xml | 2 +- 16 files changed, 63 insertions(+), 63 deletions(-) diff --git a/ebean-api/pom.xml b/ebean-api/pom.xml index 1dfb09ea5..380438cc2 100644 --- a/ebean-api/pom.xml +++ b/ebean-api/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.3 + 12.8.4-SNAPSHOT ebean api diff --git a/ebean-autotune/pom.xml b/ebean-autotune/pom.xml index d02ceb219..590680c8a 100644 --- a/ebean-autotune/pom.xml +++ b/ebean-autotune/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.3 + 12.8.4-SNAPSHOT @@ -14,7 +14,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-parent-12.8.3 + ebean-parent-12.8.0 ebean autotune @@ -26,7 +26,7 @@ io.ebean ebean-core - 12.8.3 + 12.8.4-SNAPSHOT provided diff --git a/ebean-bom/pom.xml b/ebean-bom/pom.xml index 01aff5126..aaa2b5961 100644 --- a/ebean-bom/pom.xml +++ b/ebean-bom/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.3 + 12.8.4-SNAPSHOT ebean bom @@ -81,88 +81,88 @@ io.ebean ebean - 12.8.3 + 12.8.4-SNAPSHOT io.ebean ebean-api - 12.8.3 + 12.8.4-SNAPSHOT io.ebean ebean-core - 12.8.3 + 12.8.4-SNAPSHOT io.ebean ebean-core-type - 12.8.3 + 12.8.4-SNAPSHOT io.ebean ebean-ddl-generator - 12.8.3 + 12.8.4-SNAPSHOT io.ebean ebean-externalmapping-api - 12.8.3 + 12.8.4-SNAPSHOT io.ebean ebean-externalmapping-xml - 12.8.3 + 12.8.4-SNAPSHOT io.ebean ebean-autotune - 12.8.3 + 12.8.4-SNAPSHOT io.ebean ebean-querybean - 12.8.3 + 12.8.4-SNAPSHOT io.ebean querybean-generator - 12.8.3 + 12.8.4-SNAPSHOT provided io.ebean kotlin-querybean-generator - 12.8.3 + 12.8.4-SNAPSHOT provided io.ebean ebean-test - 12.8.3 + 12.8.4-SNAPSHOT test io.ebean ebean-postgis - 12.8.3 + 12.8.4-SNAPSHOT io.ebean ebean-redis - 12.8.3 + 12.8.4-SNAPSHOT diff --git a/ebean-core-type/pom.xml b/ebean-core-type/pom.xml index 1bee819fd..04497471c 100644 --- a/ebean-core-type/pom.xml +++ b/ebean-core-type/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.3 + 12.8.4-SNAPSHOT ebean-core-type @@ -16,7 +16,7 @@ io.ebean ebean-api - 12.8.3 + 12.8.4-SNAPSHOT diff --git a/ebean-core/pom.xml b/ebean-core/pom.xml index c395097e6..dbde9f167 100644 --- a/ebean-core/pom.xml +++ b/ebean-core/pom.xml @@ -3,7 +3,7 @@ ebean-parent io.ebean - 12.8.3 + 12.8.4-SNAPSHOT ebean-core @@ -15,7 +15,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-parent-12.8.3 + ebean-parent-12.8.0 @@ -87,19 +87,19 @@ io.ebean ebean-api - 12.8.3 + 12.8.4-SNAPSHOT io.ebean ebean-core-type - 12.8.3 + 12.8.4-SNAPSHOT io.ebean ebean-externalmapping-api - 12.8.3 + 12.8.4-SNAPSHOT diff --git a/ebean-ddl-generator/pom.xml b/ebean-ddl-generator/pom.xml index 959230160..f94924830 100644 --- a/ebean-ddl-generator/pom.xml +++ b/ebean-ddl-generator/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.3 + 12.8.4-SNAPSHOT ebean ddl generation @@ -28,14 +28,14 @@ io.ebean ebean-core-type - 12.8.3 + 12.8.4-SNAPSHOT provided io.ebean ebean-core - 12.8.3 + 12.8.4-SNAPSHOT provided diff --git a/ebean-externalmapping-api/pom.xml b/ebean-externalmapping-api/pom.xml index 3031bebb8..079eebec9 100644 --- a/ebean-externalmapping-api/pom.xml +++ b/ebean-externalmapping-api/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.3 + 12.8.4-SNAPSHOT ebean external mapping api diff --git a/ebean-externalmapping-xml/pom.xml b/ebean-externalmapping-xml/pom.xml index 311a6f776..bcf9f10ff 100644 --- a/ebean-externalmapping-xml/pom.xml +++ b/ebean-externalmapping-xml/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.3 + 12.8.4-SNAPSHOT @@ -14,7 +14,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-parent-12.8.3 + ebean-parent-12.8.0 ebean external mapping xml @@ -33,7 +33,7 @@ io.ebean ebean-externalmapping-api - 12.8.3 + 12.8.4-SNAPSHOT @@ -59,14 +59,14 @@ io.ebean ebean-core - 12.8.3 + 12.8.4-SNAPSHOT test io.ebean ebean-ddl-generator - 12.8.3 + 12.8.4-SNAPSHOT test diff --git a/ebean-postgis/pom.xml b/ebean-postgis/pom.xml index a254289cf..4e1b6063b 100644 --- a/ebean-postgis/pom.xml +++ b/ebean-postgis/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.3 + 12.8.4-SNAPSHOT ebean postgis @@ -23,7 +23,7 @@ io.ebean ebean-core - 12.8.3 + 12.8.4-SNAPSHOT provided @@ -74,7 +74,7 @@ io.ebean ebean-test - 12.8.3 + 12.8.4-SNAPSHOT test diff --git a/ebean-querybean/pom.xml b/ebean-querybean/pom.xml index 252e28c54..ff6dd8754 100644 --- a/ebean-querybean/pom.xml +++ b/ebean-querybean/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.3 + 12.8.4-SNAPSHOT ebean querybean @@ -17,7 +17,7 @@ io.ebean ebean-core - 12.8.3 + 12.8.4-SNAPSHOT provided @@ -57,21 +57,21 @@ io.ebean ebean-ddl-generator - 12.8.3 + 12.8.4-SNAPSHOT test io.ebean querybean-generator - 12.8.3 + 12.8.4-SNAPSHOT test io.ebean ebean-test - 12.8.3 + 12.8.4-SNAPSHOT test diff --git a/ebean-redis/pom.xml b/ebean-redis/pom.xml index c238e7c7d..01062abf1 100644 --- a/ebean-redis/pom.xml +++ b/ebean-redis/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.3 + 12.8.4-SNAPSHOT ebean-redis @@ -22,35 +22,35 @@ io.ebean ebean-api - 12.8.3 + 12.8.4-SNAPSHOT provided io.ebean ebean-core - 12.8.3 + 12.8.4-SNAPSHOT provided io.ebean ebean-querybean - 12.8.3 + 12.8.4-SNAPSHOT test io.ebean querybean-generator - 12.8.3 + 12.8.4-SNAPSHOT test io.ebean ebean-test - 12.8.3 + 12.8.4-SNAPSHOT test diff --git a/ebean-test/pom.xml b/ebean-test/pom.xml index 9b13477da..c3ed1f57f 100644 --- a/ebean-test/pom.xml +++ b/ebean-test/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.3 + 12.8.4-SNAPSHOT ebean test @@ -29,14 +29,14 @@ io.ebean ebean-core - 12.8.3 + 12.8.4-SNAPSHOT provided io.ebean ebean-ddl-generator - 12.8.3 + 12.8.4-SNAPSHOT diff --git a/ebean/pom.xml b/ebean/pom.xml index ddd0b9574..ba312953f 100644 --- a/ebean/pom.xml +++ b/ebean/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.3 + 12.8.4-SNAPSHOT ebean composite @@ -22,20 +22,20 @@ io.ebean ebean-api - 12.8.3 + 12.8.4-SNAPSHOT io.ebean ebean-core - 12.8.3 + 12.8.4-SNAPSHOT io.ebean ebean-querybean - 12.8.3 + 12.8.4-SNAPSHOT diff --git a/kotlin-querybean-generator/pom.xml b/kotlin-querybean-generator/pom.xml index 545078f3c..a556671bb 100644 --- a/kotlin-querybean-generator/pom.xml +++ b/kotlin-querybean-generator/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.3 + 12.8.4-SNAPSHOT kotlin querybean generator @@ -29,7 +29,7 @@ io.ebean ebean-querybean - 12.8.3 + 12.8.4-SNAPSHOT test @@ -43,7 +43,7 @@ io.ebean ebean-core - 12.8.3 + 12.8.4-SNAPSHOT test @@ -64,7 +64,7 @@ io.ebean ebean-ddl-generator - 12.8.3 + 12.8.4-SNAPSHOT test diff --git a/pom.xml b/pom.xml index 61571ff85..fb82113fa 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean-parent - 12.8.3 + 12.8.4-SNAPSHOT pom ebean parent @@ -18,7 +18,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-parent-12.8.3 + ebean-parent-12.8.0 diff --git a/querybean-generator/pom.xml b/querybean-generator/pom.xml index 996feff79..1ea632096 100644 --- a/querybean-generator/pom.xml +++ b/querybean-generator/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.8.3 + 12.8.4-SNAPSHOT querybean generator From c60077174ed01d4babc0049a0beecc4ae70d0415 Mon Sep 17 00:00:00 2001 From: Robin Bygrave Date: Tue, 20 Apr 2021 15:14:20 +1200 Subject: [PATCH 50/52] Tidy use of StringHelper replace() in BeanProperty, BaseTableDdl --- .../java/io/ebeaninternal/server/deploy/BeanProperty.java | 8 +++----- .../dbmigration/ddlgeneration/platform/BaseTableDdl.java | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java index 270415a22..d96a3d850 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java @@ -56,8 +56,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import static io.ebean.util.StringHelper.replace; - /** * Description of a property of a bean. Includes its deployment information such * as database column mapping information. @@ -357,12 +355,12 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty { private String tableAliasIntern(BeanDescriptor descriptor, String s, boolean dbEncrypted, String dbColumn) { if (descriptor != null) { - s = replace(s, "${ta}.", "${}"); - s = replace(s, "${ta}", "${}"); + s = s.replace("${ta}.", "${}"); + s = s.replace("${ta}", "${}"); if (dbEncrypted) { s = dbEncryptFunction.getDecryptSql(s); String namedParam = ":encryptkey_" + descriptor.getBaseTable() + "___" + dbColumn; - s = replace(s, "?", namedParam); + s = s.replace("?", namedParam); } } return InternString.intern(s); diff --git a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/BaseTableDdl.java b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/BaseTableDdl.java index 41e91274e..0e80c2676 100644 --- a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/BaseTableDdl.java +++ b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/BaseTableDdl.java @@ -150,7 +150,7 @@ public class BaseTableDdl implements TableDdl { buffer.append("-- NOTE: table has @History - special migration may be necessary").newLine(); } for (String ddlScript : before) { - buffer.appendStatement(translate(ddlScript, tableName, columnName, this.defaultValue)); + buffer.appendStatement(translate(ddlScript, tableName, columnName, defaultValue)); } } From 4fb3b9cddc3c1d052c6509249011819df1c12f4b Mon Sep 17 00:00:00 2001 From: rbygrave Date: Tue, 20 Apr 2021 22:13:45 +1200 Subject: [PATCH 51/52] Tidy use of StringHelper replace() in BeanProperty, BaseTableDdl --- .../main/java/io/ebeaninternal/server/deploy/BeanProperty.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java index d96a3d850..8793942b6 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java @@ -354,7 +354,7 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty { } private String tableAliasIntern(BeanDescriptor descriptor, String s, boolean dbEncrypted, String dbColumn) { - if (descriptor != null) { + if (s != null && descriptor != null) { s = s.replace("${ta}.", "${}"); s = s.replace("${ta}", "${}"); if (dbEncrypted) { From 42fc41975907274f44bb58bff35f1b1f573f8054 Mon Sep 17 00:00:00 2001 From: rbygrave Date: Tue, 20 Apr 2021 22:23:33 +1200 Subject: [PATCH 52/52] #2221 - ebean-redis: bump jedis dependency to 3.6.0 --- ebean-redis/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ebean-redis/pom.xml b/ebean-redis/pom.xml index 01062abf1..573fbcf3b 100644 --- a/ebean-redis/pom.xml +++ b/ebean-redis/pom.xml @@ -16,7 +16,7 @@ redis.clients jedis - 3.5.2 + 3.6.0