Compare commits

...
Author SHA1 Message Date
rob 19d2b04175 [maven-release-plugin] prepare release ebean-parent-13.13.0 2023-02-15 10:22:38 +13:00
rob d1844c9b5a Use kotlin-querybean-generator 13.13.0-RC1 for release 2023-02-15 10:18:01 +13:00
rob 93803eade4 Put the test kotlin-querybean-generator version back 1 for release plugin 2023-02-15 10:07:30 +13:00
rob ca6171f697 Ignore TestStdFunctions.concatEq for DB2 2023-02-14 22:39:26 +13:00
rob aa80bc0c10 Bump version to 13.13.0-SNAPSHOT 2023-02-14 20:28:45 +13:00
rob 638cfbca5e Bump ebean-agent to 13.13.0 2023-02-14 20:27:29 +13:00
rob afa9d89cfe #2971 - Bump ebean-datasource to 8.5 - use connection.setSchema() rather than connection Properties 2023-02-14 19:48:03 +13:00
Rob BygraveandGitHub 22a433997e Merge pull request #2970 from ebean-orm/feature/bump-ebean-migration
Bump ebean-migration to 13.7.0 - DB2 uses logical lock due to reorg tables
2023-02-14 19:44:39 +13:00
rob b9d8a9c532 Bump ebean-migration to 13.7.0 - DB2 uses logical lock due to reorg tables 2023-02-14 19:43:41 +13:00
rob 1f0191b9e4 Tidy ebean-test internals, final classes and whitespace 2023-02-14 19:41:45 +13:00
Rob BygraveandGitHub 2d78c5c5e8 Merge pull request #2969 from ebean-orm/feature/registerTestTenantProvider-default-false
#2968 - [ebean-test] - Default ebean.test.registerTestTenantProvider = false ... by default not auto register a test TenantProvider
2023-02-14 19:40:15 +13:00
rob 7c54d21760 #2968 - [ebean-test] - Default ebean.test.registerTestTenantProvider = false ... by default not auto register a test TenantProvider 2023-02-14 19:34:35 +13:00
Rob BygraveandGitHub b9a502ca85 Merge pull request #2957 from FOCONIS/detailed-evict-stats
ENH: add statistics trimmedByGC/LRU/TTL/Idle to ServerCacheStatistics?
2023-02-14 16:29:35 +13:00
rob b622d85292 #2967 - [ebean-joda] Joda JSON ISO8601 format for DateMidnight includes timezone 2023-02-14 15:56:45 +13:00
rob 320ffb4a2d #2966 - DateTimeParseException when ScalarTypeJodaLocalDateTime parsing Json ISO8601 2023-02-14 15:50:13 +13:00
Rob BygraveandGitHub 0292b4b558 Merge pull request #2912 from ebean-orm/wip/spi-txn-logging
Refactoring SpiLogger to better support conditional logging
2023-02-14 15:03:47 +13:00
rob 2c8ae16179 Update to use String format and Object varargs 2023-02-14 14:54:23 +13:00
Rob BygraveandGitHub 381ac58eed Merge pull request #2936 from FOCONIS/mem-leak-streaming-queries
BUG: Memory-leak on streaming queries when LoadBuffers are not aligned
2023-02-14 11:45:29 +13:00
rob af9459e41e Fix build for kotlin-querybean-generator annotation processor version, didn't get bumped after release 2023-02-14 11:42:47 +13:00
rob 5882169641 Merge branch 'feature/StdExpressions' 2023-02-14 11:35:31 +13:00
rob f694f2946a Rename test to StdOperatorsTest 2023-02-14 11:34:00 +13:00
rob 4c0144de61 Fix SqlOperators for sql injection 2023-02-14 11:33:28 +13:00
rob 5e70ea5095 Bump test version after release 2023-02-14 08:24:30 +13:00
rob acb28925f2 [maven-release-plugin] prepare for next development iteration 2023-02-14 08:07:15 +13:00
rob 3d2a68782c [maven-release-plugin] prepare release ebean-parent-13.12.0 2023-02-14 08:07:07 +13:00
rob 8c97d4d0fe Bump version to 13.12.0-SNAPSHOT 2023-02-14 08:02:35 +13:00
rob eb7de343a8 #2963 - [ebean-agent] By default enable @DbArray to be nullable and @Transient field initialisation when generating default constructors 2023-02-14 08:01:48 +13:00
Rob Bygrave 4ca1645f9f #2963 - [ebean-agent] By default enable @DbArray to be nullable and @Transient field initialisation when generating default constructors 2023-02-13 22:08:30 +13:00
Rob Bygrave d1fe79005c bump test versions after release 2023-02-13 15:51:31 +13:00
Rob Bygrave 015ee44de3 [maven-release-plugin] prepare for next development iteration 2023-02-13 13:34:22 +13:00
Rob Bygrave 714bbadbc0 [maven-release-plugin] prepare release ebean-parent-13.11.4 2023-02-13 13:34:14 +13:00
Rob Bygrave 9e811e9aef bump ebean-agent to 13.11.4 2023-02-13 13:25:33 +13:00
Rob Bygrave f97dcb60c0 Improve test only, QCustomerTest using AttributeConverter 2023-02-13 08:08:16 +13:00
Rob Bygrave 65c76cb2c0 Fix test to support SqlServer using sequences 2023-02-10 14:22:11 +13:00
Rob Bygrave 874427dac1 Fix test to also support Postgres ANY 2023-02-10 14:19:35 +13:00
Rob BygraveandGitHub 1176c2e97a Merge pull request #2962 from ebean-orm/feature/2961
#2961 - Followup for #2952 - @OneToMany + orphanRemoval + @SoftDelete + non-BeanCollection collection results in hard deletes
2023-02-10 13:10:01 +13:00
Rob Bygrave 44e0585fb7 #2961 - Followup for #2952 - @OneToMany + orphanRemoval + @SoftDelete + non-BeanCollection collection results in hard deletes
As noted in comments in #2952

In the internals of SaveManyBeans we have:

- BUG: the deleteByParentId is hard delete and does not care for soft delete
- YUK: internally we have 3 ways of performing the orphan removal when we really want 2

This change fixes the BUG and fixes the YUK. It does this by removing the special case at: https://github.com/ebean-orm/ebean/blob/ebean-parent-13.11.3/ebean-core/src/main/java/io/ebeaninternal/server/persist/SaveManyBeans.java#L347-L350 ... and replacing it with the more common orphan removal code used when we do not have BeanCollection modifications.

The result of this change is that in SaveManyBeans internals we get back to have 2 ways to remove orphans.

- A BeanCollection with modifications: Orphans explicitly deleted using the known elements removed from the collection
- All other cases: Orphans as everything NOT in the collection that is going to be updated
2023-02-10 13:08:44 +13:00
Rob BygraveandGitHub 889c0f12e0 Merge pull request #2960 from ebean-orm/buchtajz-one2many_setArraylist
Fix for @OneToMany orphanRemoval not occurring for #2952 #2953
2023-02-10 13:01:55 +13:00
Rob Bygrave 0135263dbd Style only for SaveManyBeans switching order in if/else 2023-02-09 23:45:27 +13:00
Rob Bygrave 564194042b No effective change, BeanCollectionUtil perform the instanceof Collection before instanceof Map check 2023-02-09 23:44:13 +13:00
Rob Bygrave 244d45674a #2952 #2953 - Fix for @OneToMany orphanRemoval not occurring
orphanRemoval was not occurring when a loaded bean had a collection
replaced by a new BeanCollection (as opposed to a vanilla collection
like java.util.ArrayList).

Json marshalling a collection puts beans into BeanCollection and this
is part of the test that reproduced this issue.
2023-02-09 23:29:13 +13:00
Rob Bygrave 4722f10f5e Bump versions after release 2023-02-07 22:46:08 +13:00
Rob Bygrave 3f5140e7f3 [maven-release-plugin] prepare for next development iteration 2023-02-07 22:10:29 +13:00
Rob Bygrave 43dec17d08 [maven-release-plugin] prepare release ebean-parent-13.11.3 2023-02-07 22:10:16 +13:00
Rob Bygrave f1ee45d7d1 Bump ebean-agent to 13.11.3 2023-02-07 22:06:16 +13:00
Rob Bygrave 3263e7bfc3 #2959 - Improve logging for lazy loading error due to "markAsDeleted" 2023-02-07 22:05:34 +13:00
Rob Bygrave e01f19b3aa Merge branch 'one2many_setArraylist' of github.com:buchtajz/ebean into buchtajz-one2many_setArraylist 2023-02-07 20:09:01 +13:00
Rob Bygrave 20f6a659fe #2959 - Improve logging for lazy loading error due to "markAsDeleted" 2023-02-07 19:59:33 +13:00
Michal Buchtík 09fe923770 Merge remote-tracking branch 'origin/one2many_setArraylist' into one2many_setArraylist 2023-02-05 09:28:11 +01:00
buchtajzandGitHub e6f5e42c2d Merge branch 'ebean-orm:master' into one2many_setArraylist 2023-02-05 09:25:29 +01:00
Roland Praml 010f73fea2 ENH: add statistics trimmedByGC/LRU/TTL/Idle to ServerCacheStatistics? 2023-02-02 14:10:54 +01:00
Rob Bygrave 5150ecba62 #2948 - SoftDelete entities are hard deleted on orphan removal 2023-02-02 23:15:22 +13:00
Rob Bygrave 978b1dbe02 Merge branch 'master' of github.com:ebean-orm/ebean 2023-02-02 23:06:49 +13:00
Rob Bygrave 9813703ce5 Merge branch 'Ichtil-hard_delete_instead_of_soft_delete_2' 2023-02-02 23:03:28 +13:00
Rob Bygrave 09001e80b5 #2948 - SoftDelete entities are hard deleted on orphan removal 2023-02-02 23:02:44 +13:00
Rob BygraveandGitHub 4aa3ca6d95 Merge pull request #2941 from FOCONIS/expressionlist-clear
NEW: ExpressionList has clear() method
2023-02-02 01:13:28 +13:00
Rob BygraveandGitHub 5ec8469ddc Merge pull request #2940 from FOCONIS/fix-bom
FIX: Removed non existent modules from BOM
2023-02-02 00:42:43 +13:00
Michal Buchtík 39099bbcc9 print sql 2023-01-31 23:01:52 +01:00
Michal Buchtík cb2ca0de11 setArrayListDoInsertInsteadUpdate 2023-01-30 23:47:18 +01:00
Jan Klička b25233b0b9 Merge branch 'master' into hard_delete_instead_of_soft_delete_2
# Conflicts:
#	ebean-test/pom.xml
2023-01-27 16:28:03 +01:00
Jan Klička 743f1b10e3 #2948 2023-01-27 16:17:01 +01:00
Roland Praml 371f50fb4d NEW: ExpressionList has clear() method 2023-01-23 11:33:29 +01:00
Roland Praml a3be2041c8 FIX: Removed non existent modules from BOM 2023-01-23 11:31:45 +01:00
Rob Bygrave 09a831f2d6 Bump versions after release 2023-01-21 22:35:40 +13:00
Rob Bygrave 27d9e03691 [maven-release-plugin] prepare for next development iteration 2023-01-21 20:37:02 +13:00
Roland Praml 61d6cccbcb FIX: Using weak references in load buffer for streaming queries 2023-01-20 16:51:51 +01:00
Roland Praml a3540057b7 BUG: Memory-leak on streaming queries when LoadBuffers are not aligned 2023-01-18 09:24:47 +01:00
Rob Bygrave 9720cd8189 Add SpiTxnLogger as main point to log SQL, SUM and TXN messages on a per transaction basis 2022-12-02 02:34:14 +13:00
Rob Bygrave bc4d9837c6 Modify SpiLogger removing isTrace(), trace() and the 2 uses
- Not bothered to log when changing isolation level
- Not bothering to log at end of query only transaction
2022-12-01 23:45:40 +13:00
Rob Bygrave 4a0f8931a0 Add parameter type for Query.Property with DefaultUpdateQuery and TQRootBean 2022-11-09 23:41:42 +13:00
Rob Bygrave 3c8c52ca7f Simplify to use single type (not use another different type for Query.Property) 2022-11-09 23:30:51 +13:00
Rob Bygrave d29ef8934d Add more operators to StdOperators
- stricter use of UpdateQuery.set()
- Numbers just use their own type - PBaseNumber
- PEnum just uses its own type
- Expr.factory() to expose factory
2022-11-09 17:47:16 +13:00
Rob Bygrave a4c3949cfc Merge branch 'master' into feature/StdExpressions 2022-11-08 21:58:34 +13:00
Rob Bygrave 97bbce321d Make Query.Property parameterised with <BT> "Base Type" as Number, String, Temporal, Boolean or Object
These types then determine which functions are valid for the types. So:
- Number functions
- String/varchar functions
- Temporal Date, DateTime, Time functions
- Boolean functions
- Object being everything else
2022-11-08 21:57:36 +13:00
Rob Bygrave 0b9d199829 #2774 - Postgres ANY / MultiValueSupport with byte[]/binary data
Add Postgres specific support for binding an array of byte[] with ANY(?)
which is used as with client side encryption where the bind values are
implicitly converted to byte[].

