Compare commits

...
Author SHA1 Message Date
Rob Bygrave 2143ebc21c Bump ebean-agent to 13.13.2 2023-02-27 15:49:41 +13:00
Rob BygraveandGitHub 7dd25344ef Merge pull request #2986 from ebean-orm/feature/querybeans-assoc-supportInterfaceUse
[querybeans] Add support for using interface types with querybean expressions eq() in() etc WHEN entity beans implement an interface
2023-02-27 15:29:07 +13:00
Rob Bygrave c381464316 querybean-generation - cast for varargs use and use wildcard collections 2023-02-27 15:24:59 +13:00
Rob Bygrave a5d5549f2c [querybeans] Add support for using interface types with querybean expressions eq() in() etc WHEN entity beans implement an interface
- For the case where entity beans implement an interface
- Adds these expressions to the "associated" querybeans (not the root querybeans).
- The expressions added use of the interface type
2023-02-27 13:12:52 +13:00
Rob BygraveandGitHub d7d144b908 Merge pull request #2985 from ebean-orm/feature/querybean-assoc-eqIfPresent
For querybean associated beans, add missing eqIfPresent() + in() + notIn() + expressions
2023-02-26 19:28:55 +13:00
Rob Bygrave 25416a3cda For querybean associated beans, add missing eqIfPresent() + in() + notIn() + expressions 2023-02-26 19:24:00 +13:00
Rob Bygrave e6b0306bde Fix test TestStdFunctions for Oracle which only supports 2 parameters with concat() 2023-02-25 01:06:40 +13:00
Rob Bygrave 2d6ca4bb1e Fix build of test-java16 module for JDK 16+ 2023-02-25 00:25:05 +13:00
Rob Bygrave 99d5f4f01c Bump to next version 13.13.2 2023-02-24 23:56:44 +13:00
rob 8ea0936da8 Tighten Javax to Jakarta escaping the periods 2023-02-23 20:43:50 +13:00
Rob BygraveandGitHub f8fc94c694 Merge pull request #2984 from ebean-orm/feature/jakarta-javax-sed-conversion
Javax to Jakarta (+ reverse) conversion via sed
2023-02-23 12:28:40 +13:00
rob bac3fd6874 Javax to Jakarta (+ reverse) conversion via sed 2023-02-23 01:28:50 +13:00
Rob BygraveandGitHub 0659d7604c Merge pull request #2980 from FOCONIS/fix-logger
FIX: do not format log messages, when no parameter was specified
2023-02-22 23:38:08 +13:00
Rob BygraveandGitHub a825e50584 Merge pull request #2983 from ebean-orm/feature/profileLocationWithLineNumbers
ENH: Add profile-line-number-mode with options none | all | auto ... to control adding line numbers to profile locations
2023-02-22 23:35:42 +13:00
Rob BygraveandGitHub 94f24f054e Merge pull request #2982 from ebean-orm/feature/revert-revision
Revert the use of ${revision} in poms to plain old version dur to issues not being able to use mvn --rf --resume-from ... as it complains about the parent pom version
2023-02-22 23:19:15 +13:00
rob 989d82813b Revert the use of ${revision} in poms to plain old version dur to issues not being able to use mvn --rf --resume-from ... as it complains about the parent pom version 2023-02-22 23:17:42 +13:00
rob 2e0dba3741 #2981 - ENH: Add profile-line-number-mode with options none | all | auto ... to control adding line numbers to profile locations 2023-02-22 23:02:42 +13:00
Roland Praml 56360f0fb3 use captureLogger 2023-02-22 09:20:04 +01:00
Roland Praml d84f2eea58 FIX: do not format log messages, when no parameter was specified 2023-02-22 09:07:49 +01:00
rob 34dc4375da Tidy existing given that lineNumber in SpiProfileLocationFactory always comes in as 0
The history behind this is that originally there was a "profileId" concept where that was a int value that could be used as an "id" for a transactional method that we wanted to profile.

That went away and then the idea was that bytecode enhancement would determine the line number and we would use that but that was a bad idea and we ended up with lineNumber always as 0.

These days with StackWalker and DProfileLocation we can do this better that way so yeah. A followup to this is to add to the api a boolean flag as to whether a profile location should be with line numbers (which can change frequently due to refactoring etc)
2023-02-22 15:22:58 +13:00
Rob BygraveandGitHub 9e186698fe Merge pull request #2979 from ebean-orm/feature/ifPresentExpressions
ENH: Add _ifPresent() expressions for GT, GE, LT, LE (follow up from #2768)
2023-02-22 14:11:50 +13:00
rob 0b615a79cc Add _ifPresent() expressions for GT, GE, LT, LE (follow up from #2768) 2023-02-22 14:04:26 +13:00
Rob BygraveandGitHub 6e98486a03 Merge pull request #2978 from ebean-orm/feature/stackWalker
Use StackWalker for ProfileLocation and CallOrigin
2023-02-21 14:35:58 +13:00
rob b0364f3c42 Use StackWalker for ProfileLocation and CallOrigin 2023-02-21 14:21:18 +13:00
Rob BygraveandGitHub 8ed871f116 Merge pull request #2977 from ebean-orm/feature/pom-versioning
Modify poms to use ${revision} for parent pom version
2023-02-20 10:23:59 +13:00
rob f493c7e8cf Modify poms to use ${revision} for dependencies versions and annotation processor versions 2023-02-20 10:19:14 +13:00
rob 0e596fd87f Modify poms to use ${revision} for parent pom version 2023-02-20 10:09:41 +13:00
Rob BygraveandGitHub 37154cf4d4 Merge pull request #2975 from ebean-orm/feature/config-getOptional
Tidy internals, use Config.getOptional() when reading datasource.default / ebean.default.datasource
2023-02-20 09:17:45 +13:00
rob fe241d8cce Tidy internals, use Config.getOptional() when reading datasource.default / ebean.default.datasource 2023-02-20 09:07:45 +13:00
Rob Bygrave efaa771bb4 Modify test-kotlin to use ebean maven plugin 13.13.0 (for jakarta) 2023-02-20 01:15:10 +13:00
Rob Bygrave 4094b1e345 Remove ebean-api optional dependency on javax.transaction as it isn't required here
Note that it is an optional dependency of ebean-core via the JtaTransaction/JtaTransactionManager that are in ebean core
2023-02-20 00:53:14 +13:00
Rob Bygrave 8bb9ec0cfe Bump the maven tiles used in tests to 13.12.0 2023-02-19 23:21:39 +13:00
rob 86bcfa804b Remove github wf build for jdk 18 EA as that has been replaced by the other EA build 2023-02-15 11:17:12 +13:00
rob b6a3c54e99 Add build badge for DB2 LUW 2023-02-15 11:12:35 +13:00
rob 6753e36327 Bump versions after release 2023-02-15 10:54:18 +13:00
rob e78ac677f6 [maven-release-plugin] prepare for next development iteration 2023-02-15 10:22:46 +13:00
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
Roland Praml 010f73fea2 ENH: add statistics trimmedByGC/LRU/TTL/Idle to ServerCacheStatistics? 2023-02-02 14:10:54 +01: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
208 changed files with 3020 additions and 1102 deletions
-39
View File
@@ -1,39 +0,0 @@
name: JDK 18-ea
on:
workflow_dispatch:
schedule:
- cron: '30 6 * * 1,3,5'
jobs:
build:
runs-on: ${{ matrix.os }}
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
java_version: [18-ea]
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v2
- name: Set up Java
uses: actions/setup-java@v2
with:
java-version: ${{ matrix.java_version }}
distribution: 'zulu'
- name: Maven cache
uses: actions/cache@v2
env:
cache-name: maven-cache
with:
path:
~/.m2
key: build-${{ env.cache-name }}
- name: Build with Maven
run: mvn -T 8 test
+1 -2
View File
@@ -3,7 +3,6 @@
[![Maven Central : ebean](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean)
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/ebean-orm/ebean/blob/master/LICENSE)
[![Multi-JDK Build](https://github.com/ebean-orm/ebean/actions/workflows/multi-jdk-build.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/multi-jdk-build.yml)
[![JDK 18-ea](https://github.com/ebean-orm/ebean/actions/workflows/jdk-18-ea.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/jdk-18-ea.yml)
##### Build with database platforms
[![H2Database](https://github.com/ebean-orm/ebean/actions/workflows/h2database.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/h2database.yml)
@@ -12,9 +11,9 @@
[![MariaDB](https://github.com/ebean-orm/ebean/actions/workflows/mariadb.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/mariadb.yml)
[![Oracle](https://github.com/ebean-orm/ebean/actions/workflows/oracle.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/oracle.yml)
[![SqlServer](https://github.com/ebean-orm/ebean/actions/workflows/sqlserver.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/sqlserver.yml)
[![DB2 LUW](https://github.com/ebean-orm/ebean/actions/workflows/db2luw.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/db2luw.yml)
[![Yugabyte](https://github.com/ebean-orm/ebean/actions/workflows/yugabyte.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/yugabyte.yml)
##### Build with Java Early Access versions
[![ebean EA](https://github.com/ebean-orm/ebean/actions/workflows/jdk-ea.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/jdk-ea.yml)
[![datasource EA](https://github.com/ebean-orm/ebean-datasource/actions/workflows/jdk-ea.yml/badge.svg)](https://github.com/ebean-orm/ebean-datasource/actions/workflows/jdk-ea.yml)
+5 -9
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.4</version>
<version>13.13.2</version>
</parent>
<name>ebean-clickhouse</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
@@ -35,18 +35,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-clickhouse</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.11.4</tag>
</scm>
</project>
+5 -9
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.4</version>
<version>13.13.2</version>
</parent>
<name>ebean-cockroach</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
@@ -35,18 +35,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.11.4</tag>
</scm>
</project>
+5 -9
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.4</version>
<version>13.13.2</version>
</parent>
<name>ebean-db2</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
@@ -35,18 +35,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-db2</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.11.4</tag>
</scm>
</project>
+5 -9
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.4</version>
<version>13.13.2</version>
</parent>
<name>ebean-h2</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
@@ -35,18 +35,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.11.4</tag>
</scm>
</project>
+5 -9
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.4</version>
<version>13.13.2</version>
</parent>
<name>ebean-hana</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
@@ -35,18 +35,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-hana</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.11.4</tag>
</scm>
</project>
+5 -9
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.4</version>
<version>13.13.2</version>
</parent>
<name>ebean-mariadb</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
@@ -35,18 +35,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-mariadb</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.11.4</tag>
</scm>
</project>
+5 -9
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.4</version>
<version>13.13.2</version>
</parent>
<name>ebean-mysql</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
@@ -35,18 +35,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-mysql</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.11.4</tag>
</scm>
</project>
+5 -9
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.4</version>
<version>13.13.2</version>
</parent>
<name>ebean-nuodb</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
@@ -35,18 +35,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-nuodb</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.11.4</tag>
</scm>
</project>
+5 -9
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.4</version>
<version>13.13.2</version>
</parent>
<name>ebean-oracle</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
@@ -35,18 +35,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-oracle</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.11.4</tag>
</scm>
</project>
+5 -9
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.4</version>
<version>13.13.2</version>
</parent>
<name>ebean-postgres</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
@@ -35,18 +35,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.11.4</tag>
</scm>
</project>
+5 -9
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.4</version>
<version>13.13.2</version>
</parent>
<name>ebean-sqlite</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
@@ -35,18 +35,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlite</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.11.4</tag>
</scm>
</project>
+5 -9
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.4</version>
<version>13.13.2</version>
</parent>
<name>ebean-sqlserver</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
@@ -35,18 +35,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlserver</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.11.4</tag>
</scm>
</project>
+5 -9
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.4</version>
<version>13.13.2</version>
</parent>
<name>ebean-yugabyte</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
@@ -35,18 +35,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.11.4</tag>
</scm>
</project>
+8 -12
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.4</version>
<version>13.13.2</version>
</parent>
<name>ebean (all platforms)</name>
@@ -16,31 +16,31 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-joda-time</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-jackson-jsonnode</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-jackson-mapper</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
@@ -53,18 +53,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-all</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
</dependencies>
<scm>
<tag>ebean-parent-13.11.4</tag>
</scm>
</project>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.4</version>
<version>13.13.2</version>
</parent>
<artifactId>composites</artifactId>
+11 -8
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.4</version>
<version>13.13.2</version>
</parent>
<name>ebean api</name>
@@ -90,19 +90,22 @@
<optional>true</optional>
</dependency>
<dependency>
<groupId>javax.transaction</groupId>
<artifactId>jta</artifactId>
<version>1.1</version>
<optional>true</optional>
</dependency>
<!-- JAVAX-DEPENDENCY-START -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<optional>true</optional>
</dependency>
<!-- JAVAX-DEPENDENCY-END -->
<!-- JAKARTA-DEPENDENCY-START ___
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>6.0.0</version>
<optional>true</optional>
</dependency>
____ JAKARTA-DEPENDENCY-END -->
<dependency>
<groupId>io.avaje</groupId>
@@ -76,9 +76,9 @@ final class DbPrimary {
defaultServerName = System.getProperty("db", defaultServerName);
defaultServerName = System.getProperty("ebean_db", defaultServerName);
if (isEmpty(defaultServerName)) {
defaultServerName = Config.get("datasource.default", null);
defaultServerName = Config.getOptional("datasource.default").orElse(null);
if (isEmpty(defaultServerName)) {
defaultServerName = Config.get("ebean.default.datasource", null);
defaultServerName = Config.getOptional("ebean.default.datasource").orElse(null);
}
}
if (defaultServerName == null) {
@@ -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.
*/
@@ -951,9 +951,12 @@ public interface ExpressionList<T> {
ExpressionList<T> gtOrNull(String propertyName, Object value);
/**
* Greater Than or Equal to OR Null - ({@code >= or null }).
* Is GREATER THAN if value is non-null and otherwise no expression is added to the query.
* <p>
* This is effectively a helper method that allows a query to be built in fluid style where some predicates are
* effectively optional. We can use <code>gtIfPresent()</code> rather than having a separate if block.
*/
ExpressionList<T> geOrNull(String propertyName, Object value);
ExpressionList<T> gtIfPresent(String propertyName, @Nullable Object value);
/**
* Greater Than or Equal to the result of a sub-query.
@@ -966,6 +969,20 @@ public interface ExpressionList<T> {
*/
ExpressionList<T> ge(String propertyName, Object value);
/**
* Greater Than or Equal to OR Null - ({@code >= or null }).
*/
ExpressionList<T> geOrNull(String propertyName, Object value);
/**
* Is GREATER THAN OR EQUAL TO if value is non-null and otherwise no expression is added to the query.
* <p>
* This is effectively a helper method that allows a query to be built in fluid style where some predicates are
* effectively optional. We can use <code>geIfPresent()</code> rather than having a separate if block.
*/
ExpressionList<T> geIfPresent(String propertyName, @Nullable Object value);
/**
* Less Than the result of a sub-query.
*/
@@ -982,9 +999,12 @@ public interface ExpressionList<T> {
ExpressionList<T> ltOrNull(String propertyName, Object value);
/**
* Less Than or Equal to OR Null - ({@code <= or null }).
* Is LESS THAN if value is non-null and otherwise no expression is added to the query.
* <p>
* This is effectively a helper method that allows a query to be built in fluid style where some predicates are
* effectively optional. We can use <code>ltIfPresent()</code> rather than having a separate if block.
*/
ExpressionList<T> leOrNull(String propertyName, Object value);
ExpressionList<T> ltIfPresent(String propertyName, @Nullable Object value);
/**
* Less Than or Equal to the result of a sub-query.
@@ -996,6 +1016,19 @@ public interface ExpressionList<T> {
*/
ExpressionList<T> le(String propertyName, Object value);
/**
* Less Than or Equal to OR Null - ({@code <= or null }).
*/
ExpressionList<T> leOrNull(String propertyName, Object value);
/**
* Is LESS THAN OR EQUAL TO if value is non-null and otherwise no expression is added to the query.
* <p>
* This is effectively a helper method that allows a query to be built in fluid style where some predicates are
* effectively optional. We can use <code>leIfPresent()</code> rather than having a separate if block.
*/
ExpressionList<T> leIfPresent(String propertyName, @Nullable Object value);
/**
* Is Null - property is null.
*/
@@ -17,15 +17,32 @@ public interface ProfileLocation {
}
/**
* Create and return a new ProfileLocation with a given lineNumber and label.
* Create and return a new ProfileLocation with line number.
*/
static ProfileLocation create(int lineNumber, String label) {
return XServiceProvider.profileLocationFactory().create(lineNumber, label);
static ProfileLocation createWithLine() {
return XServiceProvider.profileLocationFactory().createWithLine();
}
/**
* Create and return a new ProfileLocation with a given lineNumber and label.
*/
static ProfileLocation create(String label) {
return XServiceProvider.profileLocationFactory().create(label);
}
/**
* Deprecated in favor of {@link #create(String)}.
*/
@Deprecated
static ProfileLocation create(int lineNumber, String label) {
return create(label);
}
/**
* Deprecated for removal - not used.
* Create and return a new ProfileLocation with a given location.
*/
@Deprecated
static ProfileLocation createAt(String location) {
return XServiceProvider.profileLocationFactory().createAt(location);
}
@@ -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>
@@ -2,6 +2,7 @@ package io.ebean.bean;
import java.io.Serializable;
import java.util.Arrays;
import java.util.List;
import static io.ebean.util.EncodeB64.enc;
@@ -27,19 +28,26 @@ public final class CallStack implements Serializable, CallOrigin {
private final String zeroHash;
private final String pathHash;
private final StackTraceElement[] callStack;
private final Object[] callStack;
private final int hc;
public CallStack(StackTraceElement[] callStack, int zeroHash, int pathHash) {
public CallStack(Object[] callStack, int zeroHash, int pathHash) {
this.callStack = callStack;
this.hc = computeHashCode();
this.zeroHash = enc(zeroHash);
this.pathHash = enc(pathHash);
}
public CallStack(List<StackWalker.StackFrame> frames) {
this.callStack = frames.toArray(new Object[0]);
this.hc = computeHashCode();
this.zeroHash = enc(callStack[0].hashCode());
this.pathHash = enc(hc);
}
private int computeHashCode() {
int hc = 0;
for (StackTraceElement element : callStack) {
for (Object element : callStack) {
hc = 92821 * hc + element.hashCode();
}
return hc;
@@ -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;
}
}
@@ -13,9 +13,16 @@ public interface SpiProfileLocationFactory {
ProfileLocation create();
/**
* Create a profile location with a line number.
* Create a profile location with line numbering.
*/
ProfileLocation create(int lineNumber, String label);
ProfileLocation createWithLine();
/**
* Create with a given label - used only with {@code @Transaction}.
*
* @param label the label for the transaction
*/
ProfileLocation create(String label);
/**
* Create a known location.
@@ -0,0 +1,28 @@
package io.ebean.util;
import java.util.function.Predicate;
/**
* Provides a stack filter that excludes ebean and jdk code.
*/
public final class StackWalkFilter {
private static final Filter FILTER = new Filter();
/**
* Return a stack filter that excludes ebean and jdk code.
*/
public static Predicate<StackWalker.StackFrame> filter() {
return FILTER;
}
private static class Filter implements Predicate<StackWalker.StackFrame> {
@Override
public boolean test(StackWalker.StackFrame stackFrame) {
return !stackFrame.getClassName().startsWith("io.ebean")
&& !stackFrame.getClassName().startsWith("jdk.")
&& !stackFrame.getMethodName().startsWith("_ebean_");
}
}
}
@@ -1 +1 @@
ebean-version: 141
ebean-version: 143
@@ -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')");
}
}
+20 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.4</version>
<version>13.13.2</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.4</tag>
<tag>HEAD</tag>
</scm>
<name>ebean autotune</name>
@@ -26,17 +26,31 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
<scope>provided</scope>
</dependency>
<!-- needed for java 11+ -->
<!-- JAVAX-DEPENDENCY-START -->
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.6</version>
<scope>provided</scope>
</dependency>
<!-- JAVAX-DEPENDENCY-END -->
<!-- JAKARTA-DEPENDENCY-START ___
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>4.0.0</version>
<scope>runtime</scope>
</dependency>
____ JAKARTA-DEPENDENCY-END -->
<dependency>
<groupId>io.ebean</groupId>
@@ -55,7 +69,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
<scope>test</scope>
</dependency>
@@ -70,7 +84,7 @@
<extensions>true</extensions>
<configuration>
<tiles>
<tile>io.ebean.tile:enhancement:13.10.1</tile>
<tile>io.ebean.tile:enhancement:13.12.0</tile>
</tiles>
</configuration>
</plugin>
+29 -29
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.4</version>
<version>13.13.2</version>
</parent>
<name>ebean bom</name>
@@ -89,106 +89,106 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-joda-time</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-jackson-jsonnode</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-jackson-mapper</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-api</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-xml</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-autotune</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>kotlin-querybean-generator</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgis</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-redis</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<!-- platforms -->
@@ -196,67 +196,67 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-clickhouse</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-db2</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-h2</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-hana</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-mariadb</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-mysql</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-nuodb</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-oracle</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgres</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-sqlite</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-sqlserver</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
</dependencies>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.4</version>
<version>13.13.2</version>
</parent>
<artifactId>ebean-core-type</artifactId>
@@ -16,7 +16,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
+8 -8
View File
@@ -3,7 +3,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.4</version>
<version>13.13.2</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.4</tag>
<tag>HEAD</tag>
</scm>
<dependencies>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
@@ -46,13 +46,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-api</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<dependency>
@@ -143,21 +143,21 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlserver</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
<scope>test</scope>
</dependency>
@@ -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();
@@ -2,17 +2,17 @@ package io.ebeaninternal.server.core;
import io.ebean.bean.CallOrigin;
import io.ebean.bean.CallStack;
import io.ebean.util.StackWalkFilter;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* Default CallStackFactory where the Hash function for StackTraceElement includes the line number.
*/
public final class DefaultCallOriginFactory implements CallOriginFactory {
private static final int IGNORE_LEADING_ELEMENTS = 5;
private static final String IO_EBEAN = "io.ebean";
final class DefaultCallOriginFactory implements CallOriginFactory {
private final int maxCallStack;
@@ -22,57 +22,18 @@ public final class DefaultCallOriginFactory implements CallOriginFactory {
@Override
public CallOrigin createCallOrigin() {
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
// ignore the first 6 as they are always avaje stack elements
int startIndex = IGNORE_LEADING_ELEMENTS;
// find the first non-avaje stackElement
for (; startIndex < stackTrace.length; startIndex++) {
if (!ignore(stackTrace[startIndex])) {
break;
}
}
int stackLength = stackTrace.length - startIndex;
if (stackLength > maxCallStack) {
// maximum of maxCallStack stackTrace elements
stackLength = maxCallStack;
}
// create the 'interesting' part of the stackTrace
StackTraceElement[] finalTrace = new StackTraceElement[stackLength];
System.arraycopy(stackTrace, startIndex, finalTrace, 0, stackLength);
if (stackLength < 1) {
final var frames = StackWalker.getInstance().walk(this::filter);
if (frames.isEmpty()) {
// this should not really happen
throw new RuntimeException("StackTraceElement size 0? stack: " + Arrays.toString(stackTrace));
throw new RuntimeException("stackFrames filtered to empty for stack: " + Arrays.toString(Thread.currentThread().getStackTrace()));
}
return createCallStack(finalTrace);
return new CallStack(frames);
}
private boolean ignore(StackTraceElement element) {
if (element.getClassName().startsWith(IO_EBEAN)) {
return true;
}
return element.getMethodName().startsWith("_ebean_");
}
private CallOrigin createCallStack(StackTraceElement[] finalTrace) {
return new CallStack(finalTrace, finalTrace[0].hashCode(), pathHash(finalTrace));
}
/**
* Return the hash code for the path excluding the first element.
*/
private int pathHash(StackTraceElement[] callStack) {
int hc = 0;
for (int i = 1; i < callStack.length; i++) {
hc = 92821 * hc + callStack[i].hashCode();
}
return hc;
private <T> List<StackWalker.StackFrame> filter(Stream<StackWalker.StackFrame> frames) {
return frames.filter(StackWalkFilter.filter())
.limit(maxCallStack)
.collect(Collectors.toList());
}
}
@@ -10,7 +10,7 @@ final class NoopCallOriginFactory implements CallOriginFactory {
private static final StackTraceElement E0 = new StackTraceElement("none", "none", "none", 0);
private final CallOrigin COMMON = new CallStack(new StackTraceElement[]{E0}, 0, 0);
private final CallOrigin COMMON = new CallStack(new Object[]{E0}, 0, 0);
@Override
public CallOrigin createCallOrigin() {
@@ -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);
}
}
@@ -903,6 +903,16 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
return add(expr.geOrNull(propertyName, value));
}
@Override
public ExpressionList<T> gtIfPresent(String propertyName, @Nullable Object value) {
return value == null ? this : add(expr.gt(propertyName, value));
}
@Override
public ExpressionList<T> geIfPresent(String propertyName, @Nullable Object value) {
return value == null ? this : add(expr.ge(propertyName, value));
}
@Override
public ExpressionList<T> icontains(String propertyName, String value) {
return add(expr.icontains(propertyName, value));
@@ -1061,6 +1071,16 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
return add(expr.leOrNull(propertyName, value));
}
@Override
public ExpressionList<T> ltIfPresent(String propertyName, @Nullable Object value) {
return value == null ? this : add(expr.lt(propertyName, value));
}
@Override
public ExpressionList<T> leIfPresent(String propertyName, @Nullable Object value) {
return value == null ? this : add(expr.le(propertyName, value));
}
@Override
public ExpressionList<T> not(Expression exp) {
return add(expr.not(exp));
@@ -677,6 +677,16 @@ final class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expr
return exprList.geOrNull(propertyName, value);
}
@Override
public ExpressionList<T> gtIfPresent(String propertyName, @Nullable Object value) {
return value == null ? this : exprList.gt(propertyName, value);
}
@Override
public ExpressionList<T> geIfPresent(String propertyName, @Nullable Object value) {
return value == null ? this : exprList.ge(propertyName, value);
}
@Override
public ExpressionList<T> having() {
throw new IllegalStateException("having() not allowed on Junction expression list");
@@ -837,6 +847,16 @@ final class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expr
return exprList.leOrNull(propertyName, value);
}
@Override
public ExpressionList<T> ltIfPresent(String propertyName, @Nullable Object value) {
return value == null ? this : exprList.lt(propertyName, value);
}
@Override
public ExpressionList<T> leIfPresent(String propertyName, @Nullable Object value) {
return value == null ? this : exprList.le(propertyName, value);
}
@Override
public ExpressionList<T> ne(String propertyName, Query<?> subQuery) {
return exprList.ne(propertyName, subQuery);
@@ -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);
}
}
@@ -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);
}
@@ -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);
}
}
}
@@ -1,30 +1,25 @@
package io.ebeaninternal.server.profile;
import io.ebean.ProfileLocation;
import io.ebean.util.StackWalkFilter;
import java.util.stream.Stream;
/**
* Default profile location that uses stack trace.
*/
class DProfileLocation implements ProfileLocation {
private static final String IO_EBEAN = "io.ebean";
private static final String UNKNOWN = "unknown";
private final boolean withLine;
private String fullLocation;
private String location;
private String label;
private final int lineNumber;
private int traceCount;
DProfileLocation() {
this(0);
}
/**
* Create with a given line number.
*/
DProfileLocation(int lineNumber) {
this.lineNumber = lineNumber;
DProfileLocation(boolean withLine) {
this.withLine = withLine;
}
@Override
@@ -44,7 +39,7 @@ class DProfileLocation implements ProfileLocation {
return false;
}
final String loc = create();
final String location = UtilLocation.loc(loc);
final String location = UtilLocation.loc(loc, withLine);
this.label = UtilLocation.label(location);
this.location = location;
this.fullLocation = loc;
@@ -88,25 +83,14 @@ class DProfileLocation implements ProfileLocation {
}
private String create() {
// relatively expensive but we only do it once per profile location
StackTraceElement[] trace = Thread.currentThread().getStackTrace();
for (int i = 3; i < trace.length; i++) {
if (!trace[i].getClassName().startsWith(IO_EBEAN)) {
return withLineNumber(trace[i].toString());
}
}
return UNKNOWN;
return StackWalker.getInstance().walk(this::filter);
}
private String withLineNumber(String traceLine) {
if (lineNumber == 0) {
return traceLine;
} else if (traceLine.endsWith(":1)")) {
return traceLine.substring(0, traceLine.length() - 3) + ":" + lineNumber + ")";
} else if (traceLine.contains(":")) {
return traceLine;
} else {
return traceLine.substring(0, traceLine.length() - 1) + ":" + lineNumber + ")";
}
private String filter(Stream<StackWalker.StackFrame> frames) {
return frames.filter(StackWalkFilter.filter())
.findFirst()
.map(Object::toString)
.orElse(UNKNOWN);
}
}
@@ -2,7 +2,6 @@ package io.ebeaninternal.server.profile;
import io.ebean.ProfileLocation;
import io.ebean.metric.MetricFactory;
import io.ebean.metric.TimedMetric;
import io.ebean.service.SpiProfileLocationFactory;
/**
@@ -12,15 +11,18 @@ public final class DProfileLocationFactory implements SpiProfileLocationFactory
@Override
public ProfileLocation create() {
return new DProfileLocation();
return new DProfileLocation(false);
}
@Override
public ProfileLocation create(int lineNumber, String label) {
public ProfileLocation createWithLine() {
return new DProfileLocation(true);
}
TimedMetric timedMetric = MetricFactory.get().createTimedMetric("txn.named." + label);
DTimedProfileLocation loc = new DTimedProfileLocation(lineNumber, label, timedMetric);
@Override
public ProfileLocation create(String label) {
final var timedMetric = MetricFactory.get().createTimedMetric("txn.named." + label);
final var loc = new DTimedProfileLocation(label, timedMetric);
TimedProfileLocationRegistry.register(loc);
return loc;
}
@@ -15,8 +15,8 @@ final class DTimedProfileLocation extends DProfileLocation implements TimedProfi
private String fullName;
private String reportName;
DTimedProfileLocation(int lineNumber, String label, TimedMetric timedMetric) {
super(lineNumber);
DTimedProfileLocation(String label, TimedMetric timedMetric) {
super(false);
this.label = label;
this.timedMetric = timedMetric;
this.overrideMetricName = "".equals(label);
@@ -3,14 +3,23 @@ package io.ebeaninternal.server.profile;
final class UtilLocation {
static String loc(String full) {
return loc(full, false);
}
static String loc(String full, boolean includeLineNumber) {
final int pos = full.lastIndexOf('(');
if (pos > -1) {
return full.substring(0, pos);
return !includeLineNumber ? full.substring(0, pos) : full.substring(0, pos) + lineNumberFrom(full);
} else {
return full;
}
}
private static String lineNumberFrom(String full) {
int pos = full.lastIndexOf(':');
return pos == -1 ? "" : full.substring(pos, full.length() - 1);
}
static String label(String location) {
return trimInit(shortDesc(location));
}
@@ -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());
}
/**
@@ -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();
}
}
@@ -0,0 +1,11 @@
package io.ebeaninternal.server.core;
/**
* Make DefaultCallOriginFactory accessible to tests.
*/
public class HelpDefaultCallOriginFactory {
public static CallOriginFactory create(int maxStack) {
return new DefaultCallOriginFactory(maxStack);
}
}
@@ -16,7 +16,7 @@ class BasicProfileLocationTest {
@Test
void metricNameFromOverride() {
DTimedProfileLocation loc = new DTimedProfileLocation(12, "", MetricFactory.get().createTimedMetric("a.b.c"));
DTimedProfileLocation loc = new DTimedProfileLocation("", MetricFactory.get().createTimedMetric("a.b.c"));
loc.initWith("foo.label");
loc.add(42);
@@ -39,7 +39,7 @@ class BasicProfileLocationTest {
@Test
void metricNameFromTimed() {
DTimedProfileLocation loc = new DTimedProfileLocation(12, "foo", MetricFactory.get().createTimedMetric("a.b.c"));
DTimedProfileLocation loc = new DTimedProfileLocation("foo", MetricFactory.get().createTimedMetric("a.b.c"));
loc.add(42);
BasicMetricVisitor visitor = new BasicMetricVisitor("v", naming);
@@ -52,23 +52,12 @@ class BasicProfileLocationTest {
@Test
void obtain() {
DProfileLocation loc = new DTimedProfileLocation(12, "foo", MetricFactory.get().createTimedMetric("junk"));
DProfileLocation loc = new DTimedProfileLocation("foo", MetricFactory.get().createTimedMetric("junk"));
String javaVersion = System.getProperty("java.version");
assertThat(loc.obtain()).isTrue();
if (javaVersion.startsWith("1.8")) {
assertThat(loc.fullLocation()).endsWith("invoke0(Native Method:12)");
assertThat(loc.location()).isEqualTo("sun.reflect.NativeMethodAccessorImpl.invoke0");
assertThat(loc.label()).isEqualTo("NativeMethodAccessorImpl.invoke0");
} else if (javaVersion.startsWith("18") || javaVersion.startsWith("19") || javaVersion.startsWith("20")){
assertThat(loc.fullLocation()).endsWith("jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)");
assertThat(loc.location()).isEqualTo("java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke");
assertThat(loc.label()).isEqualTo("DirectMethodHandleAccessor.invoke");
} else if (javaVersion.startsWith("11") || javaVersion.startsWith("17")) {
assertThat(loc.fullLocation()).endsWith("jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method:12)");
assertThat(loc.location()).isEqualTo("java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0");
assertThat(loc.label()).isEqualTo("NativeMethodAccessorImpl.invoke0");
}
assertThat(loc.fullLocation()).endsWith("org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725)");
assertThat(loc.location()).isEqualTo("org.junit.platform.commons.util.ReflectionUtils.invokeMethod");
assertThat(loc.label()).isEqualTo("ReflectionUtils.invokeMethod");
}
@Test
@@ -5,17 +5,23 @@ import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class UtilLocationTest {
class UtilLocationTest {
@Test
public void label() {
void label() {
Assertions.assertThat(UtilLocation.label("foo")).isEqualTo("foo");
assertThat(UtilLocation.label("ProfileLocationTest$Other.<init>")).isEqualTo("ProfileLocationTest$Other.init");
}
@Test
public void loc() {
void loc() {
assertThat(UtilLocation.loc("org.foo.MyFoo.doIt(MyFoo.java:12)")).isEqualTo("org.foo.MyFoo.doIt");
assertThat(UtilLocation.label("org.foo.MyFoo.doIt")).isEqualTo("MyFoo.doIt");
}
@Test
void locWithLineNumber() {
assertThat(UtilLocation.loc("org.foo.MyFoo.doIt(MyFoo.java:12)", true)).isEqualTo("org.foo.MyFoo.doIt:12");
assertThat(UtilLocation.label("org.foo.MyFoo.doIt:12")).isEqualTo("MyFoo.doIt:12");
}
}
@@ -0,0 +1,25 @@
package org.tests.server;
import io.ebean.bean.CallOrigin;
import io.ebeaninternal.server.core.CallOriginFactory;
import io.ebeaninternal.server.core.HelpDefaultCallOriginFactory;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
class TestDefaultCallOriginFactory {
private final CallOriginFactory factory = HelpDefaultCallOriginFactory.create(2);
@Test
void createCallOrigin() {
CallOrigin callOrigin = inner();
String topElement = callOrigin.getTopElement();
assertThat(topElement).contains("org.tests.server.TestDefaultCallOriginFactory.inner(TestDefaultCallOriginFactory.java:23)");
assertThat(callOrigin.getFullDescription()).contains("TestDefaultCallOriginFactory.java:16");
}
private CallOrigin inner() {
return factory.createCallOrigin();
}
}
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.4</version>
<version>13.13.2</version>
</parent>
<artifactId>ebean-csv-reader</artifactId>
@@ -14,21 +14,21 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
<scope>test</scope>
</dependency>
@@ -52,7 +52,7 @@
<extensions>true</extensions>
<configuration>
<tiles>
<tile>io.ebean.tile:enhancement:13.10.1</tile>
<tile>io.ebean.tile:enhancement:13.12.0</tile>
</tiles>
</configuration>
</plugin>
+19 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.4</version>
<version>13.13.2</version>
</parent>
<name>ebean ddl generation</name>
@@ -28,24 +28,38 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
<scope>provided</scope>
</dependency>
<!-- needed for java 11+ -->
<!-- JAVAX-DEPENDENCY-START -->
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.6</version>
<scope>provided</scope>
</dependency>
<!-- JAVAX-DEPENDENCY-END -->
<!-- JAKARTA-DEPENDENCY-START ___
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>4.0.0</version>
<scope>runtime</scope>
</dependency>
____ JAKARTA-DEPENDENCY-END -->
<!-- test dependencies -->
<dependency>
@@ -58,7 +72,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-all</artifactId>
<version>13.11.4</version>
<version>13.13.2</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.4</version>
<version>13.13.2</version>
</parent>
<name>ebean external mapping api</name>
+22 -8
View File
@@ -4,12 +4,12 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.4</version>
<version>13.13.2</version>
</parent>
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-parent-13.11.4</tag>
<tag>HEAD</tag>
</scm>
<name>ebean external mapping xml</name>
@@ -21,21 +21,35 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-api</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
</dependency>
<!-- JAVAX-DEPENDENCY-START -->
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.6</version>
</dependency>
<dependency>
<groupId>jakarta.activation</groupId>
<artifactId>jakarta.activation-api</artifactId>
<version>1.2.1</version>
<scope>provided</scope>
</dependency>
<!-- JAVAX-DEPENDENCY-END -->
<!-- JAKARTA-DEPENDENCY-START ___
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>4.0.0</version>
<scope>runtime</scope>
</dependency>
____ JAKARTA-DEPENDENCY-END -->
<dependency>
<groupId>io.avaje</groupId>
@@ -54,21 +68,21 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>13.11.4</version>
<version>13.13.2</version>
<scope>test</scope>
</dependency>
@@ -91,7 +105,7 @@
<configuration>
<tiles>
<!-- other tiles ... -->
<tile>io.ebean.tile:enhancement:13.10.1</tile>
<tile>io.ebean.tile:enhancement:13.12.0</tile>
</tiles>
</configuration>
</plugin>
@@ -1 +1 @@
ebean-version: 141
ebean-version: 143
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.11.4</version>
<version>13.13.2</version>
</parent>
<artifactId>ebean-jackson-jsonnode</artifactId>
@@ -14,7 +14,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>13.11.4</version>
<version>13.13.2</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.4</version>
<version>13.13.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -14,7 +14,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>13.11.4</version>
<version>13.13.2</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.4</version>
<version>13.13.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -14,7 +14,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>13.11.4</version>
<version>13.13.2</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);
}
}

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