Fixes Postgres specific failure running TestEncryptClientSide.java
2022-11-07 17:36:04 +13:00
Rob Bygrave 3da924b943 Add Query.Property.of(), Move StdFunctions to ebean-api 2022-11-07 12:57:39 +13:00
Rob Bygrave 5ad313d290 Rename TQColumn -> Query.Property, fix compile for DefaultOrmQuery use of OrderBy.Property 2022-11-03 17:46:30 +13:00
Rob Bygrave 8565f5f807 Rename TQColumn -> Query.Property and move to api + use with UpdateQuery.set()
- Refactor rename TQColumn to Query.Property and move to ebean-api module
- Add UpdateQuery.set() methods to use Query.Property (as per #2849)
2022-11-03 17:33:11 +13:00
Rob Bygrave 96e79248dc Add StdFunctions, StdExpressions, TQColumn marker interface 2022-11-03 11:16:30 +13:00
187 changed files with 2408 additions and 867 deletions
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.2</version>
<version>13.13.0</version>
</parent>
<name>ebean-clickhouse</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
@@ -35,18 +35,18 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-clickhouse</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.11.2</tag>
<tag>ebean-parent-13.13.0</tag>
</scm>
</project>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.2</version>
<version>13.13.0</version>
</parent>
<name>ebean-cockroach</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
@@ -35,18 +35,18 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.11.2</tag>
<tag>ebean-parent-13.13.0</tag>
</scm>
</project>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.2</version>
<version>13.13.0</version>
</parent>
<name>ebean-db2</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
@@ -35,18 +35,18 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-db2</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.11.2</tag>
<tag>ebean-parent-13.13.0</tag>
</scm>
</project>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.2</version>
<version>13.13.0</version>
</parent>
<name>ebean-h2</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
@@ -35,18 +35,18 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.11.2</tag>
<tag>ebean-parent-13.13.0</tag>
</scm>
</project>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.2</version>
<version>13.13.0</version>
</parent>
<name>ebean-hana</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
@@ -35,18 +35,18 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-hana</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.11.2</tag>
<tag>ebean-parent-13.13.0</tag>
</scm>
</project>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.2</version>
<version>13.13.0</version>
</parent>
<name>ebean-mariadb</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
@@ -35,18 +35,18 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-mariadb</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.11.2</tag>
<tag>ebean-parent-13.13.0</tag>
</scm>
</project>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.2</version>
<version>13.13.0</version>
</parent>
<name>ebean-mysql</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
@@ -35,18 +35,18 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-mysql</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.11.2</tag>
<tag>ebean-parent-13.13.0</tag>
</scm>
</project>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.2</version>
<version>13.13.0</version>
</parent>
<name>ebean-nuodb</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
@@ -35,18 +35,18 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-nuodb</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.11.2</tag>
<tag>ebean-parent-13.13.0</tag>
</scm>
</project>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.2</version>
<version>13.13.0</version>
</parent>
<name>ebean-oracle</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
@@ -35,18 +35,18 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-oracle</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.11.2</tag>
<tag>ebean-parent-13.13.0</tag>
</scm>
</project>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.2</version>
<version>13.13.0</version>
</parent>
<name>ebean-postgres</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
@@ -35,18 +35,18 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.11.2</tag>
<tag>ebean-parent-13.13.0</tag>
</scm>
</project>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.2</version>
<version>13.13.0</version>
</parent>
<name>ebean-sqlite</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
@@ -35,18 +35,18 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlite</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.11.2</tag>
<tag>ebean-parent-13.13.0</tag>
</scm>
</project>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.2</version>
<version>13.13.0</version>
</parent>
<name>ebean-sqlserver</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
@@ -35,18 +35,18 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlserver</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.11.2</tag>
<tag>ebean-parent-13.13.0</tag>
</scm>
</project>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.2</version>
<version>13.13.0</version>
</parent>
<name>ebean-yugabyte</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
@@ -35,18 +35,18 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.11.2</tag>
<tag>ebean-parent-13.13.0</tag>
</scm>
</project>
+9 -9
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.2</version>
<version>13.13.0</version>
</parent>
<name>ebean (all platforms)</name>
@@ -16,31 +16,31 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-joda-time</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-jackson-jsonnode</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-jackson-mapper</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
@@ -53,18 +53,18 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-all</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.11.2</tag>
<tag>ebean-parent-13.13.0</tag>
</scm>
</project>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.2</version>
<version>13.13.0</version>
</parent>
<artifactId>composites</artifactId>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.2</version>
<version>13.13.0</version>
</parent>
<name>ebean api</name>
@@ -30,6 +30,13 @@ public final class Expr {
private Expr() {
}
/**
* Return the underlying expression factory.
*/
public static ExpressionFactory factory() {
return DB.expressionFactory();
}
/**
* Equal To - property equal to the given value.
*/
@@ -1730,4 +1730,8 @@ public interface ExpressionList<T> {
*/
ExpressionList<T> endNot();
/**
* Clears the current expression list.
*/
ExpressionList<T> clear();
}
@@ -1768,4 +1768,31 @@ public interface Query<T> extends CancelableQuery {
*/
Query<T> orderById(boolean orderById);
/**
* Type safe query bean properties and expressions (marker interface).
* <p>
* Implemented by query bean properties and expressions based on those properties.
* <p>
* The base type determines which {@link StdOperators} can be used on the property.
*
* @param <T> The property type.
*/
interface Property<T> {
/**
* Return a property given the expression.
*/
static <T> Property<T> of(String expression) {
return new SimpleProperty<>(expression);
}
/**
* Return the property in string expression form.
* <p>
* This is a path to a database column (like "name" or "billingAddress.city") or a function
* wrapping a path (like <em>lower(name)</em>, <em>concat(name, '-', billingAddress.city)</em>
*/
@Override
String toString();
}
}
@@ -0,0 +1,15 @@
package io.ebean;
final class SimpleProperty<T> implements Query.Property<T> {
private final String expression;
SimpleProperty(String expression) {
this.expression = expression;
}
@Override
public String toString() {
return expression;
}
}
@@ -0,0 +1,332 @@
package io.ebean;
import io.ebean.Query.Property;
import java.util.Collection;
/**
* Standard Operators for use with strongly typed query construction.
* <p>
* This is currently deemed to be experimental and subject to change.
*/
@Deprecated(since = "experimental")
public final class StdOperators {
// ---- Functions ---- //
/**
* Sum of the given property.
*/
public static Property<Number> sum(Property<? extends Number> property) {
return Property.of("sum(" + property + ")");
}
/**
* Count of the given property.
*/
public static Property<Number> count(Property<?> property) {
return Property.of("count(" + property + ")");
}
/**
* Average of the given property.
*/
public static <T> Property<T> avg(Property<T> property) {
return Property.of("avg(" + property + ")");
}
/**
* Max of the given property.
*/
public static <T> Property<T> max(Property<T> property) {
return Property.of("max(" + property + ")");
}
/**
* Min of the given property.
*/
public static <T> Property<T> min(Property<T> property) {
return Property.of("min(" + property + ")");
}
/**
* Coalesce of the property and value.
*/
public static <T> Property<T> coalesce(Property<T> property, Object value) {
return Property.of("coalesce(" + property.toString() + "," + sqlValue(value) + ")");
}
/**
* Lower of the given property.
*/
public static Property<String> lower(Property<String> property) {
return Property.of("lower(" + property + ")");
}
/**
* Upper of the given property.
*/
public static Property<String> upper(Property<String> property) {
return Property.of("upper(" + property + ")");
}
/**
* Concat of the given property and values or other properties.
*/
public static Property<String> concat(Property<?> property, Object... values) {
StringBuilder expression = new StringBuilder(50);
expression.append("concat(").append(property.toString());
for (Object value : values) {
expression.append(",").append(sqlConcatString(value));
}
expression.append(")");
return Property.of(expression.toString());
}
private static String sqlConcatString(Object value) {
if (value instanceof Property) {
return value.toString();
} else {
return sqlQuote(value);
}
}
/**
* Allows numbers to be unquoted.
*/
private static String sqlValue(Object value) {
if (value instanceof Property || value instanceof Number) {
return value.toString();
} else {
return sqlQuote(value);
}
}
/**
* SQL quoted escaping single quotes.
*/
private static String sqlQuote(Object value) {
return "'" + String.valueOf(value).replace("'", "''") + "'";
}
// ---- Operators ---- //
/**
* Equal to - for a property and value.
*/
public static <T> Expression eq(Property<T> property, T value) {
return Expr.eq(property.toString(), value);
}
/**
* Equal to - for a property and sub-query.
*/
public static <T> Expression eq(Property<T> property, Query<?> subQuery) {
return Expr.in(property.toString(), subQuery);
}
/**
* Equal to or null - for a property and value.
*/
public static <T> Expression eqOrNull(Property<T> property, T value) {
return Expr.factory().eqOrNull(property.toString(), value);
}
/**
* Not equal to - for a property and value.
*/
public static <T> Expression ne(Property<T> property, T value) {
return Expr.ne(property.toString(), value);
}
/**
* Not equal to - for a property and sub-query.
*/
public static <T> Expression ne(Property<T> property, Query<?> subQuery) {
return Expr.ne(property.toString(), subQuery);
}
/**
* Greater than - for a property and value.
*/
public static <T> Expression gt(Property<T> property, T value) {
return Expr.gt(property.toString(), value);
}
/**
* Greater than - for a property and sub-query.
*/
public static <T> Expression gt(Property<T> property, Query<?> subQuery) {
return Expr.gt(property.toString(), subQuery);
}
/**
* Greater than or null - for a property and value.
*/
public static <T> Expression gtOrNull(Property<T> property, T value) {
return Expr.factory().gtOrNull(property.toString(), value);
}
/**
* Greater than or equal to - for a property and value.
*/
public static <T> Expression ge(Property<T> property, T value) {
return Expr.ge(property.toString(), value);
}
/**
* Greater than or equal to - for a property and sub-query.
*/
public static <T> Expression ge(Property<T> property, Query<?> subQuery) {
return Expr.ge(property.toString(), subQuery);
}
/**
* Greater than or null - for a property and value.
*/
public static <T> Expression geOrNull(Property<T> property, T value) {
return Expr.factory().geOrNull(property.toString(), value);
}
/**
* Less than - for a property and value.
*/
public static <T> Expression lt(Property<T> property, T value) {
return Expr.lt(property.toString(), value);
}
/**
* Less than - for a property and sub-query.
*/
public static <T> Expression lt(Property<T> property, Query<?> subQuery) {
return Expr.lt(property.toString(), subQuery);
}
/**
* Less than or null - for a property and value.
*/
public static <T> Expression ltOrNull(Property<T> property, T value) {
return Expr.factory().ltOrNull(property.toString(), value);
}
/**
* Greater than or equal to - for a property and value.
*/
public static <T> Expression le(Property<T> property, T value) {
return Expr.le(property.toString(), value);
}
/**
* Greater than or equal to - for a property and sub-query.
*/
public static <T> Expression le(Property<T> property, Query<?> subQuery) {
return Expr.le(property.toString(), subQuery);
}
/**
* Greater than or equal to or null - for a property and value.
*/
public static <T> Expression leOrNull(Property<T> property, T value) {
return Expr.factory().leOrNull(property.toString(), value);
}
/**
* In range - for a property and values.
*/
public static <T> Expression inRange(Property<T> property, T lowValue, T highValue) {
return Expr.factory().inRange(property.toString(), lowValue, highValue);
}
/**
* In range - for properties and a value.
*/
public static <T> Expression inRange(Property<T> lowProperty, Property<T> highProperty, T value) {
return Expr.factory().inRangeWith(lowProperty.toString(), highProperty.toString(), value);
}
/**
* In range - for properties.
*/
public static <T> Expression inRange(Property<T> lowProperty, Property<T> property, Property<T> highProperty) {
return Expr.factory().inRangeWithProperties(lowProperty.toString(), property.toString(), highProperty.toString());
}
/**
* In - for a given property and collection of values.
*/
public static <T> Expression in(Property<T> property, Collection<T> value) {
return Expr.in(property.toString(), value);
}
/**
* In - for a given property and sub-query.
*/
public static <T> Expression in(Property<T> property, Query<?> subQuery) {
return Expr.in(property.toString(), subQuery);
}
/**
* In or empty - for a given property and collection of values.
*/
public static <T> Expression inOrEmpty(Property<T> property, Collection<T> value) {
return Expr.inOrEmpty(property.toString(), value);
}
/**
* Not In - for a given property and collection of values.
*/
public static <T> Expression notIn(Property<T> property, Collection<T> value) {
return Expr.factory().notIn(property.toString(), value);
}
/**
* Not In - for a given property and sub-query.
*/
public static <T> Expression notIn(Property<T> property, Query<?> subQuery) {
return Expr.factory().notIn(property.toString(), subQuery);
}
// ---- String operators ---- //
/**
* Like - for a given property and value.
*/
public static Expression like(Property<String> property, String value) {
return Expr.like(property.toString(), value);
}
/**
* Case-insensitive Like - for a given property and value.
*/
public static Expression ilike(Property<String> property, String value) {
return Expr.ilike(property.toString(), value);
}
/**
* Starts with - for a given property and value.
*/
public static Expression startsWith(Property<String> property, String value) {
return Expr.startsWith(property.toString(), value);
}
/**
* Case-insensitive starts with - for a given property and value.
*/
public static Expression istartsWith(Property<String> property, String value) {
return Expr.istartsWith(property.toString(), value);
}
/**
* Contains - for a given property and value.
*/
public static Expression contains(Property<String> property, String value) {
return Expr.contains(property.toString(), value);
}
/**
* Case-insensitive contains - for a given property and value.
*/
public static Expression icontains(Property<String> property, String value) {
return Expr.icontains(property.toString(), value);
}
}
@@ -14,7 +14,7 @@ package io.ebean;
*
* int rows = DB.update(Customer.class)
* .set("status", Customer.Status.ACTIVE)
* .set("updtime", new Timestamp(System.currentTimeMillis()))
* .set("whenUpdated", Instant.now())
* .where()
* .gt("id", 1000)
* .update();
@@ -25,6 +25,20 @@ package io.ebean;
* update o_customer set status=?, updtime=? where id > ?
*
* }</pre>
*
* <h4>Example: Using query bean</h4>
* <pre>{@code
*
* var cust = QCustomer.alias();
*
* int rows = new QCustomer()
* .id.gt(1000)
* .asUpdate()
* .set(cust.status, Customer.Status.COMPLETE)
* .set(cust.whenUpdated, Instant.now())
* .update();
*
* }</pre>
* <p>
* Note that if the where() clause contains a join then the SQL update changes to use a
* <code> WHERE ID IN () </code> form.
@@ -40,7 +54,7 @@ package io.ebean;
*
* int rows = DB.update(Customer.class)
* .set("status", Customer.Status.ACTIVE)
* .set("updtime", new Timestamp(System.currentTimeMillis()))
* .set("whenUpdated", Instant.now())
* .where()
* .eq("status", Customer.Status.NEW)
* .eq("billingAddress.country", nz)
@@ -73,7 +87,7 @@ public interface UpdateQuery<T> {
*
* int rows = DB.update(Customer.class)
* .set("status", Customer.Status.ACTIVE)
* .set("updtime", new Timestamp(System.currentTimeMillis()))
* .set("whenUpdated", Instant.now())
* .where()
* .gt("id", 1000)
* .update();
@@ -85,6 +99,27 @@ public interface UpdateQuery<T> {
*/
UpdateQuery<T> set(String property, Object value);
/**
* Set the value of a property.
* <p>
* <pre>{@code
*
* var cust = QCustomer.alias();
*
* int rows = new QCustomer()
* .id.gt(1000)
* .asUpdate()
* .set(cust.status, Customer.Status.COMPLETE)
* .set(cust.whenUpdated, Instant.now())
* .update();
*
* }</pre>
*
* @param property The bean property to be set
* @param value The value to set the property to
*/
<P> UpdateQuery<T> set(Query.Property<P> property, P value);
/**
* Set the property to be null.
* <p>
@@ -102,6 +137,13 @@ public interface UpdateQuery<T> {
*/
UpdateQuery<T> setNull(String property);
/**
* Set the property to be null.
*
* @param property The bean property to be set
*/
UpdateQuery<T> setNull(Query.Property<?> property);
/**
* Set using a property expression that does not need any bind values.
* <p>
@@ -725,7 +725,7 @@ public final class InterceptReadWrite implements EntityBeanIntercept {
loader.loadBean(this);
if (lazyLoadFailure) {
// failed when lazy loading this bean
throw new EntityNotFoundException("Lazy loading failed on type:" + owner.getClass().getName() + " id:" + ownerId + " - Bean has been deleted.");
throw new EntityNotFoundException("Lazy loading failed on type:" + owner.getClass().getName() + " id:" + ownerId + " - Bean has been deleted. BeanLoader: " + beanLoader);
}
// bean should be loaded and intercepting now. setLoaded() has
// been called by the lazy loading mechanism
@@ -29,6 +29,11 @@ public class ServerCacheStatistics {
protected long evictCount;
protected long gcCount;
protected long idleCount;
protected long ttlCount;
protected long lruCount;
@Override
public String toString() {
//noinspection StringBufferReplaceableByString
@@ -43,6 +48,10 @@ public class ServerCacheStatistics {
sb.append(" remove:").append(removeCount);
sb.append(" clear:").append(clearCount);
sb.append(" evict:").append(evictCount);
sb.append(" gc:").append(gcCount);
sb.append(" idle:").append(idleCount);
sb.append(" ttl:").append(ttlCount);
sb.append(" lru:").append(lruCount);
return sb.toString();
}
@@ -191,4 +200,37 @@ public class ServerCacheStatistics {
return evictCount;
}
/**
* Set the count of entries removed by the garbage collection.
*/
public void setGcCount(long gcCount) {
this.gcCount = gcCount;
}
/**
* Return the count of entries removed by the garbage collection.
*/
public long getGcCount() {
return gcCount;
}
public void setIdleCount(long idleCount) {
this.idleCount = idleCount;
}
public long getIdleCount() {
return idleCount;
}
public void setTtlCount(long ttlCount) {
this.ttlCount = ttlCount;
}
public long getTtlCount() {
return ttlCount;
}
public void setLruCount(long lruCount) {
this.lruCount = lruCount;
}
}
@@ -1 +1 @@
ebean-version: 141
ebean-version: 142
@@ -0,0 +1,78 @@
package io.ebean;
import org.junit.jupiter.api.Test;
import java.time.LocalDate;
import static io.ebean.StdOperators.*;
import static org.assertj.core.api.Assertions.assertThat;
class StdOperatorsTest {
final Query.Property<Number> amount = Query.Property.of("amount");
final Query.Property<String> foo = Query.Property.of("foo");
final Query.Property<String> bar = Query.Property.of("bar");
@Test
void testAvg() {
assertThat(avg(foo).toString()).isEqualTo("avg(foo)");
}
@Test
void testCount() {
assertThat(count(foo).toString()).isEqualTo("count(foo)");
}
@Test
void testMax() {
assertThat(max(foo).toString()).isEqualTo("max(foo)");
}
@Test
void testMin() {
assertThat(min(foo).toString()).isEqualTo("min(foo)");
}
@Test
void testSum() {
assertThat(sum(amount).toString()).isEqualTo("sum(amount)");
}
@Test
void testLower() {
assertThat(lower(foo).toString()).isEqualTo("lower(foo)");
}
@Test
void testUpper() {
assertThat(upper(foo).toString()).isEqualTo("upper(foo)");
}
@Test
void testConcat() {
assertThat(concat(foo, "+").toString()).isEqualTo("concat(foo,'+')");
assertThat(concat(foo, 42).toString()).isEqualTo("concat(foo,'42')");
assertThat(concat(foo, LocalDate.of(2022, 9, 1)).toString()).isEqualTo("concat(foo,'2022-09-01')");
assertThat(concat(foo, bar).toString()).isEqualTo("concat(foo,bar)");
assertThat(concat(foo, ":", 42, bar).toString()).isEqualTo("concat(foo,':','42',bar)");
}
@Test
void testCoalesce() {
assertThat(coalesce(foo, bar).toString()).isEqualTo("coalesce(foo,bar)");
assertThat(coalesce(foo, 42).toString()).isEqualTo("coalesce(foo,42)");
assertThat(coalesce(foo, 0).toString()).isEqualTo("coalesce(foo,0)");
assertThat(coalesce(foo, "apple").toString()).isEqualTo("coalesce(foo,'apple')");
assertThat(coalesce(foo, "banana").toString()).isEqualTo("coalesce(foo,'banana')");
}
@Test
void testCoalesceWithQuoted() {
assertThat(coalesce(foo, "ba'nana").toString()).isEqualTo("coalesce(foo,'ba''nana')");
}
@Test
void testConcatWithQuoted() {
assertThat(concat(foo, "ba'nana").toString()).isEqualTo("concat(foo,'ba''nana')");
}
}
+4 -4
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.2</version>
<version>13.13.0</version>
</parent>
<!-- <parent>-->
<!-- <groupId>org.avaje</groupId>-->
@@ -14,7 +14,7 @@
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-parent-13.11.2</tag>
<tag>ebean-parent-13.13.0</tag>
</scm>
<name>ebean autotune</name>
@@ -26,7 +26,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
<scope>provided</scope>
</dependency>
@@ -55,7 +55,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
<scope>test</scope>
</dependency>
+29 -47
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.2</version>
<version>13.13.0</version>
</parent>
<name>ebean bom</name>
@@ -89,192 +89,174 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-joda-time</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-jackson-jsonnode</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-jackson-mapper</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-api</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-xml</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-autotune</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>kotlin-querybean-generator</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgis</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-redis</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<!-- platforms -->
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-all</artifactId>
<version>13.11.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-clickhouse</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-db2</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-h2</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-hana</artifactId>
<version>13.11.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-hsqldb</artifactId>
<version>13.11.2-SNAPSHOT</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-mariadb</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-mysql</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-nuodb</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-oracle</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgres</artifactId>
<version>13.11.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-sqlanywhere</artifactId>
<version>13.11.2-SNAPSHOT</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-sqlite</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-sqlserver</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
</dependencies>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.2</version>
<version>13.13.0</version>
</parent>
<artifactId>ebean-core-type</artifactId>
@@ -16,7 +16,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
+8 -8
View File
@@ -3,7 +3,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.2</version>
<version>13.13.0</version>
</parent>
<artifactId>ebean-core</artifactId>
@@ -15,14 +15,14 @@
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-parent-13.11.2</tag>
<tag>ebean-parent-13.13.0</tag>
</scm>
<dependencies>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
@@ -46,13 +46,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-api</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
@@ -143,21 +143,21 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlserver</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
<scope>test</scope>
</dependency>
@@ -9,4 +9,5 @@ public final class CoreLog {
public static final System.Logger log = AppLog.getLogger("io.ebean.core");
public static final System.Logger internal = AppLog.getLogger("io.ebean.internal");
public static final System.Logger markedAsDeleted = AppLog.getLogger("io.ebean.MarkedAsDeleted");
}
@@ -6,10 +6,7 @@ import io.ebeaninternal.api.SpiQuery.Mode;
import io.ebeaninternal.server.core.OrmQueryRequest;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.*;
/**
* Request for loading ManyToOne and OneToOne relationships.
@@ -103,7 +100,7 @@ public final class LoadBeanRequest extends LoadRequest {
/**
* Load the beans into the L2 cache if that is requested and check for load failures due to deletes.
*/
public void postLoad(List<?> list) {
public Result postLoad(List<?> list) {
Set<Object> loadedIds = new HashSet<>();
BeanDescriptor<?> desc = loadBuffer.descriptor();
// collect Ids and maybe load bean cache
@@ -114,6 +111,7 @@ public final class LoadBeanRequest extends LoadRequest {
desc.cacheBeanPutAll(list);
}
if (lazyLoadProperty != null) {
Set<Object> missedIds = new HashSet<>();
for (EntityBeanIntercept ebi : batch) {
// check if the underlying row in DB was deleted. Mark the bean as 'failed' if
// necessary but allow processing to continue until it is accessed by client code
@@ -121,8 +119,36 @@ public final class LoadBeanRequest extends LoadRequest {
if (!loadedIds.contains(id)) {
// assume this is logically deleted (hence not found)
desc.markAsDeleted(ebi.getOwner());
missedIds.add(id);
}
}
return new Result(loadedIds, missedIds);
}
return EMPTY_RESULT;
}
static final Result EMPTY_RESULT = new Result(Collections.emptySet(),Collections.emptySet());
public static class Result {
private final Set<Object> loadedIds;
private final Set<Object> missedIds;
Result(Set<Object> loadedIds, Set<Object> missedIds) {
this.loadedIds = loadedIds;
this.missedIds = missedIds;
}
public boolean markedDeleted() {
return !missedIds.isEmpty();
}
public Set<Object> missedIds() {
return missedIds;
}
public Set<Object> loadedIds() {
return loadedIds;
}
}
}
@@ -50,4 +50,9 @@ public interface LoadContext {
* Register a collection for lazy loading.
*/
void register(String path, BeanPropertyAssocMany<?> many, BeanCollection<?> bc);
/**
* Use soft-references for streaming queries, so unreachable entries can be garbage collected.
*/
void useReferences(boolean useReferences);
}
@@ -6,16 +6,30 @@ import io.ebean.bean.PersistenceContext;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import java.util.List;
/**
* A buffer of bean collections for batch lazy loading and secondary query loading.
*/
public interface LoadManyBuffer {
int getBatchSize();
/**
* The batch (max) size;
*/
int batchSize();
List<BeanCollection<?>> getBatch();
/**
* The actual size.
*/
int size();
/**
* Get the <code>i</code>th element from buffer. This can be null.
*/
BeanCollection<?> get(int i);
/**
* Removes an element from the buffer. This will NOT affect size.
*/
boolean removeFromBuffer(BeanCollection<?> collection);
BeanPropertyAssocMany<?> getBeanProperty();
@@ -19,8 +19,6 @@ import static java.lang.System.Logger.Level.DEBUG;
public final class LoadManyRequest extends LoadRequest {
private static final System.Logger log = CoreLog.log;
private final List<BeanCollection<?>> batch;
private final LoadManyBuffer loadContext;
private final boolean onlyIds;
private final boolean loadCache;
@@ -42,7 +40,6 @@ public final class LoadManyRequest extends LoadRequest {
private LoadManyRequest(LoadManyBuffer loadContext, OrmQueryRequest<?> parentRequest, boolean lazy, boolean onlyIds, boolean loadCache) {
super(parentRequest, lazy);
this.loadContext = loadContext;
this.batch = loadContext.getBatch();
this.onlyIds = onlyIds;
this.loadCache = loadCache;
}
@@ -59,9 +56,12 @@ public final class LoadManyRequest extends LoadRequest {
private List<Object> parentIdList(SpiEbeanServer server) {
List<Object> idList = new ArrayList<>();
BeanPropertyAssocMany<?> many = many();
for (BeanCollection<?> bc : batch) {
idList.add(many.parentId(bc.getOwnerBean()));
bc.setLoader(server); // don't use the load buffer again
for (int i = 0; i < loadContext.size(); i++) {
BeanCollection<?> bc = loadContext.get(i);
if (bc != null) {
idList.add(many.parentId(bc.getOwnerBean()));
bc.setLoader(server); // don't use the load buffer again
}
}
if (many.targetDescriptor().isPadInExpression()) {
BindPadding.padIds(idList);
@@ -91,7 +91,7 @@ public final class LoadManyRequest extends LoadRequest {
query.setPersistenceContext(loadContext.getPersistenceContext());
query.setLoadDescription(lazy ? "+lazy" : "+query", description());
if (lazy) {
query.setLazyLoadBatchSize(loadContext.getBatchSize());
query.setLazyLoadBatchSize(loadContext.batchSize());
} else {
query.setBeanCacheMode(CacheMode.OFF);
}
@@ -112,15 +112,18 @@ public final class LoadManyRequest extends LoadRequest {
BeanPropertyAssocMany<?> many = many();
// check for BeanCollection's that where never processed
// in the +query or +lazy load due to no rows (predicates)
for (BeanCollection<?> bc : batch) {
if (bc.checkEmptyLazyLoad()) {
if (log.isLoggable(DEBUG)) {
EntityBean ownerBean = bc.getOwnerBean();
Object parentId = desc.getId(ownerBean);
log.log(DEBUG, "BeanCollection after lazy load was empty. type:{0} id:{1} owner:{2}", ownerBean.getClass().getName(), parentId, ownerBean);
for (int i = 0; i < loadContext.size(); i++) {
BeanCollection<?> bc = loadContext.get(i);
if (bc != null) {
if (bc.checkEmptyLazyLoad()) {
if (log.isLoggable(DEBUG)) {
EntityBean ownerBean = bc.getOwnerBean();
Object parentId = desc.getId(ownerBean);
log.log(DEBUG, "BeanCollection after lazy load was empty. type:{0} id:{1} owner:{2}", ownerBean.getClass().getName(), parentId, ownerBean);
}
} else if (loadCache && many.isUseCache()) {
desc.cacheManyPropPut(many, bc, desc.cacheKeyForBean(bc.getOwnerBean()));
}
} else if (loadCache && many.isUseCache()) {
desc.cacheManyPropPut(many, bc, desc.cacheKeyForBean(bc.getOwnerBean()));
}
}
}
@@ -10,18 +10,25 @@ package io.ebeaninternal.api;
public interface SpiLogManager {
/**
* Return the SQL logger.
* Enable bind logging.
*/
boolean enableBindLog();
/**
* Logger used for general transactions.
*/
SpiTxnLogger logger();
/**
* Logger used for read only transactions.
*/
SpiTxnLogger readOnlyLogger();
/**
* Hmmmm, return the SQL logger for logging truncate statements.
* <p>
* Maybe we should get rid of this
*/
SpiLogger sql();
/**
* Return the TXN logger.
*/
SpiLogger txn();
/**
* Return the Summary logger.
*/
SpiLogger sum();
}
@@ -14,18 +14,9 @@ public interface SpiLogger {
*/
boolean isDebug();
/**
* Is trace logging enabled.
*/
boolean isTrace();
/**
* Log a debug level message.
*/
void debug(String msg);
void debug(String msg, Object... args);
/**
* Log a trace level message.
*/
void trace(String msg);
}
@@ -27,10 +27,6 @@ public interface SpiTransaction extends Transaction {
*/
String getLabel();
/**
* Return the string prefix with the transaction id and label used in logging.
*/
String getLogPrefix();
/**
* Return true if generated SQL and Bind values should be logged to the
@@ -47,12 +43,17 @@ public interface SpiTransaction extends Transaction {
/**
* Log a message to the SQL logger.
*/
void logSql(String msg);
void logSql(String msg, Object... args);
/**
* Log a message to the SUMMARY logger.
* Log a summary message to the SUMMARY logger.
*/
void logSummary(String msg);
void logSummary(String msg, Object... args);
/**
* Log a transaction message to the transaction logger.
*/
void logTxn(String msg, Object... args);
/**
* Register a "Deferred Relationship" that requires an additional update later.
@@ -137,10 +137,6 @@ public abstract class SpiTransactionProxy implements SpiTransaction {
transaction.setDocStoreBatchSize(batchSize);
}
@Override
public String getLogPrefix() {
return transaction.getLogPrefix();
}
@Override
public boolean isLogSql() {
@@ -153,13 +149,18 @@ public abstract class SpiTransactionProxy implements SpiTransaction {
}
@Override
public void logSql(String msg) {
transaction.logSql(msg);
public void logSql(String msg, Object... args) {
transaction.logSql(msg, args);
}
@Override
public void logSummary(String msg) {
transaction.logSummary(msg);
public void logSummary(String msg, Object... args) {
transaction.logSummary(msg, args);
}
@Override
public void logTxn(String msg, Object... args) {
transaction.logTxn(msg, args);
}
@Override
@@ -0,0 +1,49 @@
package io.ebeaninternal.api;
/**
* Per Transaction logging of SQL, TXN and Summary messages.
*/
public interface SpiTxnLogger {
String id();
/**
* Is debug logging enabled.
*/
boolean isLogSql();
/**
* Is summary logging enabled.
*/
boolean isLogSummary();
/**
* Log a SQL message.
*/
void sql(String msg, Object... args);
/**
* Log a Summary message.
*/
void sum(String msg, Object... args);
/**
* Log a Transaction message.
*/
void txn(String msg, Object... args);
/**
* Transaction Committed.
*/
void notifyCommit();
/**
* Query only transaction completed.
*/
void notifyQueryOnly();
/**
* Transaction Rolled back.
*/
void notifyRollback(Throwable cause);
}
@@ -44,7 +44,10 @@ public class DefaultServerCache implements ServerCache {
protected final CountMetric removeCount;
protected final CountMetric clearCount;
protected final CountMetric evictCount;
protected final CountMetric gcCount;
protected final CountMetric idleCount;
protected final CountMetric ttlCount;
protected final CountMetric lruCount;
protected final String name;
protected final String shortName;
protected final int maxSize;
@@ -55,6 +58,7 @@ public class DefaultServerCache implements ServerCache {
protected final ReentrantLock lock = new ReentrantLock();
protected final AtomicLong mutationCounter = new AtomicLong();
public DefaultServerCache(DefaultServerCacheConfig config) {
this.name = config.getName();
this.shortName = config.getShortName();
@@ -73,6 +77,11 @@ public class DefaultServerCache implements ServerCache {
this.removeCount = factory.createCountMetric(prefix + shortName + ".remove");
this.clearCount = factory.createCountMetric(prefix + shortName + ".clear");
this.evictCount = factory.createCountMetric(prefix + shortName + ".evict");
this.gcCount = factory.createCountMetric(prefix + shortName + ".gc");
this.idleCount = factory.createCountMetric(prefix + shortName + ".idle");
this.ttlCount = factory.createCountMetric(prefix + shortName + ".ttl");
this.lruCount = factory.createCountMetric(prefix + shortName + ".lru");
}
public void periodicTrim(BackgroundExecutor executor) {
@@ -90,6 +99,10 @@ public class DefaultServerCache implements ServerCache {
removeCount.visit(visitor);
clearCount.visit(visitor);
evictCount.visit(visitor);
gcCount.visit(visitor);
idleCount.visit(visitor);
ttlCount.visit(visitor);
lruCount.visit(visitor);
}
@Override
@@ -104,6 +117,10 @@ public class DefaultServerCache implements ServerCache {
cacheStats.setRemoveCount(removeCount.get(reset));
cacheStats.setClearCount(clearCount.get(reset));
cacheStats.setEvictCount(evictCount.get(reset));
cacheStats.setGcCount(gcCount.get(reset));
cacheStats.setIdleCount(idleCount.get(reset));
cacheStats.setTtlCount(ttlCount.get(reset));
cacheStats.setLruCount(lruCount.get(reset));
return cacheStats;
}
@@ -289,6 +306,12 @@ public class DefaultServerCache implements ServerCache {
evictCount.add(trimmedByGC);
evictCount.add(trimmedByTTL);
evictCount.add(trimmedByLRU);
gcCount.add(trimmedByGC);
idleCount.add(trimmedByIdle);
ttlCount.add(trimmedByTTL);
lruCount.add(trimmedByLRU);
if (logger.isLoggable(TRACE)) {
long exeMicros = TimeUnit.MICROSECONDS.convert(System.nanoTime() - startNanos, TimeUnit.NANOSECONDS);
logger.log(TRACE, "Executed trim of cache {0} in [{1}]millis idle[{2}] timeToLive[{3}] accessTime[{4}] gc[{5}]",
@@ -4,7 +4,6 @@ import io.ebean.CancelableQuery;
import io.ebean.Transaction;
import io.ebean.util.JdbcClose;
import io.ebeaninternal.api.*;
import io.ebeaninternal.server.util.Str;
import io.ebeaninternal.server.persist.Binder;
import io.ebeaninternal.server.persist.TrimLogSql;
import io.ebeaninternal.server.util.BindParamsParser;
@@ -151,7 +150,7 @@ public abstract class AbstractSqlQueryRequest implements CancelableQuery {
}
if (isLogSql()) {
long micros = (System.nanoTime() - startNano) / 1000L;
transaction.logSql(Str.add(TrimLogSql.trim(sql), "; --bind(", bindLog, ") --micros(", micros + ")"));
transaction.logSql("{0}; --bind({1}) --micros({2})", TrimLogSql.trim(sql), bindLog, micros);
}
} finally {
lock.unlock();
@@ -14,10 +14,11 @@ import io.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import io.ebeaninternal.server.transaction.DefaultPersistenceContext;
import javax.persistence.EntityNotFoundException;
import java.text.MessageFormat;
import java.util.List;
import java.util.Set;
import static java.lang.System.Logger.Level.DEBUG;
import static java.lang.System.Logger.Level.*;
/**
* Helper to handle lazy loading and refreshing of beans.
@@ -137,8 +138,12 @@ final class DefaultBeanLoader {
SpiQuery<?> query = server.createQuery(loadRequest.beanType());
loadRequest.configureQuery(query, idList);
List<?> list = executeQuery(loadRequest, query);
loadRequest.postLoad(list);
final List<?> list = executeQuery(loadRequest, query);
final LoadBeanRequest.Result result = loadRequest.postLoad(list);
if (result.markedDeleted() && CoreLog.markedAsDeleted.isLoggable(DEBUG)) {
String msg = MessageFormat.format("Loaded bean marked as deleted for {0} missedIds:{1} loadedIds:{2} sql:{3} list:{4}", loadRequest.beanType(), result.missedIds(), result.loadedIds(), query.getGeneratedSql(), list);
CoreLog.markedAsDeleted.log(DEBUG, msg, new RuntimeException("LoadBeanRequest markedAsDeleted"));
}
}
/**
@@ -229,6 +229,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
persistenceContext.beginIterate();
}
loadContext = new DLoadContext(this, secondaryQueries);
loadContext.useReferences(Type.ITERATE == query.getType());
}
/**
@@ -700,8 +701,8 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
/**
* Log the SQL if the logLevel is appropriate.
*/
public void logSql(String sql) {
transaction.logSql(sql);
public void logSql(String msg, Object... args) {
transaction.logSql(msg, args);
}
/**
@@ -928,20 +928,20 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
}
private void logSummaryMessage() {
String draft = (beanDescriptor.isDraftable() && !publish) ? "] draft[true]" : "]";
String draft = (beanDescriptor.isDraftable() && !publish) ? " draft[true]" : "";
String name = beanDescriptor.name();
switch (type) {
case INSERT:
transaction.logSummary("Inserted [" + name + "] [" + (idValue == null ? "" : idValue) + draft);
transaction.logSummary("Inserted [{0}] [{1}]{2}", name, (idValue == null ? "" : idValue), draft);
break;
case UPDATE:
transaction.logSummary("Updated [" + name + "] [" + idValue + draft);
transaction.logSummary("Updated [{0}] [{1}]{2}", name, idValue , draft);
break;
case DELETE:
transaction.logSummary("Deleted [" + name + "] [" + idValue + draft);
transaction.logSummary("Deleted [{0}] [{1}]{2}", name, idValue , draft);
break;
case DELETE_SOFT:
transaction.logSummary("SoftDelete [" + name + "] [" + idValue + draft);
transaction.logSummary("SoftDelete [{0}] [{1}]{2}", name, idValue , draft);
break;
default:
break;
@@ -1,12 +1,8 @@
package io.ebeaninternal.server.core;
import io.ebean.CallableSql;
import io.ebeaninternal.api.BindParams;
import io.ebeaninternal.api.*;
import io.ebeaninternal.api.BindParams.Param;
import io.ebeaninternal.api.SpiCallableSql;
import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.api.SpiTransaction;
import io.ebeaninternal.api.TransactionEventTable;
import io.ebeaninternal.server.persist.PersistExecute;
import java.sql.CallableStatement;
@@ -86,7 +82,7 @@ public final class PersistRequestCallableSql extends PersistRequest {
persistExecute.collectSqlCall(label, startNanos);
}
if (transaction.isLogSummary()) {
transaction.logSummary("CallableSql label[" + callableSql.getLabel() + "]" + " rows[" + rowCount + "]" + " bind[" + bindLog + "]");
transaction.logSummary("CallableSql label[{0}] rows[{1}] bind[{2}]", callableSql.getLabel(), rowCount, bindLog);
}
// register table modifications with the transaction event
@@ -83,7 +83,7 @@ public final class PersistRequestOrmUpdate extends PersistRequest {
OrmUpdateType ormUpdateType = ormUpdate.getOrmUpdateType();
String tableName = ormUpdate.getBaseTable();
if (transaction.isLogSummary()) {
transaction.logSummary(ormUpdateType + " table[" + tableName + "] rows[" + rowCount + "] bind[" + bindLog + "]");
transaction.logSummary("{0} table[{1}] rows[{2}] bind[{3}]", ormUpdateType, tableName, rowCount, bindLog);
}
if (ormUpdate.isNotifyCache()) {
// add the modification info to the TransactionEvent
@@ -3,7 +3,6 @@ package io.ebeaninternal.server.core;
import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.api.SpiSqlUpdate;
import io.ebeaninternal.api.SpiTransaction;
import io.ebeaninternal.server.util.Str;
import io.ebeaninternal.server.persist.BatchControl;
import io.ebeaninternal.server.persist.PersistExecute;
import io.ebeaninternal.server.persist.TrimLogSql;
@@ -148,7 +147,7 @@ public final class PersistRequestUpdateSql extends PersistRequest {
*/
public void logSqlBatchBind() {
if (transaction.isLogSql()) {
transaction.logSql(Str.add(" -- bind(", bindLog, ")"));
transaction.logSql(" -- bind({0})", bindLog);
}
}
@@ -161,7 +160,7 @@ public final class PersistRequestUpdateSql extends PersistRequest {
persistExecute.collectSqlUpdate(label, startNanos);
}
if (transaction.isLogSql() && !batchThisRequest) {
transaction.logSql(Str.add(TrimLogSql.trim(updateSql.getGeneratedSql()), "; -- bind(", bindLog, ") rows(", String.valueOf(rowCount), ")"));
transaction.logSql("{0}; -- bind({1}) rows({2})", TrimLogSql.trim(updateSql.getGeneratedSql()), bindLog, rowCount);
}
if (updateSql.isAutoTableMod()) {
// add the modification info to the TransactionEvent
@@ -123,7 +123,7 @@ public final class RelationalQueryRequest extends AbstractSqlQueryRequest {
public void logSummary() {
if (transaction.isLogSummary()) {
long micros = (System.nanoTime() - startNano) / 1000L;
transaction.logSummary("SqlQuery rows[" + rows + "] micros[" + micros + "] bind[" + bindLog + "]");
transaction.logSummary("SqlQuery rows[{0}] micros[{1}] bind[{2}]", rows, micros, bindLog);
}
}
@@ -38,13 +38,10 @@ public final class BeanCollectionUtil {
// returns a collection of beans
return bc.getActualEntries();
}
if (o instanceof Map<?, ?>) {
// yes, we want the entrySet (to set the keys)
return ((Map<?, ?>) o).entrySet();
} else if (o instanceof Collection<?>) {
if (o instanceof Collection<?>) {
return ((Collection<?>) o);
} else if (o instanceof Map<?, ?>) {
return ((Map<?, ?>) o).entrySet();
}
throw new PersistenceException("expecting a Map or Collection but got " + o.getClass().getName());
}
@@ -1268,4 +1268,10 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
}
return null;
}
@Override
public ExpressionList<T> clear() {
list.clear();
return this;
}
}
@@ -1068,4 +1068,9 @@ final class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expr
}
return null;
}
@Override
public ExpressionList<T> clear() {
return exprList.clear();
}
}
@@ -58,6 +58,7 @@ public final class DLoadContext implements LoadContext {
private final ProfilingListener profilingListener;
private final Map<String, ObjectGraphNode> nodePathMap = new HashMap<>();
private final PersistenceContext persistenceContext;
boolean useReferences;
private List<OrmQueryProperties> secQuery;
private Object tenantId;
@@ -118,7 +119,6 @@ public final class DLoadContext implements LoadContext {
this.origin = null;
this.relativePath = null;
}
// initialise rootBeanContext after origin and relativePath have been set
this.rootBeanContext = new DLoadBeanContext(this, rootDescriptor, null, null);
registerSecondaryQueries(secondaryQueries);
@@ -156,6 +156,11 @@ public final class DLoadContext implements LoadContext {
}
}
@Override
public void useReferences(boolean useReferences) {
this.useReferences = useReferences;
}
/**
* Setup the load context at this path with OrmQueryProperties which is
* used to build the appropriate query for +query or +lazy loading.
@@ -14,7 +14,10 @@ import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import io.ebeaninternal.server.querydefn.OrmQueryProperties;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
@@ -38,7 +41,7 @@ final class DLoadManyContext extends DLoadBaseContext implements LoadManyContext
}
private LoadBuffer createBuffer(int size) {
LoadBuffer buffer = new LoadBuffer(this, size);
LoadBuffer buffer = parent.useReferences ? new LoadBufferWeakRef(this, size) : new LoadBufferHardRef(this, size);
if (bufferList != null) {
bufferList.add(buffer);
}
@@ -94,7 +97,7 @@ final class DLoadManyContext extends DLoadBaseContext implements LoadManyContext
try {
if (bufferList != null) {
for (LoadBuffer loadBuffer : bufferList) {
if (!loadBuffer.list.isEmpty()) {
if (loadBuffer.size() > 0) {
LoadManyRequest req = new LoadManyRequest(loadBuffer, parentRequest);
parent.getEbeanServer().loadMany(req);
}
@@ -115,13 +118,12 @@ final class DLoadManyContext extends DLoadBaseContext implements LoadManyContext
* A buffer for batch loading bean collections on a given path.
* Supports batch lazy loading and secondary query loading.
*/
static class LoadBuffer implements BeanCollectionLoader, LoadManyBuffer {
static abstract class LoadBuffer implements BeanCollectionLoader, LoadManyBuffer {
private final ReentrantLock lock = new ReentrantLock();
private final PersistenceContext persistenceContext;
private final DLoadManyContext context;
private final int batchSize;
private final List<BeanCollection<?>> list;
final int batchSize;
LoadBuffer(DLoadManyContext context, int batchSize) {
this.context = context;
@@ -129,7 +131,6 @@ final class DLoadManyContext extends DLoadBaseContext implements LoadManyContext
// case it changes as part of a findIterate etc
this.persistenceContext = context.getPersistenceContext();
this.batchSize = batchSize;
this.list = new ArrayList<>(batchSize);
}
@Override
@@ -138,7 +139,7 @@ final class DLoadManyContext extends DLoadBaseContext implements LoadManyContext
}
@Override
public int getBatchSize() {
public int batchSize() {
return batchSize;
}
@@ -146,20 +147,15 @@ final class DLoadManyContext extends DLoadBaseContext implements LoadManyContext
* Return true if the buffer is full.
*/
public boolean isFull() {
return batchSize == list.size();
return batchSize() == size();
}
/**
* Return true if the buffer is full.
*/
public void add(BeanCollection<?> bc) {
list.add(bc);
}
public abstract void add(BeanCollection<?> bc);
@Override
public List<BeanCollection<?>> getBatch() {
return list;
}
abstract void clear();
@Override
public BeanPropertyAssocMany<?> getBeanProperty() {
@@ -208,25 +204,133 @@ final class DLoadManyContext extends DLoadBaseContext implements LoadManyContext
final String parentKey = parentDesc.cacheKey(parentId);
if (parentDesc.cacheManyPropLoad(context.property, bc, parentKey, context.parent.isReadOnly())) {
// we loaded the bean collection from cache so remove it from the buffer
for (int i = 0; i < list.size(); i++) {
// find it using instance equality - avoiding equals() and potential deadlock issue
if (list.get(i) == bc) {
list.remove(i);
bc.setLoader(context.parent.getEbeanServer());
return;
}
if (removeFromBuffer(bc)) {
bc.setLoader(context.parent.getEbeanServer());
}
// find it using instance equality - avoiding equals() and potential deadlock issue
return;
}
}
context.parent.getEbeanServer().loadMany(new LoadManyRequest(this, onlyIds, useCache));
// clear the buffer as all entries have been loaded
list.clear();
clear();
} finally {
lock.unlock();
}
}
}
static class LoadBufferHardRef extends LoadBuffer {
private final BeanCollection<?>[] list;
private int size;
LoadBufferHardRef(DLoadManyContext context, int batchSize) {
super(context, batchSize);
this.list = new BeanCollection<?>[batchSize];
}
/**
* Return true if the buffer is full.
*/
@Override
public void add(BeanCollection<?> bc) {
list[size++] = bc;
}
@Override
void clear() {
Arrays.fill(list, null);
size = 0;
}
@Override
public int size() {
return size;
}
@Override
public BeanCollection<?> get(int i) {
return list[i];
}
@Override
public boolean removeFromBuffer(BeanCollection<?> collection) {
for (int i = 0; i < size; i++) {
// find it using instance equality - avoiding equals() and potential deadlock issue
if (list[i] == collection) {
list[i] = null;
return true;
}
}
return false;
}
}
/**
* This load buffer uses weak references, so unreachable beanCollections will drop out from the buffer.
*/
static class LoadBufferWeakRef extends LoadBuffer {
private final Reference<BeanCollection<?>>[] list;
private int size;
LoadBufferWeakRef(DLoadManyContext context, int batchSize) {
super(context, batchSize);
this.list = new Reference[batchSize];
}
/**
* Return true if the buffer is full.
*/
@Override
public void add(BeanCollection<?> bc) {
list[size++] = new WeakReference<>(bc);
}
@Override
void clear() {
Arrays.fill(list, null);
size = 0;
}
@Override
public int size() {
return size;
}
@Override
public BeanCollection<?> get(int i) {
Reference<BeanCollection<?>> ref = list[i];
if (ref == null) {
return null;
}
BeanCollection<?> bc = ref.get();
if (bc == null) {
// remove dead references
list[i] = null;
}
return bc;
}
@Override
public boolean removeFromBuffer(BeanCollection<?> collection) {
for (int i = 0; i < size; i++) {
if (list[i] != null) {
BeanCollection<?> bc = list[i].get();
if (bc == null) {
// remove dead references
list[i] = null;
}
// find it using instance equality - avoiding equals() and potential deadlock issue
if (bc == collection) {
list[i] = null;
return true;
}
}
}
return false;
}
}
}
@@ -2,22 +2,30 @@ package io.ebeaninternal.server.logger;
import io.ebeaninternal.api.SpiLogManager;
import io.ebeaninternal.api.SpiLogger;
import io.ebeaninternal.api.SpiTxnLogger;
import java.util.concurrent.atomic.AtomicLong;
public final class DLogManager implements SpiLogManager {
private final SpiLogger sql;
private final SpiLogger summary;
private final SpiLogger txn;
private final boolean useIds;
private final AtomicLong counter = new AtomicLong(1000);
private final DTxnLogger readOnly;
public DLogManager(SpiLogger sql, SpiLogger summary, SpiLogger txn) {
this.sql = sql;
this.summary = summary;
this.txn = txn;
this.useIds = txn.isDebug();
this.readOnly = new DTxnLogger(null, sql, summary, txn);
}
@Override
public SpiLogger txn() {
return txn;
public boolean enableBindLog() {
return sql.isDebug();
}
@Override
@@ -26,8 +34,13 @@ public final class DLogManager implements SpiLogManager {
}
@Override
public SpiLogger sum() {
return summary;
public SpiTxnLogger logger() {
String id = useIds ? Long.toString(counter.incrementAndGet()) : "";
return new DTxnLogger(id, sql, summary, txn);
}
@Override
public SpiTxnLogger readOnlyLogger() {
return readOnly;
}
}
@@ -3,7 +3,6 @@ package io.ebeaninternal.server.logger;
import io.ebeaninternal.api.SpiLogger;
import static java.lang.System.Logger.Level.DEBUG;
import static java.lang.System.Logger.Level.TRACE;
final class DSpiLogger implements SpiLogger {
@@ -19,17 +18,7 @@ final class DSpiLogger implements SpiLogger {
}
@Override
public boolean isTrace() {
return logger.isLoggable(TRACE);
}
@Override
public void debug(String msg) {
logger.log(DEBUG, msg);
}
@Override
public void trace(String msg) {
logger.log(TRACE, msg);
public void debug(String msg, Object... args) {
logger.log(DEBUG, msg, args);
}
}
@@ -0,0 +1,96 @@
package io.ebeaninternal.server.logger;
import io.ebeaninternal.api.SpiLogger;
import io.ebeaninternal.api.SpiTxnLogger;
import io.ebeaninternal.server.util.Str;
final class DTxnLogger implements SpiTxnLogger {
private final String id;
private final String logPrefix;
private final SpiLogger sql;
private final SpiLogger sum;
private final SpiLogger txn;
DTxnLogger(String id, SpiLogger sql, SpiLogger sum, SpiLogger txn) {
this.id = id;
this.logPrefix = id == null ? "" : "txn[" + id + "] ";
this.sql = sql;
this.sum = sum;
this.txn = txn;
}
@Override
public String id() {
return id;
}
@Override
public boolean isLogSql() {
return sql.isDebug();
}
@Override
public boolean isLogSummary() {
return sum.isDebug();
}
@Override
public void sql(String msg, Object... args) {
sql.debug(Str.add(logPrefix, msg), args);
}
@Override
public void sum(String msg, Object... args) {
sum.debug(Str.add(logPrefix, msg), args);
}
@Override
public void txn(String msg, Object... args) {
txn.debug(Str.add(logPrefix, msg), args);
}
@Override
public void notifyCommit() {
txn.debug(Str.add(logPrefix, "Commit"));
}
@Override
public void notifyQueryOnly() {
// do nothing
}
@Override
public void notifyRollback(Throwable cause) {
if (txn.isDebug()) {
String msg = logPrefix + "Rollback";
if (cause != null) {
msg += " error: " + formatThrowable(cause);
}
txn.debug(msg);
}
}
private String formatThrowable(Throwable e) {
if (e == null) {
return "";
}
StringBuilder sb = new StringBuilder();
formatThrowable(e, sb);
return sb.toString();
}
private void formatThrowable(Throwable e, StringBuilder sb) {
sb.append(e.toString());
StackTraceElement[] stackTrace = e.getStackTrace();
if (stackTrace.length > 0) {
sb.append(" stack0: ");
sb.append(stackTrace[0]);
}
Throwable cause = e.getCause();
if (cause != null) {
sb.append(" cause: ");
formatThrowable(cause, sb);
}
}
}
@@ -313,7 +313,7 @@ public final class BatchControl {
BatchedBeanHolder[] bsArray = beanHolderArray();
Arrays.sort(bsArray, depthComparator);
if (transaction.isLogSummary()) {
transaction.logSummary("BatchControl flush " + Arrays.toString(bsArray));
transaction.logSummary("BatchControl flush {0}", Arrays.toString(bsArray));
}
for (BatchedBeanHolder beanHolder : bsArray) {
beanHolder.executeNow();
@@ -44,7 +44,7 @@ public final class Binder {
this.dbExpressionHandler = dbExpressionHandler;
this.dataTimeZone = dataTimeZone;
this.multiValueBind = multiValueBind;
this.enableBindLog = logManager.sql().isDebug();
this.enableBindLog = logManager.enableBindLog();
}
/**
@@ -672,7 +672,7 @@ public final class DefaultPersister implements Persister {
if (idList != null) {
q.where().idIn(idList);
if (t.isLogSummary()) {
t.logSummary("-- DeleteById of " + descriptor.name() + " ids[" + idList + "] requires fetch of foreign key values");
t.logSummary("-- DeleteById of {0} ids[{1}] requires fetch of foreign key values", descriptor.name(), idList);
}
List<?> beanList = server.findList(q, t);
deleteCascade(beanList, t, deleteMode, false);
@@ -681,7 +681,7 @@ public final class DefaultPersister implements Persister {
} else {
q.where().idEq(id);
if (t.isLogSummary()) {
t.logSummary("-- DeleteById of " + descriptor.name() + " id[" + id + "] requires fetch of foreign key values");
t.logSummary("-- DeleteById of {0} id[{1}] requires fetch of foreign key values", descriptor.name(), id);
}
EntityBean bean = (EntityBean) server.findOne(q, t);
if (bean == null) {
@@ -741,7 +741,7 @@ public final class DefaultPersister implements Persister {
for (BeanPropertyAssocMany<?> many : manys) {
SqlUpdate sqlDelete = many.deleteByParentId(id, idList);
if (t.isLogSummary()) {
t.logSummary("-- Deleting intersection table entries: " + many.fullName());
t.logSummary("-- Deleting intersection table entries: {0}", many.fullName());
}
executeSqlUpdate(sqlDelete, t);
}
@@ -751,9 +751,9 @@ public final class DefaultPersister implements Persister {
SqlUpdate deleteById = descriptor.deleteById(id, idList, deleteMode);
if (t.isLogSummary()) {
if (idList != null) {
t.logSummary("-- Deleting " + descriptor.name() + " Ids: " + idList);
t.logSummary("-- Deleting {0} Ids: {1}", descriptor.name(), idList);
} else {
t.logSummary("-- Deleting " + descriptor.name() + " Id: " + id);
t.logSummary("-- Deleting {0} Id: {1}", descriptor.name(), id);
}
}
@@ -861,7 +861,7 @@ public final class DefaultPersister implements Persister {
SpiTransaction t = request.transaction();
EntityBean orphanForRemoval = request.importedOrphanForRemoval();
if (orphanForRemoval != null) {
delete(orphanForRemoval, request.transaction(), true);
delete(orphanForRemoval, request.transaction(), false);
}
// exported ones with cascade save
@@ -1079,7 +1079,7 @@ public final class DefaultPersister implements Persister {
private void deleteOrphan(PersistRequestBean<?> request, BeanPropertyAssocOne<?> prop) {
Object origValue = request.getOrigValue(prop);
if (origValue instanceof EntityBean) {
delete((EntityBean) origValue, request.transaction(), true);
delete((EntityBean) origValue, request.transaction(), false);
}
}
@@ -69,7 +69,7 @@ final class DeleteUnloadedForeignKeys {
SpiTransaction t = request.transaction();
if (t.isLogSummary()) {
t.logSummary("-- Ebean fetching foreign key values for delete of " + descriptor.name() + " id:" + id);
t.logSummary("-- Ebean fetching foreign key values for delete of {0} id:{1}", descriptor.name(), id);
}
beanWithForeignKeys = (EntityBean) server.findOne(q, t);
}
@@ -35,8 +35,9 @@ final class SaveManyBeans extends SaveManyBase {
private final boolean untouchedBeanCollection;
private final Collection<?> collection;
private final boolean hasOrderColumn;
private final boolean forcedUpdate;
private int sortOrder;
private boolean insertAllChildren;
private boolean forceOrphanRemoval;
SaveManyBeans(DefaultPersister persister, boolean insertedParent, BeanPropertyAssocMany<?> many, EntityBean parentBean, PersistRequestBean<?> request) {
super(persister, insertedParent, many, parentBean, request);
@@ -49,6 +50,7 @@ final class SaveManyBeans extends SaveManyBase {
this.untouchedBeanCollection = untouchedBeanCollection();
this.collection = cascade ? BeanCollectionUtil.getActualEntries(value) : null;
this.hasOrderColumn = many.hasOrderColumn();
this.forcedUpdate = request.isForcedUpdate();
}
/**
@@ -127,10 +129,8 @@ final class SaveManyBeans extends SaveManyBase {
targetDescriptor.preAllocateIds(collection.size());
}
if (forcedUpdateOrphanRemoval()) {
// collect the Id's (to exclude from deleteManyDetails)
List<Object> detailIds = collectIds(collection, targetDescriptor, isMap);
// deleting missing children - children not in our collected detailIds
persister.deleteManyDetails(transaction, many.descriptor(), parentBean, many, detailIds, deleteMode);
// deleting orphans, anything not in our detailsIds
persister.deleteManyDetails(transaction, many.descriptor(), parentBean, many, detailIds(), deleteMode);
}
transaction.depth(+1);
saveAllBeans(orderColumn);
@@ -141,7 +141,7 @@ final class SaveManyBeans extends SaveManyBase {
}
private boolean forcedUpdateOrphanRemoval() {
return !insertedParent && many.isOrphanRemoval() && request.isForcedUpdate();
return !insertedParent && many.isOrphanRemoval() && (forceOrphanRemoval || forcedUpdate);
}
private void saveAllBeans(final BeanProperty orderColumn) {
@@ -177,10 +177,6 @@ final class SaveManyBeans extends SaveManyBase {
skipSavingThisBean = false;
// set the parent bean to detailBean
many.setJoinValuesToChild(parentBean, detail, mapKeyValue);
} else if (insertAllChildren) {
ebi.setNew();
skipSavingThisBean = false;
many.setJoinValuesToChild(parentBean, detail, mapKeyValue);
} else {
skipSavingThisBean = saveRecurseSkippable;
}
@@ -215,12 +211,10 @@ final class SaveManyBeans extends SaveManyBase {
}
/**
* Collect the Id values of the details to remove 'missing children' for stateless updates.
* Return the Id values of beans we know are being updated (any others are orphans)
*/
private List<Object> collectIds(Collection<?> collection, BeanDescriptor<?> targetDescriptor, boolean isMap) {
List<Object> detailIds = new ArrayList<>();
// stateless update with deleteMissingChildren so first
// collect the Id values to remove the 'missing children'
private List<Object> detailIds() {
final var detailIds = new ArrayList<>();
for (Object detailBean : collection) {
if (isMap) {
detailBean = ((Map.Entry<?, ?>) detailBean).getValue();
@@ -228,8 +222,10 @@ final class SaveManyBeans extends SaveManyBase {
if (detailBean instanceof EntityBean) {
Object id = targetDescriptor.id(detailBean);
if (!isNullOrZero(id)) {
// remember the Id (other details not in the collection) will be removed
detailIds.add(id);
if (forcedUpdate || !((EntityBean) detailBean)._ebean_getIntercept().isNew()) {
// Id of bean that will be updated, exclude it from orphan removal
detailIds.add(id);
}
}
}
}
@@ -261,8 +257,7 @@ final class SaveManyBeans extends SaveManyBase {
}
private void saveAssocManyIntersection(boolean queue) {
boolean forcedUpdate = request.isForcedUpdate();
boolean vanillaCollection = !(value instanceof BeanCollection<?>);
final boolean vanillaCollection = !(value instanceof BeanCollection<?>);
if (vanillaCollection || forcedUpdate) {
// delete all intersection rows and then treat all
// beans in the collection as additions
@@ -321,7 +316,7 @@ final class SaveManyBeans extends SaveManyBase {
CoreLog.log.log(System.Logger.Level.WARNING, m);
} else {
if (!many.hasImportedId(otherBean)) {
throw new PersistenceException("ManyToMany bean " + otherBean + " does not have an Id value.");
throw new PersistenceException("ManyToMany bean does not have an Id value? " + otherBean);
} else {
// build a intersection row for 'insert'
IntersectionRow intRow = many.buildManyToManyMapBean(parentBean, otherBean, publish);
@@ -344,10 +339,7 @@ final class SaveManyBeans extends SaveManyBase {
return;
}
if (!(value instanceof BeanCollection<?>)) {
if (!forcedUpdateOrphanRemoval() && (!insertedParent && cascade && isChangedProperty())) {
persister.addToFlushQueue(many.deleteByParentId(request.beanId(), null), transaction, 0);
insertAllChildren = true;
}
forceOrphanRemoval = !insertedParent && isChangedProperty();
} else {
BeanCollection<?> c = (BeanCollection<?>) value;
Set<?> modifyRemovals = c.getModifyRemovals();
@@ -359,7 +351,9 @@ final class SaveManyBeans extends SaveManyBase {
if (!hasOrderColumn) {
c.modifyReset();
}
if (modifyRemovals != null && !modifyRemovals.isEmpty()) {
if (modifyRemovals == null || modifyRemovals.isEmpty()) {
forceOrphanRemoval = !insertedParent && isChangedProperty();
} else {
for (Object removedBean : modifyRemovals) {
if (removedBean instanceof EntityBean) {
EntityBean eb = (EntityBean) removedBean;
@@ -8,7 +8,6 @@ import io.ebeaninternal.server.persist.BatchedPstmt;
import io.ebeaninternal.server.persist.BatchedPstmtHolder;
import io.ebeaninternal.server.persist.dmlbind.BindableRequest;
import io.ebeaninternal.server.bind.DataBind;
import io.ebeaninternal.server.util.Str;
import javax.persistence.OptimisticLockException;
import java.sql.Connection;
@@ -102,7 +101,7 @@ public abstract class DmlHandler implements PersistHandler, BindableRequest {
} catch (OptimisticLockException e) {
// add the SQL and bind values to error message
final String m = e.getMessage() + " sql[" + sql + "] bind[" + bindLog + "]";
persistRequest.transaction().logSummary("OptimisticLockException:" + m);
persistRequest.transaction().logSummary("OptimisticLockException:{0}", m);
throw new OptimisticLockException(m, null, e.getEntity());
}
}
@@ -146,15 +145,15 @@ public abstract class DmlHandler implements PersistHandler, BindableRequest {
switch (batchedStatus) {
case BATCHED_FIRST: {
transaction.logSql(sql);
transaction.logSql(Str.add(" -- bind(", bindLog.toString(), ")"));
transaction.logSql(" -- bind({0})", bindLog);
return;
}
case BATCHED: {
transaction.logSql(Str.add(" -- bind(", bindLog.toString(), ")"));
transaction.logSql(" -- bind({0})", bindLog);
return;
}
default: {
transaction.logSql(Str.add(sql, "; -- bind(", bindLog.toString(), ")"));
transaction.logSql("{0}; -- bind({1})", sql, bindLog);
}
}
}
@@ -18,7 +18,6 @@ import io.ebeaninternal.server.core.OrmQueryRequest;
import io.ebeaninternal.server.core.SpiResultSet;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.persist.Binder;
import io.ebeaninternal.server.util.Str;
import javax.persistence.PersistenceException;
import java.sql.ResultSet;
@@ -73,7 +72,7 @@ public final class CQueryEngine {
try {
int rows = query.execute();
if (request.logSql()) {
request.logSql(Str.add(query.generatedSql(), "; --bind(", query.bindLog(), ") --micros(", query.micros() + ") --rows(", rows + ")"));
request.logSql("{0}; --bind({1}) --micros({2}) --rows({3})", query.generatedSql(), query.bindLog(), query.micros(), rows);
}
return rows;
} catch (SQLException e) {
@@ -129,7 +128,7 @@ public final class CQueryEngine {
SpiTransaction t = request.transaction();
if (t.isLogSummary()) {
// log the error to the transaction log
t.logSummary("ERROR executing query, bindLog[" + bindLog + "] error:" + StringHelper.removeNewLines(e.getMessage()));
t.logSummary("ERROR executing query, bindLog[{0}] error:{1}", bindLog, StringHelper.removeNewLines(e.getMessage()));
}
// ensure 'rollback' is logged if queryOnly transaction
t.connection();
@@ -147,7 +146,7 @@ public final class CQueryEngine {
}
private <T> void logGeneratedSql(OrmQueryRequest<T> request, String sql, String bindLog, long micros) {
request.logSql(Str.add(sql, "; --bind(", bindLog, ") --micros(", micros + ")"));
request.logSql("{0}; --bind({1}) --micros({2})", sql, bindLog, micros);
}
/**
@@ -403,7 +402,7 @@ public final class CQueryEngine {
* Log the generated SQL to the transaction log.
*/
private void logSql(CQuery<?> query) {
query.transaction().logSql(Str.add(query.generatedSql(), "; --bind(", query.bindLog(), ") --micros(", query.micros() + ")"));
query.transaction().logSql("{0}; --bind({1}) --micros({2})", query.generatedSql(), query.bindLog(), query.micros());
}
/**
@@ -5,6 +5,7 @@ import io.ebean.bean.EntityBean;
import io.ebean.bean.EntityBeanIntercept;
import io.ebean.bean.PersistenceContext;
import io.ebean.core.type.ScalarDataReader;
import io.ebeaninternal.api.CoreLog;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.api.SpiQuery.Mode;
import io.ebeaninternal.server.deploy.DbReadContext;
@@ -14,6 +15,8 @@ import io.ebeaninternal.server.deploy.id.IdBinder;
import java.sql.SQLException;
import java.util.Map;
import static java.lang.System.Logger.Level.DEBUG;
/**
* Normal bean included in the query.
*/
@@ -211,6 +214,9 @@ class SqlTreeLoadBean implements SqlTreeLoad {
contextBean = ((STreePropertyAssocOne)nodeBeanProp).valueAsEntityBean(parentBean);
if (contextBean != null) {
desc.markAsDeleted(contextBean);
if (CoreLog.markedAsDeleted.isLoggable(DEBUG)) {
CoreLog.markedAsDeleted.log(DEBUG, contextBean + " contextBean markedAsDeleted", new RuntimeException(contextBean + " contextBean markedAsDeleted"));
}
}
}
}
@@ -2,7 +2,6 @@ package io.ebeaninternal.server.querydefn;
import io.avaje.lang.NonNullApi;
import io.ebean.*;
import io.ebean.OrderBy.Property;
import io.ebean.bean.CallOrigin;
import io.ebean.bean.ObjectGraphNode;
import io.ebean.bean.ObjectGraphOrigin;
@@ -420,7 +419,7 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
havingExpressions.containsMany(beanDescriptor, manyWhere);
}
if (orderBy != null) {
for (Property orderProperty : orderBy.getProperties()) {
for (OrderBy.Property orderProperty : orderBy.getProperties()) {
ElPropertyDeploy elProp = beanDescriptor.elPropertyDeploy(orderProperty.getProperty());
if (elProp != null && elProp.containsFormulaWithJoin()) {
manyWhere.addFormulaWithJoin(elProp.elPrefix(), elProp.name());
@@ -460,10 +459,10 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
for (OrmQueryProperties joinPath : queryJoins) {
// loop through the orderBy properties and
// move any ones related to the query join
List<Property> properties = orderBy.getProperties();
Iterator<Property> it = properties.iterator();
List<OrderBy.Property> properties = orderBy.getProperties();
Iterator<OrderBy.Property> it = properties.iterator();
while (it.hasNext()) {
Property property = it.next();
OrderBy.Property property = it.next();
if (property.getProperty().startsWith(joinPath.getPath())) {
// remove this orderBy segment and
// add it to the secondary join
@@ -1963,7 +1962,7 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
havingExpressions.validate(validation);
}
if (orderBy != null) {
for (Property property : orderBy.getProperties()) {
for (OrderBy.Property property : orderBy.getProperties()) {
validation.validate(property.getProperty());
}
}
@@ -2,6 +2,7 @@ package io.ebeaninternal.server.querydefn;
import io.ebean.ExpressionList;
import io.ebean.ProfileLocation;
import io.ebean.Query;
import io.ebean.UpdateQuery;
import io.ebean.core.type.ScalarType;
import io.ebeaninternal.server.deploy.BeanDescriptor;
@@ -34,6 +35,16 @@ public final class DefaultUpdateQuery<T> implements UpdateQuery<T> {
return this;
}
@Override
public <P> UpdateQuery<T> set(Query.Property<P> property, P value) {
return set(property.toString(), value);
}
@Override
public UpdateQuery<T> setNull(Query.Property<?> property) {
return setNull(property.toString());
}
@Override
public UpdateQuery<T> setNull(String property) {
values.setNull(property);
@@ -10,8 +10,8 @@ public final class DocStoreOnlyTransaction extends JdbcTransaction {
/**
* Create a new DocStore only Transaction.
*/
public DocStoreOnlyTransaction(String id, boolean explicit, TransactionManager manager) {
super(id, explicit, null, manager);
public DocStoreOnlyTransaction(boolean explicit, TransactionManager manager) {
super(explicit, null, manager);
}
@Override
@@ -25,11 +25,11 @@ public final class DocStoreTransactionManager extends TransactionManager {
@Override
public SpiTransaction createReadOnlyTransaction(Object tenantId) {
return new DocStoreOnlyTransaction("", false, this);
return new DocStoreOnlyTransaction(false, this);
}
@Override
protected SpiTransaction createTransaction(boolean explicit, Connection c) {
return new DocStoreOnlyTransaction(nextTxnId(), explicit, this);
return new DocStoreOnlyTransaction(explicit, this);
}
}
@@ -25,14 +25,14 @@ public class ExternalJdbcTransaction extends JdbcTransaction {
* </p>
*/
public ExternalJdbcTransaction(Connection connection) {
super(null, true, connection, null);
super(true, connection, null);
}
/**
* Construct will all explicit parameters.
*/
public ExternalJdbcTransaction(String id, boolean explicit, Connection connection, TransactionManager manager) {
super(id, explicit, connection, manager);
public ExternalJdbcTransaction(boolean explicit, Connection connection, TransactionManager manager) {
super(explicit, connection, manager);
}
/**
@@ -33,6 +33,7 @@ final class ImplicitReadOnlyTransaction implements SpiTransaction, TxnProfileEve
private static final String notExpectedMessage = "Not expected on read only transaction";
private final TransactionManager manager;
private final SpiTxnLogger logger;
private final boolean logSql;
private final boolean logSummary;
@@ -61,8 +62,9 @@ final class ImplicitReadOnlyTransaction implements SpiTransaction, TxnProfileEve
*/
ImplicitReadOnlyTransaction(TransactionManager manager, Connection connection) {
this.manager = manager;
this.logSql = manager.isLogSql();
this.logSummary = manager.isLogSummary();
this.logger = manager.loggerReadOnly();
this.logSql = logger.isLogSql();
this.logSummary = logger.isLogSummary();
this.active = true;
this.connection = connection;
this.persistenceContext = new DefaultPersistenceContext();
@@ -147,11 +149,6 @@ final class ImplicitReadOnlyTransaction implements SpiTransaction, TxnProfileEve
public void setSkipCache(boolean skipCache) {
}
@Override
public String getLogPrefix() {
return null;
}
@Override
public void addBeanChange(BeanChange beanChange) {
throw new IllegalStateException(notExpectedMessage);
@@ -433,13 +430,18 @@ final class ImplicitReadOnlyTransaction implements SpiTransaction, TxnProfileEve
}
@Override
public void logSql(String msg) {
manager.log().sql().debug(msg);
public void logSql(String msg, Object... args) {
logger.sql(msg, args);
}
@Override
public void logSummary(String msg) {
manager.log().sum().debug(msg);
public void logSummary(String msg, Object... args) {
logger.sum(msg, args);
}
@Override
public void logTxn(String msg, Object... args) {
// never called
}
/**
@@ -11,7 +11,6 @@ import io.ebeaninternal.server.core.PersistDeferredRelationship;
import io.ebeaninternal.server.core.PersistRequestBean;
import io.ebeaninternal.server.persist.BatchControl;
import io.ebeaninternal.server.persist.BatchedSqlException;
import io.ebeaninternal.server.util.Str;
import io.ebeanservice.docstore.api.DocStoreTransaction;
import javax.persistence.PersistenceException;
@@ -33,8 +32,8 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes {
private static final String illegalStateMessage = "Transaction is Inactive";
final TransactionManager manager;
private final SpiTxnLogger logger;
private final String id;
private final String logPrefix;
private final boolean logSql;
private final boolean logSummary;
private final boolean explicit;
@@ -95,17 +94,17 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes {
private final long startNanos;
private boolean autoPersistUpdates;
JdbcTransaction(String id, boolean explicit, Connection connection, TransactionManager manager) {
JdbcTransaction(boolean explicit, Connection connection, TransactionManager manager) {
try {
this.active = true;
this.id = id;
this.logPrefix = deriveLogPrefix(id);
this.explicit = explicit;
this.manager = manager;
this.connection = connection;
this.persistenceContext = new DefaultPersistenceContext();
this.startNanos = System.nanoTime();
if (manager == null) {
this.logger = null;
this.id = "";
this.logSql = false;
this.logSummary = false;
this.skipCacheAfterWrite = true;
@@ -113,9 +112,11 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes {
this.batchOnCascadeMode = false;
this.onQueryOnlyCommit = false;
} else {
this.logger = manager.logger();
this.id = logger.id();
this.autoPersistUpdates = explicit && manager.isAutoPersistUpdates();
this.logSql = manager.isLogSql();
this.logSummary = manager.isLogSummary();
this.logSql = logger.isLogSql();
this.logSummary = logger.isLogSummary();
this.skipCacheAfterWrite = manager.isSkipCacheAfterWrite();
this.batchMode = manager.isPersistBatch();
this.batchOnCascadeMode = manager.isPersistBatchOnCascade();
@@ -188,16 +189,7 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes {
}
}
private static String deriveLogPrefix(String id) {
StringBuilder sb = new StringBuilder();
sb.append("txn[");
if (id != null) {
sb.append(id);
}
sb.append("] ");
return sb.toString();
}
@Override
public final void setAutoPersistUpdates(boolean autoPersistUpdates) {
@@ -226,17 +218,13 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes {
this.skipCache = skipCache;
}
@Override
public final String getLogPrefix() {
return logPrefix;
}
@Override
public String toString() {
if (active) {
return logPrefix;
return id;
} else {
return logPrefix + "(inactive)";
return id + "(inactive)";
}
}
@@ -726,13 +714,18 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes {
}
@Override
public final void logSql(String msg) {
manager.log().sql().debug(Str.add(logPrefix, msg));
public void logSql(String msg, Object... args) {
logger.sql(msg, args);
}
@Override
public final void logSummary(String msg) {
manager.log().sum().debug(Str.add(logPrefix, msg));
public final void logSummary(String msg, Object... args) {
logger.sum(msg, args);
}
@Override
public void logTxn(String msg, Object... args) {
logger.txn(msg, args);
}
/**
@@ -805,9 +798,11 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes {
final void notifyCommit() {
if (manager != null) {
if (queryOnly) {
logger.notifyQueryOnly();
manager.notifyOfQueryOnly(this);
} else {
manager.notifyOfCommit(this);
logger.notifyCommit();
}
}
}
@@ -966,6 +961,7 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes {
manager.notifyOfQueryOnly(this);
} else {
manager.notifyOfRollback(this, cause);
logger.notifyRollback(cause);
}
}
}
@@ -20,8 +20,8 @@ public final class JtaTransaction extends JdbcTransaction {
/**
* Create the JtaTransaction.
*/
public JtaTransaction(String id, boolean explicit, UserTransaction utx, DataSource ds, TransactionManager manager) {
super(id, explicit, null, manager);
public JtaTransaction(boolean explicit, UserTransaction utx, DataSource ds, TransactionManager manager) {
super(explicit, null, manager);
userTransaction = utx;
try {
newTransaction = userTransaction.getStatus() == Status.STATUS_NO_TRANSACTION;
@@ -105,8 +105,7 @@ public final class JtaTransactionManager implements ExternalTransactionManager {
// This is a transaction that Ebean has not seen before.
// "wrap" it in a Ebean specific JtaTransaction
String txnId = String.valueOf(System.currentTimeMillis());
JtaTransaction newTrans = new JtaTransaction(txnId, true, ut, dataSource(), transactionManager);
JtaTransaction newTrans = new JtaTransaction( true, ut, dataSource(), transactionManager);
// create and register transaction listener
JtaTxnListener txnListener = createJtaTxnListener(newTrans);
@@ -117,10 +117,6 @@ final class NoTransaction implements SpiTransaction {
// do nothing
}
@Override
public String getLogPrefix() {
return null;
}
@Override
public boolean isLogSql() {
@@ -133,12 +129,17 @@ final class NoTransaction implements SpiTransaction {
}
@Override
public void logSql(String msg) {
public void logSql(String msg, Object... args) {
}
@Override
public void logSummary(String msg) {
public void logSummary(String msg, Object... args) {
}
@Override
public void logTxn(String msg, Object... args) {
}
@@ -21,7 +21,6 @@ final class SavepointTransaction extends SpiTransactionProxy {
private final TransactionManager manager;
private final Savepoint savepoint;
private final Connection connection;
private final String logPrefix;
private final String spPrefix;
private boolean rollbackOnly;
@@ -33,13 +32,12 @@ final class SavepointTransaction extends SpiTransactionProxy {
this.transaction = transaction;
this.connection = transaction.getInternalConnection();
this.savepoint = connection.setSavepoint();
if (manager.isTxnDebug()) {
if (transaction.isLogSql()) {
int savepointId = manager.isSupportsSavepointId() ? savepoint.getSavepointId() : 0;
this.spPrefix = "sp[" + savepointId + "] ";
} else {
this.spPrefix = "sp[] ";
}
this.logPrefix = transaction.getLogPrefix() + spPrefix;
}
@Override
@@ -51,18 +49,13 @@ final class SavepointTransaction extends SpiTransactionProxy {
}
@Override
public String getLogPrefix() {
return logPrefix;
public void logSql(String msg, Object... args) {
transaction.logSql(Str.add(spPrefix, msg), args);
}
@Override
public void logSql(String msg) {
transaction.logSql(Str.add(spPrefix, msg));
}
@Override
public void logSummary(String msg) {
transaction.logSummary(Str.add(spPrefix, msg));
public void logSummary(String msg, Object... args) {
transaction.logSummary(Str.add(spPrefix, msg), args);
}
@Override
@@ -99,6 +92,7 @@ final class SavepointTransaction extends SpiTransactionProxy {
connection.releaseSavepoint(savepoint);
state = STATE_COMMITTED;
manager.notifyOfCommit(this);
transaction.logTxn(spPrefix + "commit");
} catch (SQLException e) {
throw new PersistenceException("Error trying to commit/release Savepoint", e);
}
@@ -109,6 +103,7 @@ final class SavepointTransaction extends SpiTransactionProxy {
connection.rollback(savepoint);
state = STATE_ROLLED_BACK;
manager.notifyOfRollback(this, cause);
transaction.logTxn(spPrefix + "rollback");//TODO: Pass the cause
} catch (SQLException e) {
throw new PersistenceException("Error trying to rollback Savepoint", e);
}
@@ -43,9 +43,6 @@ abstract class TransactionFactory {
throw new PersistenceException(e);
}
}
if (explicit && manager.log().txn().isTrace()) {
manager.log().txn().trace(t.getLogPrefix() + "Begin");
}
return t;
}
}
@@ -36,7 +36,6 @@ import java.sql.SQLException;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import static java.lang.System.Logger.Level.DEBUG;
import static java.lang.System.Logger.Level.ERROR;
@@ -63,8 +62,6 @@ public class TransactionManager implements SpiTransactionManager {
* Prefix for transaction id's (logging).
*/
final String prefix;
private final String externalTransPrefix;
private final AtomicLong counter = new AtomicLong(1000L);
/**
* The dataSource of connections.
@@ -96,8 +93,6 @@ public class TransactionManager implements SpiTransactionManager {
private final boolean skipCacheAfterWrite;
private final TransactionFactory transactionFactory;
private final SpiLogManager logManager;
private final SpiLogger txnLogger;
private final boolean txnDebug;
private final DatabasePlatform databasePlatform;
private final SpiProfileHandler profileHandler;
private final TimedMetric txnMain;
@@ -115,8 +110,6 @@ public class TransactionManager implements SpiTransactionManager {
public TransactionManager(TransactionManagerOptions options) {
this.server = options.server;
this.logManager = options.logManager;
this.txnLogger = logManager.txn();
this.txnDebug = txnLogger.isDebug();
this.databasePlatform = options.config.getDatabasePlatform();
this.supportsSavepointId = databasePlatform.supportsSavepointId();
this.skipCacheAfterWrite = options.config.isSkipCacheAfterWrite();
@@ -142,7 +135,6 @@ public class TransactionManager implements SpiTransactionManager {
this.profileHandler = options.profileHandler;
this.bulkEventListenerMap = new BulkEventListenerMap(options.config.getBulkTableEventListeners());
this.prefix = "";
this.externalTransPrefix = "e";
CurrentTenantProvider tenantProvider = options.config.getCurrentTenantProvider();
this.transactionFactory = TransactionFactoryBuilder.build(this, dataSourceSupplier, tenantProvider);
@@ -273,14 +265,7 @@ public class TransactionManager implements SpiTransactionManager {
* Wrap the externally supplied Connection.
*/
public SpiTransaction wrapExternalConnection(Connection c) {
return wrapExternalConnection(externalTransPrefix + c.hashCode(), c);
}
/**
* Wrap an externally supplied Connection with a known transaction id.
*/
private SpiTransaction wrapExternalConnection(String id, Connection c) {
ExternalJdbcTransaction t = new ExternalJdbcTransaction(id, true, c, this);
ExternalJdbcTransaction t = new ExternalJdbcTransaction(true, c, this);
// set the default batch mode
t.setBatchMode(persistBatch);
t.setBatchOnCascade(persistBatchOnCascade);
@@ -313,14 +298,7 @@ public class TransactionManager implements SpiTransactionManager {
* Create a new transaction.
*/
SpiTransaction createTransaction(boolean explicit, Connection c) {
return new JdbcTransaction(nextTxnId(), explicit, c, this);
}
/**
* Return the next transaction id.
*/
String nextTxnId() {
return txnDebug ? prefix + counter.incrementAndGet() : prefix;
return new JdbcTransaction(explicit, c, this);
}
/**
@@ -328,17 +306,7 @@ public class TransactionManager implements SpiTransactionManager {
*/
@Override
public final void notifyOfRollback(SpiTransaction transaction, Throwable cause) {
try {
if (txnLogger.isDebug()) {
String msg = transaction.getLogPrefix() + "Rollback";
if (cause != null) {
msg += " error: " + formatThrowable(cause);
}
txnLogger.debug(msg);
}
} catch (Exception ex) {
log.log(ERROR, "Error while notifying TransactionEventListener of rollback event", ex);
}
// Do nothing now
}
/**
@@ -347,32 +315,6 @@ public class TransactionManager implements SpiTransactionManager {
@Override
public final void notifyOfQueryOnly(SpiTransaction transaction) {
// Nothing that interesting here
if (txnLogger.isTrace()) {
txnLogger.trace(transaction.getLogPrefix() + "Commit - query only");
}
}
private String formatThrowable(Throwable e) {
if (e == null) {
return "";
}
StringBuilder sb = new StringBuilder();
formatThrowable(e, sb);
return sb.toString();
}
private void formatThrowable(Throwable e, StringBuilder sb) {
sb.append(e.toString());
StackTraceElement[] stackTrace = e.getStackTrace();
if (stackTrace.length > 0) {
sb.append(" stack0: ");
sb.append(stackTrace[0]);
}
Throwable cause = e.getCause();
if (cause != null) {
sb.append(" cause: ");
formatThrowable(cause, sb);
}
}
/**
@@ -381,9 +323,6 @@ public class TransactionManager implements SpiTransactionManager {
@Override
public final void notifyOfCommit(SpiTransaction transaction) {
try {
if (txnLogger.isDebug()) {
txnLogger.debug(transaction.getLogPrefix() + "Commit");
}
PostCommitProcessing postCommit = new PostCommitProcessing(clusterManager, this, transaction);
postCommit.notifyLocalCache();
backgroundExecutor.execute(postCommit.backgroundNotify());
@@ -676,25 +615,18 @@ public class TransactionManager implements SpiTransactionManager {
}
}
/**
* Return true if Transaction debug is on.
*/
public final boolean isTxnDebug() {
return txnDebug;
public SpiTxnLogger logger() {
return logManager.logger();
}
public SpiTxnLogger loggerReadOnly() {
return logManager.readOnlyLogger();
}
public final SpiLogManager log() {
return logManager;
}
public final boolean isLogSql() {
return logManager.sql().isDebug();
}
public final boolean isLogSummary() {
return logManager.sum().isDebug();
}
/**
* Experimental - find dirty beans in the persistence context and persist them.
*/
@@ -704,4 +636,5 @@ public class TransactionManager implements SpiTransactionManager {
server.updateAll(dirtyBeans, transaction);
}
}
}
@@ -43,4 +43,24 @@ public final class Str {
return sb.append(s0).append(s1).toString();
}
public static String add(String s0, String[] s1) {
if (s1 == null || s1.length == 0) {
return s0;
}
int len = s0.length();
for (String s : s1) {
if (s != null) {
len += s.length();
}
}
StringBuilder sb = new StringBuilder(len);
sb.append(s0);
for (String s : s1) {
if (s != null) {
sb.append(s);
}
}
return sb.toString();
}
}
@@ -99,6 +99,14 @@ public class DefaultExpressionListTest extends BaseExpressionTest {
.isSameByBind(spi(exp().eq("a", 10).eq("b", 20)))).isFalse();
}
@Test
public void isSameWithClear() {
DefaultExpressionList<?> exp1 = spi(exp().eq("a", 10).eq("b", 20).clear().eq("c", 30));
DefaultExpressionList<?> exp2 = spi(exp().eq("c", 30));
same(exp1, exp2);
assertThat(exp1.isSameByBind(exp2)).isTrue();
}
@SuppressWarnings("unchecked")
@Test
void copy() {
+4 -4
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.2</version>
<version>13.13.0</version>
</parent>
<artifactId>ebean-csv-reader</artifactId>
@@ -14,21 +14,21 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
<scope>test</scope>
</dependency>
+4 -4
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.2</version>
<version>13.13.0</version>
</parent>
<name>ebean ddl generation</name>
@@ -28,14 +28,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
<scope>provided</scope>
</dependency>
@@ -58,7 +58,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-all</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
<scope>test</scope>
</dependency>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.2</version>
<version>13.13.0</version>
</parent>
<name>ebean external mapping api</name>
+6 -6
View File
@@ -4,12 +4,12 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.2</version>
<version>13.13.0</version>
</parent>
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-parent-13.11.2</tag>
<tag>ebean-parent-13.13.0</tag>
</scm>
<name>ebean external mapping xml</name>
@@ -21,7 +21,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-api</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<dependency>
@@ -54,21 +54,21 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
<scope>test</scope>
</dependency>
@@ -1 +1 @@
ebean-version: 141
ebean-version: 142
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.2</version>
<version>13.13.0</version>
</parent>
<artifactId>ebean-jackson-jsonnode</artifactId>
@@ -14,7 +14,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
<scope>provided</scope>
</dependency>
+2 -2
View File
@@ -3,7 +3,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.2</version>
<version>13.13.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -14,7 +14,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
<scope>provided</scope>
</dependency>
+2 -2
View File
@@ -3,7 +3,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.2</version>
<version>13.13.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -14,7 +14,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
<scope>provided</scope>
</dependency>
@@ -23,7 +23,7 @@ final class ScalarTypeJodaDateMidnight extends ScalarTypeBaseDate<DateMidnight>
@Override
protected String toIsoFormat(DateMidnight value) {
return value.toString();
return value.toLocalDate().toString();
}
@Override
@@ -28,6 +28,11 @@ final class ScalarTypeJodaLocalDateTime extends ScalarTypeBaseDateTime<LocalDate
return value.toString();
}
@Override
protected LocalDateTime fromJsonISO8601(String value) {
return LocalDateTime.parse(value);
}
@Override
public long convertToMillis(LocalDateTime value) {
return value.toDateTime().getMillis();
@@ -0,0 +1,30 @@
package io.ebean.joda.time;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import io.ebean.config.JsonConfig;
import org.joda.time.DateMidnight;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.io.StringReader;
import static org.junit.jupiter.api.Assertions.assertEquals;
class ScalarTypeJodaDateMidnightTest {
ScalarTypeJodaDateMidnight type = new ScalarTypeJodaDateMidnight(JsonConfig.Date.ISO8601);
JsonFactory jsonFactory = new JsonFactory();
@Test
void testIsoFormat() throws IOException {
// long millis = 1674472451640L;
JsonParser parser = jsonFactory.createParser(new StringReader("\"2023-01-23\""));
JsonToken token = parser.nextToken();
assertEquals(JsonToken.VALUE_STRING, token);
DateMidnight dm = type.jsonRead(parser);
String iso = type.toIsoFormat(dm);
assertEquals("2023-01-23", iso);
}
}
@@ -1,21 +1,37 @@
package io.ebean.joda.time;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import io.ebean.config.JsonConfig;
import org.joda.time.DateTimeZone;
import org.joda.time.LocalDateTime;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.io.StringReader;
import java.sql.Timestamp;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class ScalarTypeJodaLocalDateTimeTest {
class ScalarTypeJodaLocalDateTimeTest {
ScalarTypeJodaLocalDateTime type = new ScalarTypeJodaLocalDateTime(JsonConfig.DateTime.ISO8601);
JsonFactory jsonFactory = new JsonFactory();
@Test
public void testConvertFromTimestamp() throws Exception {
void testIsoFormat() throws IOException {
JsonParser parser = jsonFactory.createParser(new StringReader("\"2023-01-23T12:14:11.640\""));
JsonToken token = parser.nextToken();
assertEquals(JsonToken.VALUE_STRING, token);
LocalDateTime ldt1 = type.jsonRead(parser);
String iso = type.toJsonISO8601(ldt1);
assertEquals("2023-01-23T12:14:11.640", iso);
}
@Test
void testConvertFromTimestamp() {
long now = System.currentTimeMillis();
Timestamp nowTs = new Timestamp(now);
@@ -30,12 +46,10 @@ public class ScalarTypeJodaLocalDateTimeTest {
assertEquals(ts1, ts2);
}
LocalDateTime localConvertFromTimestamp(Timestamp ts) {
return new LocalDateTime(ts.getTime(), DateTimeZone.getDefault());
}
Timestamp localConvertToTimestamp(LocalDateTime t) {
return new Timestamp(t.toDateTime(DateTimeZone.getDefault()).getMillis());
}
+3 -3
View File
@@ -6,7 +6,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.2-SNAPSHOT</version>
<version>13.13.0-SNAPSHOT</version>
</parent>
<artifactId>ebean-kotlin</artifactId>
@@ -28,7 +28,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.11.2-SNAPSHOT</version>
<version>13.13.0-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
@@ -50,7 +50,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>13.11.2-SNAPSHOT</version>
<version>13.13.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
+4 -4
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.2</version>
<version>13.13.0</version>
</parent>
<name>ebean postgis</name>
@@ -22,14 +22,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
</dependency>
<!-- provided scope -->
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
<scope>provided</scope>
</dependency>
@@ -65,7 +65,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
<scope>test</scope>
</dependency>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.2</version>
<version>13.13.0</version>
</parent>
<name>ebean querybean</name>
@@ -17,7 +17,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
<scope>provided</scope>
</dependency>
@@ -63,21 +63,21 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>13.11.2</version>
<version>13.13.0</version>
<scope>test</scope>
</dependency>
@@ -6,7 +6,7 @@ package io.ebean.typequery;
* @param <R> the root query bean type
* @param <E> the element type of the DbArray
*/
public final class PArray<R, E> extends TQPropertyBase<R> {
public final class PArray<R, E> extends TQPropertyBase<R, E> {
/**
* Construct with a property name and root instance.
@@ -9,8 +9,7 @@ import io.ebean.Query;
* @param <R> the root query bean type
* @param <T> the type of the scalar property
*/
@SuppressWarnings("rawtypes")
public class PBaseCompareable<R, T> extends PBaseValueEqual<R, T> {
public abstract class PBaseComparable<R, T> extends PBaseValueEqual<R, T> {
/**
* Construct with a property name and root instance.
@@ -18,14 +17,14 @@ public class PBaseCompareable<R, T> extends PBaseValueEqual<R, T> {
* @param name property name
* @param root the root query bean instance
*/
public PBaseCompareable(String name, R root) {
public PBaseComparable(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PBaseCompareable(String name, R root, String prefix) {
public PBaseComparable(String name, R root, String prefix) {
super(name, root, prefix);
}
@@ -44,12 +43,14 @@ public class PBaseCompareable<R, T> extends PBaseValueEqual<R, T> {
/**
* Greater than other property.
* <p>
* Note that the other property must have the same common "Base type" (String, Number, Temporal, Boolean or Object).
*
* @param other the other property to compare
* @return the root query bean instance
*/
public final R gt(TQProperty<?> other) {
expr().raw(_name + " > " + other.propertyName());
public final R gt(Query.Property<T> other) {
expr().raw(_name + " > " + other.toString());
return _root;
}
@@ -81,8 +82,8 @@ public class PBaseCompareable<R, T> extends PBaseValueEqual<R, T> {
* @param other the other property to compare
* @return the root query bean instance
*/
public final R ge(TQProperty<?> other) {
expr().raw(_name + " >= " + other.propertyName());
public final R ge(Query.Property<T> other) {
expr().raw(_name + " >= " + other.toString());
return _root;
}
@@ -114,8 +115,8 @@ public class PBaseCompareable<R, T> extends PBaseValueEqual<R, T> {
* @param other the other property to compare
* @return the root query bean instance
*/
public final R lt(TQProperty<?> other) {
expr().raw(_name + " < " + other.propertyName());
public final R lt(Query.Property<T> other) {
expr().raw(_name + " < " + other.toString());
return _root;
}
@@ -147,8 +148,8 @@ public class PBaseCompareable<R, T> extends PBaseValueEqual<R, T> {
* @param other the other property to compare
* @return the root query bean instance
*/
public final R le(TQProperty<?> other) {
expr().raw(_name + " <= " + other.propertyName());
public final R le(Query.Property<T> other) {
expr().raw(_name + " <= " + other.toString());
return _root;
}
@@ -197,8 +198,8 @@ public class PBaseCompareable<R, T> extends PBaseValueEqual<R, T> {
* The most common use of this could be called "effective dating" where 2 date or
* timestamp columns represent the date range in which
*/
public final R inRangeWith(TQProperty<R> highProperty, T value) {
expr().inRangeWith(_name, highProperty._name, value);
public final R inRangeWith(Query.Property<T> highProperty, T value) {
expr().inRangeWith(_name, highProperty.toString(), value);
return _root;
}
@@ -220,8 +221,8 @@ public class PBaseCompareable<R, T> extends PBaseValueEqual<R, T> {
* <p>
* This is a convenience expression combining a number of simple expressions.
*/
public final R inRangeWith(TQProperty<?> lowProperty, TQProperty<?> highProperty) {
expr().inRangeWithProperties(_name, lowProperty.propertyName(), highProperty.propertyName());
public final R inRangeWith(Query.Property<T> lowProperty, Query.Property<T> highProperty) {
expr().inRangeWithProperties(_name, lowProperty.toString(), highProperty.toString());
return _root;
}
@@ -4,10 +4,10 @@ package io.ebean.typequery;
* Base property for date and date time types.
*
* @param <R> the root query bean type
* @param <D> the date time type
* @param <T> the scalar type
*/
@SuppressWarnings("rawtypes")
public abstract class PBaseDate<R, D extends Comparable> extends PBaseCompareable<R, D> {
public abstract class PBaseDate<R, T extends Comparable> extends PBaseComparable<R, T> {
/**
* Construct with a property name and root instance.
@@ -32,7 +32,7 @@ public abstract class PBaseDate<R, D extends Comparable> extends PBaseCompareabl
* @param value the equal to bind value
* @return the root query bean instance
*/
public final R after(D value) {
public final R after(T value) {
expr().gt(_name, value);
return _root;
}
@@ -43,7 +43,7 @@ public abstract class PBaseDate<R, D extends Comparable> extends PBaseCompareabl
* @param value the equal to bind value
* @return the root query bean instance
*/
public final R before(D value) {
public final R before(T value) {
expr().lt(_name, value);
return _root;
}
@@ -4,10 +4,10 @@ package io.ebean.typequery;
* Base property for number types.
*
* @param <R> the root query bean type
* @param <T> the number type
* @param <T> the property type
*/
@SuppressWarnings("rawtypes")
public abstract class PBaseNumber<R,T extends Comparable> extends PBaseCompareable<R,T> {
public abstract class PBaseNumber<R, T extends Comparable> extends PBaseComparable<R, T> {
/**
* Construct with a property name and root instance.
@@ -16,7 +16,7 @@ public abstract class PBaseNumber<R,T extends Comparable> extends PBaseCompareab
* @param root the root query bean instance
*/
public PBaseNumber(String name, R root) {
super(name , root);
super(name, root);
}
/**
@@ -5,7 +5,7 @@ package io.ebean.typequery;
*
* @param <R> the root query bean type
*/
public abstract class PBaseString<R,T> extends PBaseCompareable<R, String> {
public abstract class PBaseString<R, T> extends PBaseComparable<R, T> {
/**
* Construct with a property name and root instance.
@@ -25,22 +25,28 @@ public abstract class PBaseString<R,T> extends PBaseCompareable<R, String> {
}
/**
* Deprecated migrate to eq().
* <p>
* Is equal to. The same as <code>eq</code> but uses the strong type as argument rather than String.
*
* @param value the equal to bind value
* @return the root query bean instance
*/
@Deprecated
public final R equalToType(T value) {
expr().eq(_name, value);
return _root;
}
/**
* Deprecated migrate to ne().
* <p>
* Is not equal to. The same as <code>ne</code> but uses the strong type as argument rather than String.
*
* @param value the equal to bind value
* @return the root query bean instance
*/
@Deprecated
public final R notEqualToType(T value) {
expr().ne(_name, value);
return _root;
@@ -49,7 +55,146 @@ public abstract class PBaseString<R,T> extends PBaseCompareable<R, String> {
// common string / expressions ------------
/**
* Case insensitive is equal to.
* Equal to.
*
* @param value the bind value
* @return the root query bean instance
*/
public final R eq(String value) {
expr().eq(_name, value);
return _root;
}
/**
* Not equal to.
*
* @param value the bind value
* @return the root query bean instance
*/
public final R ne(String value) {
expr().ne(_name, value);
return _root;
}
/**
* Greater than.
*
* @param value the bind value
* @return the root query bean instance
*/
public final R gt(String value) {
expr().gt(_name, value);
return _root;
}
/**
* Greater than OR Null.
*
* @param value the bind value
* @return the root query bean instance
*/
public final R gtOrNull(String value) {
expr().gtOrNull(_name, value);
return _root;
}
/**
* Greater than or Equal to.
*
* @param value the bind value
* @return the root query bean instance
*/
public final R ge(String value) {
expr().ge(_name, value);
return _root;
}
/**
* Greater than or Equal to OR Null.
*
* @param value the bind value
* @return the root query bean instance
*/
public final R geOrNull(String value) {
expr().geOrNull(_name, value);
return _root;
}
/**
* Less than.
*
* @param value the bind value
* @return the root query bean instance
*/
public final R lt(String value) {
expr().lt(_name, value);
return _root;
}
/**
* Less than OR Null.
*
* @param value the bind value
* @return the root query bean instance
*/
public final R ltOrNull(String value) {
expr().ltOrNull(_name, value);
return _root;
}
/**
* Less than or Equal to.
*
* @param value the bind value
* @return the root query bean instance
*/
public final R le(String value) {
expr().le(_name, value);
return _root;
}
/**
* Less than or Equal to OR null.
*
* @param value the bind value
* @return the root query bean instance
*/
public final R leOrNull(String value) {
expr().leOrNull(_name, value);
return _root;
}
/**
* Greater or equal to lower value and strictly less than upper value.
* <p>
* This is generally preferable over Between for date and datetime types
* as SQL Between is inclusive on the upper bound ({@code <= }) and generally
* we need the upper bound to be exclusive ({@code < }).
* </p>
*
* @param lower the lower bind value ({@code >= })
* @param upper the upper bind value ({@code < })
* @return the root query bean instance
*/
public final R inRange(String lower, String upper) {
expr().inRange(_name, lower, upper);
return _root;
}
/**
* Between lower and upper values.
*
* @param lower the lower bind value
* @param upper the upper bind value
* @return the root query bean instance
*/
public final R between(String lower, String upper) {
expr().between(_name, lower, upper);
return _root;
}
/**
* Case-insensitive is equal to.
*
* @param value the equal to bind value
* @return the root query bean instance
@@ -60,7 +205,7 @@ public abstract class PBaseString<R,T> extends PBaseCompareable<R, String> {
}
/**
* Case insensitive is equal to.
* Case-insensitive is equal to.
*
* @param value the equal to bind value
* @return the root query bean instance
@@ -115,7 +260,7 @@ public abstract class PBaseString<R,T> extends PBaseCompareable<R, String> {
}
/**
* Case insensitive like.
* Case-insensitive like.
*
* @param value the equal to bind value
* @return the root query bean instance
@@ -126,7 +271,7 @@ public abstract class PBaseString<R,T> extends PBaseCompareable<R, String> {
}
/**
* Case insensitive starts with.
* Case-insensitive starts with.
*
* @param value the equal to bind value
* @return the root query bean instance
@@ -137,7 +282,7 @@ public abstract class PBaseString<R,T> extends PBaseCompareable<R, String> {
}
/**
* Case insensitive ends with.
* Case-insensitive ends with.
*
* @param value the equal to bind value
* @return the root query bean instance
@@ -148,7 +293,7 @@ public abstract class PBaseString<R,T> extends PBaseCompareable<R, String> {
}
/**
* Case insensitive contains.
* Case-insensitive contains.
*
* @param value the equal to bind value
* @return the root query bean instance

Some files were not shown because too many files have changed in this diff Show More