Compare commits

..
Author SHA1 Message Date
Rob Bygrave 2c4b8492da ebean-test: Add PersistenceContextAccess.clear() for tests that need to clear the Persistence Context
To support tests that use a transaction that wraps test setup and running the test logic. The need for this case is to clear the persistence context after the test setup phase.
2024-03-16 14:56:24 +13:00
Rob BygraveandGitHub 02dafc9838 Merge pull request #3360 from ebean-orm/feature/refactor-DbExpressionRequest
Refactor extract DbExpressionRequest interface for db platform specific expressions
2024-03-08 00:53:56 +13:00
Rob Bygrave 0816810d3b Refactor extract DbExpressionRequest interface for db platform specific expressions
This provides a simpler DbExpressionRequest interface for db platform specific expression adapters (rather than the SpiExpressionRequest which has more features that we don't wish to expose to those expression adapters.
2024-03-07 22:45:21 +13:00
Rob Bygrave 1f6e2ee844 No effective change - update test only ClusterTest, increase wait to 200ms 2024-03-07 20:59:41 +13:00
Rob Bygrave dc00765a98 Merge branch 'fix-for-db2' 2024-03-07 20:45:57 +13:00
Rob Bygrave a48b2f4ebe #3354 Use 4000 for DB Lob detection with distinct query
- Use 4000 to match the DB2 logic for considering a column a lob (for distinct etc)
- Rename distinctNoLobs -> platformDistinctNoLobs
- Rename  isDbLob() -> isLobForPlatform()
- Rename unselectLobs() -> unselectLobsForPlatform()
2024-03-07 20:45:40 +13:00
Rob BygraveandGitHub 837563544f Merge pull request #3357 from ebean-orm/feature/avaje-config-dependency-ContainerConfig
Modify ContainerConfig to remove the avaje-config dependency
2024-03-07 20:23:36 +13:00
Rob Bygrave fd199f406b Modify ContainerConfig to remove the avaje-config dependency
This actually reverts a change that was made in commit:
https://github.com/ebean-orm/ebean/commit/803f1d86428ce3b653276d72207e5a0009b57d16
2024-03-05 21:18:27 +13:00
Roland Praml a48e96c7e9 FIX broken test for DB2 2024-03-04 10:02:05 +01:00
Rob Bygrave 7ba6e5f67d Add howto-deploy-to-central.md 2024-03-03 22:08:47 +13:00
Rob Bygrave 6ce42b1ca3 Version 14.0.1 2024-03-03 20:24:26 +13:00
Rob BygraveandGitHub 89617cefbe Merge pull request #3353 from ebean-orm/feature/bump-migration-14
dep: Bump ebean-migration to 14.0.0, no effective change
2024-03-03 20:19:40 +13:00
Rob Bygrave dd377621a4 dep: Bump ebean-migration to 14.0.0, no effective change
No effective change in that ebean-migration 14.0.0 has no change, it was released to align version numbers with 14.x
2024-03-03 20:19:17 +13:00
Rob Bygrave d844855462 Bump ebean-agent to 14.0.1 2024-03-03 18:32:14 +13:00
Rob BygraveandGitHub f68c25d5f3 Merge pull request #3352 from ebean-orm/feature/dep-common-components
dep: Update the common components to 14.0.0 ebean-joda-types, ebean-jackson-jsonnode
2024-03-03 18:29:15 +13:00
Rob Bygrave 61cfc7a979 dep: Update the common components to 14.0.0 ebean-joda-types, ebean-jackson-jsonnode 2024-03-03 17:01:36 +13:00
Rob BygraveandGitHub 3c98ee7f1b Merge pull request #3351 from ebean-orm/dep/bump-config
Bump test dependencies only - logback and ebean-test-containers
2024-03-03 16:54:56 +13:00
Rob Bygrave 0738316f15 Bump test dependencies only - logback and ebean-test-containers 2024-03-03 16:54:22 +13:00
Rob BygraveandGitHub ceb83befa3 Merge pull request #3350 from ebean-orm/dep/bump-config
dep: Bump avaje-config to 3.12 - supports AWS AppConfig & Dynamic Logback
2024-03-03 15:42:59 +13:00
Rob Bygrave a0b04cceda dep: Bump avaje-config to 3.12 - supports AWS AppConfig & Dynamic Logback
This version of avaje-config supports using AWS AppConfig as a configuration source (via avaje-aws-appconfig). It also supports dynamic changing Logback logging levels (via avaje-dynamic-logback).
2024-03-03 15:38:14 +13:00
Rob Bygrave 03edfb5454 git workflow trigger on push to master and pull_request 2024-03-03 15:33:39 +13:00
Rob BygraveandGitHub 62015451df Merge pull request #3349 from ebean-orm/feature/dep-ebean-datasource
dep: Bump ebean-datasource to 8.12
2024-03-03 15:32:36 +13:00
Rob Bygrave ed9113efe6 dep: Bump ebean-datasource to 8.12
This adds the option to register a JVM shutdown hook (which we generally will not use with ebean as the ebean io.ebean.Database shutdown wants to shutdown the DataSource after any background tasks have completed).

This also adds an experimental feature for use with AWS Lambda to check for old idle connections due to lambda suspension.
2024-03-03 15:24:44 +13:00
Rob Bygrave 334793667e Add deployment error message for ManyToMany with one of the related beans missing an @Id property 2024-03-03 14:14:23 +13:00
Rob BygraveandGitHub 351a1c4739 Merge pull request #3348 from ebean-orm/feature/3313-fetchGroup-with-config
#3313 Ability to configure fetch batch size when using FetchGroups and query beans
2024-03-03 13:53:52 +13:00
Rob Bygrave b2de333dcc #3313 Ability to configure fetch batch size when using FetchGroups and query beans
We can do this currently using string paths and properties, this adds support for doing this when using query beans and strong types
2024-03-03 13:47:49 +13:00
Rob Bygrave 6091f7b683 No effective change - tidy test TestJsonImplicitLoaded 2024-03-03 12:25:25 +13:00
Rob BygraveandGitHub 43fb84cbc0 Merge pull request #3345 from FOCONIS/jsonwrite-loaded-props
NEW: Allow control of jsonwrite-loadedprops
2024-03-03 12:23:17 +13:00
Rob BygraveandGitHub 52a4e9e19b Merge pull request #3347 from ebean-orm/feature/3337-querybean-imports
#3337 Fix querybean-generation to not import the entity bean type
2024-03-03 12:17:42 +13:00
Rob Bygrave a2cdea24ed #3337 Fix querybean-generation to not import the entity bean type
Use the full canonical name of the entity bean in the generated code.
2024-03-03 12:13:49 +13:00
Rob Bygrave cd780208e5 Javadoc format only for io.ebean.Database 2024-03-03 11:45:36 +13:00
Rob BygraveandGitHub 9ce0e923d7 Merge pull request #3346 from ebean-orm/feature/lengthCheck-postgres
#3341 String length validation with Postgres PGobject (JSON/JSONB)
2024-03-02 10:26:52 +13:00
Rob Bygrave 9e461e4708 #3341 String length validation with Postgres PGobject (JSON/JSONB) 2024-03-02 10:06:22 +13:00
Rob Bygrave 5fa09a6f90 #3341 String length validation with Postgres PGobject (JSON/JSONB) 2024-03-02 09:52:04 +13:00
Rob Bygrave 6babb2e6f5 Add ebean.lengthCheck for mariadb test run 2024-03-02 09:39:25 +13:00
Rob Bygrave 26abe27e42 Add ebean.lengthCheck for sqlserver17 test run 2024-03-02 09:38:33 +13:00
Rob Bygrave 9b18d46b78 Add ebean.lengthCheck for mysql test run 2024-03-02 09:27:05 +13:00
Roland Praml eed487ad26 NEW: Allow control of jsonwrite-loadedprops 2024-02-29 13:26:22 +01:00
Rob BygraveandGitHub c10865dfaf Merge pull request #3344 from ebean-orm/feature/bump-avaje-config-311
Bump avaje-config to 3.11
2024-02-27 21:22:38 +13:00
Rob Bygrave 2352df309c Bump avaje-config to 3.11 2024-02-27 21:21:58 +13:00
Rob Bygrave feb2bd1e15 String length validation tidy up 2024-02-27 21:04:19 +13:00
Rob Bygrave 11c9bdfc6f Squashed commit of the following:
commit 20152e16891582f8ff466a93ec2cf01871824d6d
Author: Rob Bygrave <robin.bygrave@gmail.com>
Date:   Tue Feb 27 20:59:51 2024 +1300

    #3341 Update DatabaseConfig for fluid style + javadoc

commit 1c495a7384
Author: Roland Praml <roland.praml@foconis.de>
Date:   Mon Feb 26 10:25:42 2024 +0100

    Fix: Compile errors

commit 574876b758
Merge: df7b04877 77634fc3e
Author: Roland Praml <roland.praml@foconis.de>
Date:   Fri Feb 23 16:16:39 2024 +0100

    Merge branch 'master-rob' into FOCONIS-string-length-validation

commit df7b04877d
Author: Rob Bygrave <robin.bygrave@gmail.com>
Date:   Mon Jun 26 21:16:32 2023 +1200

    #3121 BindMaxLength validation

    At deploy time derive a BindMaxLength property to use
    per BeanProperty

commit 4683877e0b
Merge: 9a4b9d4be d0020ab8c
Author: Rob Bygrave <robin.bygrave@gmail.com>
Date:   Fri Jun 23 16:51:34 2023 +1200

    Merge branch 'string-length-validation' of github.com:FOCONIS/ebean into FOCONIS-string-length-validation

commit d0020ab8ce
Author: Roland Praml <roland.praml@foconis.de>
Date:   Tue Jun 20 14:47:20 2023 +0200

    Length validation less invasive

commit 9b3b8ad46a
Author: Roland Praml <roland.praml@foconis.de>
Date:   Tue Jun 20 13:03:04 2023 +0200

    extended DataBind, so that it could return the last bound object

commit ca3c02bc1c
Author: Roland Praml <roland.praml@foconis.de>
Date:   Mon Jun 19 09:52:52 2023 +0200

    Failing test for SqlServer
2024-02-27 21:04:06 +13:00
Rob BygraveandGitHub 4a6fc98395 Merge pull request #3339 from ebean-orm/fix/3338
Fix for #3338 Potential shutdown hang with SpringContextShutdownHook …
2024-02-26 21:58:39 +13:00
Rob Bygrave 7322030e90 Fix for #3338 Potential shutdown hang with SpringContextShutdownHook and ebean ShutdownHook 2024-02-26 08:32:44 +13:00
Rob BygraveandGitHub 77634fc3eb Merge pull request #3336 from ebean-orm/feature/bump-postgresql-4272
Bump postgresql dependency to 42.7.2
2024-02-21 16:11:24 +13:00
robin.bygrave ed8d4b5fc4 Bump postgresql dependency to 42.7.2 2024-02-21 16:05:13 +13:00
Rob BygraveandGitHub 187cc0903d Merge pull request #3329 from ebean-orm/feature/bump-test-dependencies
Bump test dependencies for assertj and bytebuddy
2024-02-19 22:04:56 +13:00
Rob Bygrave 1d7a14c8f4 Bump test dependencies for assertj and bytebuddy 2024-02-19 21:51:38 +13:00
Rob Bygrave c58b7d3da3 Test ebean.properties config values 2024-02-15 22:51:26 +13:00
Rob Bygrave 6b2cdc14aa Version 14.0.0 2024-02-15 22:48:38 +13:00
Rob Bygrave 6d712a92a0 Bump ebean-agent to 14.0.0, no functional change 2024-02-15 22:21:09 +13:00
Rob BygraveandGitHub ea11b0c3b6 Merge pull request #3289 from FOCONIS/fix-nested-user-objects
Change semantic of userObjects in nested transaction
2024-02-15 22:10:45 +13:00
Rob BygraveandGitHub 08e8402d05 Merge pull request #3301 from ebean-orm/feature/3295-PC-clear-on-bulk-update
#3295 Clear PersistenceContext on execution of bulk updates or deletes
2024-02-15 22:09:16 +13:00
Rob BygraveandGitHub 006ad79379 Merge branch 'master' into feature/3295-PC-clear-on-bulk-update 2024-02-15 22:09:03 +13:00
Rob BygraveandGitHub 0e063549cd Merge pull request #3327 from ebean-orm/feature/remove-deprecated-commitTransaction
Remove deprecated database.commitTransaction(), migrate to transaction.commit()
2024-02-15 22:07:32 +13:00
Rob BygraveandGitHub 4f0d2cabfb Merge pull request #3325 from ebean-orm/feature/default-batchSize-100
Change default persistBatchSize from 20 to 100 (as a better default value)
2024-02-15 22:07:14 +13:00
Rob Bygrave 80b2d9f983 Remove deprecated database.commitTransaction(), migrate to transaction.commit()
Remove the deprecated methods:
- DB.commitTransaction()
- DB.rollbackTransaction()
- DB.endTransaction()
- database.commitTransaction()
- database.rollbackTransaction()
- database.endTransaction()

Migrate to using try-with-resources and transaction.commit(), transaction.rollback()
2024-02-15 21:56:57 +13:00
Rob Bygrave 287d0c467d #3326 Update the test example of Postgres DML with RETURNING clause to use explicit transactions and transaction.addModification() 2024-02-11 14:25:01 +13:00
Rob Bygrave a8835379e7 #3326 Add test as example of Postgres DML with RETURNING clause 2024-02-11 13:18:19 +13:00
Rob Bygrave e4df20b9dc Update test TestPersistCascade with default batch size 100 2024-02-10 13:28:04 +13:00
Rob Bygrave e6e53e0d93 Change default persistBatchSize from 20 to 100 (as a better default value)
This is the batch size used with PreparedStatement executeBatch() with
batched inserts, updates and deletes. 20 is really on the low side and
bumping this default to 100 seems good and right.
2024-02-10 12:15:50 +13:00
Rob Bygrave 6645e5b9ec Update the test comments in TestPersistenceContextQueryScope
To reflect the behaviour with #3295
2024-01-19 08:58:19 +13:00
Rob Bygrave 3576aafffc #3295 When isAutoPersistUpdates is used do NOT clear the PersistenceContext
Also make improvements to the test asserts in TestPersistenceContextQueryScope
2024-01-10 23:23:47 +13:00
Rob Bygrave 66234249c6 #3295 Clear PersistenceContext on execution of bulk updates or deletes
Using SqlUpdate or an ORM Update query clear the appropriate part of
the PersistenceContext. The effect is that ORM queries executed after
a bulk update will effectively load a fresh copy of the data from the
database and will not reuse an instance from the persistence context
if the bean in question had already been loaded.
2024-01-09 07:44:27 +13:00
Roland Praml 6f64821584 Change semantic of userObjects in nested transaction 2023-12-08 14:50:30 +01:00
165 changed files with 1606 additions and 760 deletions
+4 -1
View File
@@ -1,7 +1,10 @@
name: Build
on: [push, pull_request]
on:
pull_request:
push:
branches: master
jobs:
build:
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-clickhouse</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-db2</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-hana</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-mariadb</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-mysql</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-nuodb</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-oracle</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
</dependencies>
+7 -7
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
<relativePath>../..</relativePath>
</parent>
@@ -14,7 +14,7 @@
<properties>
<postgis.jdbc.version>2.5.1</postgis.jdbc.version>
<postgres.jdbc.version>42.6.0</postgres.jdbc.version>
<postgres.jdbc.version>42.7.2</postgres.jdbc.version>
</properties>
<dependencies>
@@ -22,13 +22,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
@@ -47,19 +47,19 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgis-types</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlite</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlserver</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
</dependencies>
+8 -8
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,31 +17,31 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-joda-time</artifactId>
<version>13.24.0</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-jackson-jsonnode</artifactId>
<version>13.24.0</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-jackson-mapper</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
@@ -60,13 +60,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-all</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
</dependencies>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</parent>
<artifactId>composites</artifactId>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</parent>
<name>ebean api</name>
@@ -39,7 +39,7 @@
<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-config</artifactId>
<version>3.10</version>
<version>3.12</version>
</dependency>
<dependency>
-49
View File
@@ -266,55 +266,6 @@ public final class DB {
getDefault().register(transactionCallback);
}
/**
* Deprecated for removal migrate using try-with-resources and commit on the transaction itself.
* <p>
* Commit the current transaction.
*/
@Deprecated(forRemoval = true)
public static void commitTransaction() {
getDefault().commitTransaction();
}
/**
* Deprecated for removal migrate to using try-with-resources and rollback on the transaction itself.
* <p>
* Rollback the current transaction.
*/
@Deprecated(forRemoval = true)
public static void rollbackTransaction() {
getDefault().rollbackTransaction();
}
/**
* If the current transaction has already been committed do nothing otherwise
* rollback the transaction.
* <p>
* It is preferable to use <em>try with resources</em> rather than this.
* <p>
* Useful to put in a finally block to ensure the transaction is ended, rather
* than a rollbackTransaction() in each catch block.
* <p>
* Code example:
*
* <pre>{@code
* DB.beginTransaction();
* try {
* // do some fetching and or persisting
*
* // commit at the end
* DB.commitTransaction();
*
* } finally {
* // if commit didn't occur then rollback the transaction
* DB.endTransaction();
* }
* }</pre>
*/
public static void endTransaction() {
getDefault().endTransaction();
}
/**
* Mark the current transaction as rollback only.
*/
@@ -3,7 +3,7 @@ package io.ebean;
import jakarta.persistence.PersistenceException;
/**
* Thrown when a foreign key constraint is enforced.
* Thrown when a foreign key constraint is enforced or a field is too large.
*/
public class DataIntegrityException extends PersistenceException {
private static final long serialVersionUID = -6740171949170180970L;
@@ -14,4 +14,11 @@ public class DataIntegrityException extends PersistenceException {
public DataIntegrityException(String message, Throwable cause) {
super(message, cause);
}
/**
* Create with message only.
*/
public DataIntegrityException(String message) {
super(message);
}
}
+10 -53
View File
@@ -88,16 +88,16 @@ public interface Database {
/**
* Return a new database builder.
* <pre>{@code
*
* // build the 'default' database using configuration
* // from application.properties / application.yaml
*
* Database db = Database.builder()
* .loadFromProperties()
* .build();
*
* }</pre>
* <pre>{@code
*
* // build the 'default' database using configuration
* // from application.properties / application.yaml
*
* Database db = Database.builder()
* .loadFromProperties()
* .build();
*
* }</pre>
*/
static DatabaseBuilder builder() {
return new DatabaseConfig();
@@ -666,49 +666,6 @@ public interface Database {
*/
void flush();
/**
* Deprecated for removal migrate using try-with-resources and commit on the transaction itself.
* <p>
* Commit the current transaction.
*/
@Deprecated(forRemoval = true)
void commitTransaction();
/**
* Deprecated for removal migrate to using try-with-resources and rollback on the transaction itself.
* <p>
* Rollback the current transaction.
*/
@Deprecated(forRemoval = true)
void rollbackTransaction();
/**
* If the current transaction has already been committed do nothing otherwise
* rollback the transaction.
* <p>
* Useful to put in a finally block to ensure the transaction is ended, rather
* than a rollbackTransaction() in each catch block.
* <p>
* Code example:
* <p>
* <pre>{@code
*
* database.beginTransaction();
* try {
* // do some fetching and or persisting ...
*
* // commit at the end
* database.commitTransaction();
*
* } finally {
* // if commit didn't occur then rollback the transaction
* database.endTransaction();
* }
*
* }</pre>
*/
void endTransaction();
/**
* Refresh the values of a bean.
* <p>
@@ -87,6 +87,7 @@ public interface DatabaseBuilder {
}
return this;
}
/**
* Set the name of the Database.
*/
@@ -2221,6 +2222,11 @@ public interface DatabaseBuilder {
@Deprecated
DatabaseBuilder setMetricNaming(Function<String, String> metricNaming);
/**
* Sets the length check mode.
*/
DatabaseConfig lengthCheck(LengthCheck lengthCheck);
/**
* Provides read access (getters) for the DatabaseBuilder configuration
* that has been set.
@@ -3103,5 +3109,9 @@ public interface DatabaseBuilder {
*/
Function<String, String> getMetricNaming();
/**
* Returns the length check mode.
*/
LengthCheck getLengthCheck();
}
}
@@ -1,8 +1,5 @@
package io.ebean.config;
import io.avaje.config.Config;
import io.avaje.config.Configuration;
import java.util.Properties;
/**
@@ -19,16 +16,6 @@ public class ContainerConfig {
private String podName;
private int port;
private Properties properties;
private Configuration configuration;
public ContainerConfig() {
this.configuration = Config.asConfiguration();
this.active = configuration.getBool("ebean.cluster.active", active);
this.serviceName = configuration.getNullable("ebean.cluster.serviceName", serviceName);
this.namespace = configuration.getNullable("ebean.cluster.namespace", namespace);
this.podName = configuration.getNullable("ebean.cluster.podName", podName);
this.port = configuration.getInt("ebean.cluster.port", 0);
}
/**
* Return the service name.
@@ -104,7 +91,7 @@ public class ContainerConfig {
* Return the deployment properties.
*/
public Properties getProperties() {
return properties != null ? properties : configuration.asProperties();
return properties;
}
/**
@@ -114,4 +101,25 @@ public class ContainerConfig {
this.properties = properties;
}
/**
* Load the settings from properties.
*/
public void loadFromProperties(Properties properties) {
this.properties = properties;
this.active = getProperty(properties, "ebean.cluster.active", active);
this.serviceName = properties.getProperty("ebean.cluster.serviceName", serviceName);
this.namespace = properties.getProperty("ebean.cluster.namespace", namespace);
this.podName = properties.getProperty("ebean.cluster.podName", podName);
String portParam = properties.getProperty("ebean.cluster.port");
if (portParam != null) {
this.port = Integer.parseInt(portParam);
}
}
/**
* Return the boolean property setting.
*/
protected boolean getProperty(Properties properties, String key, boolean defaultValue) {
return "true".equalsIgnoreCase(properties.getProperty(key, Boolean.toString(defaultValue)));
}
}
@@ -236,7 +236,7 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
*/
private PersistBatch persistBatchOnCascade = PersistBatch.INHERIT;
private int persistBatchSize = 20;
private int persistBatchSize = 100;
private EnumType defaultEnumType = EnumType.ORDINAL;
@@ -545,6 +545,8 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
private String dumpMetricsOptions;
private LengthCheck lengthCheck = LengthCheck.OFF;
private Function<String, String> metricNaming = MetricNamingMatch.INSTANCE;
/**
@@ -2195,6 +2197,7 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
jdbcFetchSizeFindEach = p.getInt("jdbcFetchSizeFindEach", jdbcFetchSizeFindEach);
jdbcFetchSizeFindList = p.getInt("jdbcFetchSizeFindList", jdbcFetchSizeFindList);
databasePlatformName = p.get("databasePlatformName", databasePlatformName);
lengthCheck = p.getEnum(LengthCheck.class, "lengthCheck", lengthCheck);
uuidVersion = p.getEnum(UuidVersion.class, "uuidVersion", uuidVersion);
uuidStateFile = p.get("uuidStateFile", uuidStateFile);
@@ -2571,6 +2574,19 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
return this;
}
/**
* Returns the length check mode.
*/
public LengthCheck getLengthCheck() {
return lengthCheck;
}
@Override
public DatabaseConfig lengthCheck(LengthCheck lengthCheck) {
this.lengthCheck = lengthCheck;
return this;
}
public enum UuidVersion {
VERSION4,
VERSION1,
@@ -0,0 +1,22 @@
package io.ebean.config;
/**
* Defines the length-check mode.
*
* @author Roland Praml, FOCONIS AG
*/
public enum LengthCheck {
/**
* By default, length checking is off. This means, strings/jsons and files are passed to the DB and the DB might or might not check the length.
* The DB has to check the data length. Note this is not possible for certain datatypes (e.g. clob without size)
*/
OFF,
/**
* When enabling length check, ebean validates strings/json strings and files before saving them to DB.
*/
ON,
/**
* Same as "ON", but take the UTF8-bytelength for validation. This may be useful, if you have an UTF8 based charset (default for DB2)
*/
UTF8
}
@@ -8,6 +8,7 @@ import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
@@ -23,7 +24,7 @@ public final class ShutdownManager {
private static final System.Logger log = EbeanVersion.log;
private static final ReentrantLock lock = new ReentrantLock();
private static final List<Database> databases = new ArrayList<>();
private static final List<Database> databases = Collections.synchronizedList(new ArrayList<>());
private static final ShutdownHook shutdownHook = new ShutdownHook();
private static boolean stopping;
@@ -177,12 +178,7 @@ public final class ShutdownManager {
* Register an ebeanServer to be shutdown when the JVM is shutdown.
*/
public static void registerDatabase(Database server) {
lock.lock();
try {
databases.add(server);
} finally {
lock.unlock();
}
databases.add(server);
}
/**
@@ -192,12 +188,7 @@ public final class ShutdownManager {
* </p>
*/
public static void unregisterDatabase(Database server) {
lock.lock();
try {
databases.remove(server);
} finally {
lock.unlock();
}
databases.remove(server);
}
private static class ShutdownHook extends Thread {
@@ -22,6 +22,8 @@ public class JsonWriteOptions {
protected JsonConfig.Include include;
protected boolean includeLoadedImplicit = true;
protected Map<String, JsonWriteBeanVisitor<?>> visitorMap;
/**
@@ -73,6 +75,20 @@ public class JsonWriteOptions {
this.include = include;
}
/**
* Should loaded properties be included implicit, if no other fetch path is specified (default = true).
*/
public boolean isIncludeLoadedImplicit() {
return includeLoadedImplicit;
}
/**
* Set include loaded properties implicit (default = true).
*/
public void setIncludeLoadedImplicit(boolean includeLoadedImplicit) {
this.includeLoadedImplicit = includeLoadedImplicit;
}
/**
* Register a JsonWriteBeanVisitor for the root level.
*/
@@ -75,6 +75,7 @@ class DatabaseConfigTest {
props.setProperty("defaultServer", "false");
props.setProperty("skipDataSourceCheck", "true");
props.setProperty("readOnlyDatabase", "true");
props.setProperty("lengthCheck", "ON");
props.setProperty("queryPlan.enable", "true");
props.setProperty("queryPlan.thresholdMicros", "10000");
@@ -95,6 +96,7 @@ class DatabaseConfigTest {
assertTrue(settings.isLoadModuleInfo());
assertTrue(settings.skipDataSourceCheck());
assertTrue(settings.readOnlyDatabase());
assertThat(settings.getLengthCheck()).isEqualTo(LengthCheck.ON);
assertTrue(settings.isIdGeneratorAutomatic());
assertFalse(settings.getPlatformConfig().isCaseSensitiveCollation());
@@ -128,8 +130,11 @@ class DatabaseConfigTest {
assertThat(settings.getMappingLocations()).containsExactly("classpath:/foo","bar");
config.setPersistBatch(PersistBatch.NONE);
config.setPersistBatchOnCascade(PersistBatch.NONE);
config.persistBatch(PersistBatch.NONE)
.persistBatchOnCascade(PersistBatch.NONE)
.lengthCheck(LengthCheck.ON)
.lengthCheck(LengthCheck.UTF8);
Properties props1 = new Properties();
props1.setProperty("ebean.persistBatch", "ALL");
@@ -146,6 +151,7 @@ class DatabaseConfigTest {
assertEquals(PersistBatch.ALL, settings.getPersistBatch());
assertEquals(PersistBatch.ALL, settings.getPersistBatchOnCascade());
assertEquals(LengthCheck.UTF8, settings.getLengthCheck());
config.setEnabledL2Regions("r0,orgs");
assertEquals("r0,orgs", settings.getEnabledL2Regions());
@@ -174,6 +180,7 @@ class DatabaseConfigTest {
assertEquals(600, config.getQueryPlanCapturePeriodSecs());
assertEquals(10000L, config.getQueryPlanCaptureMaxTimeMillis());
assertEquals(10, config.getQueryPlanCaptureMaxCount());
assertThat(config.getLengthCheck()).isEqualTo(LengthCheck.OFF);
config.setLoadModuleInfo(false);
assertFalse(config.isAutoLoadModuleInfo());
+31 -31
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</parent>
<name>ebean bom</name>
@@ -89,103 +89,103 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-joda-time</artifactId>
<version>13.24.0</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-jackson-jsonnode</artifactId>
<version>13.24.0</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-jackson-mapper</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-api</artifactId>
<version>13.18.0</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-xml</artifactId>
<version>13.18.0</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-autotune</artifactId>
<version>13.18.0</version>
<version>14.0.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>kotlin-querybean-generator</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-redis</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-spring-txn</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<!-- platforms -->
@@ -193,79 +193,79 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-clickhouse</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-db2</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-h2</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-hana</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-mariadb</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-mysql</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-nuodb</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-oracle</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgres</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgis</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgis-types</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-sqlite</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-sqlserver</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
</dependencies>
+3 -3
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</parent>
<artifactId>ebean-core-type</artifactId>
@@ -16,7 +16,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
@@ -30,7 +30,7 @@
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.6.0</version>
<version>42.7.2</version>
<optional>true</optional>
</dependency>
@@ -174,4 +174,9 @@ public interface DataBinder {
*/
String popJson();
/**
* Returns the last bound object (e.g. for BindValidation). Note for InputStreams you'll get an InputStreamInfo.
*/
Object popLastObject();
}
@@ -0,0 +1,27 @@
package io.ebean.core.type;
import java.io.InputStream;
/**
* Helper to transports length info of DataBind.setBinaryStream(stream, length) to BindValidation
*
* @author Roland Praml, FOCONIS AG
*/
public final class InputStreamInfo {
private final InputStream stream;
private final long length;
public InputStreamInfo(InputStream stream, long length) {
this.stream = stream;
this.length = length;
}
public InputStream stream() {
return stream;
}
public long length() {
return length;
}
}
+8 -8
View File
@@ -3,7 +3,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</parent>
<artifactId>ebean-core</artifactId>
@@ -22,7 +22,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
@@ -46,13 +46,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-api</artifactId>
<version>13.18.0</version>
<version>14.0.0</version>
</dependency>
<dependency>
@@ -151,7 +151,7 @@
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.6.0</version>
<version>42.7.2</version>
<optional>true</optional>
</dependency>
@@ -159,21 +159,21 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlserver</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
<scope>test</scope>
</dependency>
@@ -3,6 +3,8 @@ package io.ebeaninternal.api;
import io.ebean.TxScope;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
/**
* Used internally to handle the scoping of transactions for methods.
@@ -47,6 +49,11 @@ public final class ScopeTrans {
private boolean nestedCommit;
private boolean nestedUseSavepoint;
/**
* The UserObjects when using in nested transactions.
*/
private Map<String, Object> userObjects;
public ScopeTrans(boolean rollbackOnChecked, boolean created, SpiTransaction transaction, TxScope txScope) {
this.rollbackOnChecked = rollbackOnChecked;
this.created = created;
@@ -218,4 +225,17 @@ public final class ScopeTrans {
return e instanceof RuntimeException || rollbackOnChecked;
}
public void putUserObject(String name, Object value) {
if (userObjects == null) {
userObjects = new HashMap<>();
}
userObjects.put(name, value);
}
public Object getUserObject(String name) {
if (userObjects == null) {
return null;
}
return userObjects.get(name);
}
}
@@ -2,7 +2,6 @@ package io.ebeaninternal.api;
import io.ebeaninternal.server.transaction.TransactionScopeManager;
import io.ebeaninternal.server.util.ArrayStack;
import jakarta.persistence.PersistenceException;
/**
@@ -173,4 +172,31 @@ public final class ScopedTransaction extends SpiTransactionProxy {
return current.caughtThrowable(e);
}
/**
* New user objects are always written to the current ScopeTrans.
*/
@Override
public void putUserObject(String name, Object value) {
current.putUserObject(name, value);
}
/**
* Returns the userObject in the stack, Herew we search
* the stack and return the first found userObject
*/
@Override
public Object getUserObject(String name) {
Object obj = current.getUserObject(name);
if (obj != null) {
return obj;
}
for (ScopeTrans trans : stack) {
obj = trans.getUserObject(name);
if (obj != null) {
return obj;
}
}
return transaction.getUserObject(name);
}
}
@@ -86,6 +86,11 @@ public interface SpiEbeanServer extends SpiServer, ExtendedServer, BeanCollectio
*/
SpiTransactionManager transactionManager();
/**
* End the current transaction if it is active.
*/
void endTransaction();
/**
* Return all the descriptors.
*/
@@ -3,13 +3,14 @@ package io.ebeaninternal.api;
import io.ebeaninternal.server.core.SpiOrmQueryRequest;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.expression.platform.DbExpressionHandler;
import io.ebeaninternal.server.expression.platform.DbExpressionRequest;
import java.util.List;
/**
* Request object used for gathering expression sql and bind values.
*/
public interface SpiExpressionRequest {
public interface SpiExpressionRequest extends DbExpressionRequest {
/**
* Return the DB specific handler for JSON and ARRAY expressions.
@@ -34,11 +35,13 @@ public interface SpiExpressionRequest {
/**
* Append to the expression sql without any parsing.
*/
@Override
SpiExpressionRequest append(String expression);
/**
* Append to the expression sql without any parsing.
*/
@Override
SpiExpressionRequest append(char c);
/**
@@ -47,6 +50,7 @@ public interface SpiExpressionRequest {
* This is a fast path case when expression is a bean property path and falls back to using parse()
* when that isn't the case.
*/
@Override
SpiExpressionRequest property(String expression);
/**
@@ -1,10 +1,14 @@
package io.ebeaninternal.server.bind;
import io.ebean.core.type.DataBinder;
import io.ebean.core.type.InputStreamInfo;
import io.ebeaninternal.api.CoreLog;
import io.ebeaninternal.server.core.timezone.DataTimeZone;
import java.io.*;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.math.BigDecimal;
import java.sql.*;
import java.util.ArrayList;
@@ -23,6 +27,8 @@ public class DataBind implements DataBinder {
protected int pos;
private String json;
private Object lastObject = null;
public DataBind(DataTimeZone dataTimeZone, PreparedStatement pstmt, Connection connection) {
this.dataTimeZone = dataTimeZone;
this.pstmt = pstmt;
@@ -65,16 +71,19 @@ public class DataBind implements DataBinder {
@Override
public void setObject(Object value) throws SQLException {
pstmt.setObject(++pos, value);
lastObject = value;
}
@Override
public final void setObject(Object value, int sqlType) throws SQLException {
pstmt.setObject(++pos, value, sqlType);
lastObject = value;
}
@Override
public void setNull(int jdbcType) throws SQLException {
pstmt.setNull(++pos, jdbcType);
lastObject = null;
}
@Override
@@ -96,7 +105,7 @@ public class DataBind implements DataBinder {
}
}
private void closeInputStreams() {
public void closeInputStreams() {
if (inputStreams != null) {
for (InputStream inputStream : inputStreams) {
try {
@@ -117,36 +126,43 @@ public class DataBind implements DataBinder {
@Override
public void setString(String value) throws SQLException {
pstmt.setString(++pos, value);
lastObject = value;
}
@Override
public final void setInt(int value) throws SQLException {
pstmt.setInt(++pos, value);
lastObject = null;
}
@Override
public final void setLong(long value) throws SQLException {
pstmt.setLong(++pos, value);
lastObject = null;
}
@Override
public final void setShort(short value) throws SQLException {
pstmt.setShort(++pos, value);
lastObject = null;
}
@Override
public final void setFloat(float value) throws SQLException {
pstmt.setFloat(++pos, value);
lastObject = null;
}
@Override
public final void setDouble(double value) throws SQLException {
pstmt.setDouble(++pos, value);
lastObject = null;
}
@Override
public final void setBigDecimal(BigDecimal value) throws SQLException {
pstmt.setBigDecimal(++pos, value);
lastObject = null;
}
@Override
@@ -157,6 +173,7 @@ public class DataBind implements DataBinder {
} else {
pstmt.setDate(++pos, value);
}
lastObject = null;
}
@Override
@@ -167,6 +184,7 @@ public class DataBind implements DataBinder {
} else {
pstmt.setTimestamp(++pos, value);
}
lastObject = null;
}
@Override
@@ -177,26 +195,31 @@ public class DataBind implements DataBinder {
} else {
pstmt.setTime(++pos, value);
}
lastObject = null;
}
@Override
public void setBoolean(boolean value) throws SQLException {
pstmt.setBoolean(++pos, value);
lastObject = null;
}
@Override
public void setBytes(byte[] value) throws SQLException {
pstmt.setBytes(++pos, value);
lastObject = value;
}
@Override
public void setByte(byte value) throws SQLException {
pstmt.setByte(++pos, value);
lastObject = null;
}
@Override
public void setChar(char value) throws SQLException {
pstmt.setString(++pos, String.valueOf(value));
lastObject = null;
}
@Override
@@ -211,21 +234,31 @@ public class DataBind implements DataBinder {
}
inputStreams.add(inputStream);
pstmt.setBinaryStream(++pos, inputStream, length);
lastObject = new InputStreamInfo(inputStream, length);
}
@Override
public void setBlob(byte[] bytes) throws SQLException {
pstmt.setBinaryStream(++pos, new ByteArrayInputStream(bytes), bytes.length);
lastObject = bytes;
}
@Override
public void setClob(String content) throws SQLException {
pstmt.setCharacterStream(++pos, new StringReader(content), content.length());
lastObject = content;
}
@Override
public void setArray(String arrayType, Object[] elements) throws SQLException {
pstmt.setArray(++pos, connection.createArrayOf(arrayType, elements));
lastObject = null;
}
@Override
public Object popLastObject() {
Object ret = lastObject;
lastObject = null;
return ret;
}
}
@@ -756,16 +756,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
currentTransaction().flush();
}
@Override
public void commitTransaction() {
currentTransaction().commit();
}
@Override
public void rollbackTransaction() {
currentTransaction().rollback();
}
@Override
public void endTransaction() {
Transaction transaction = transactionManager.inScope();
@@ -773,4 +773,10 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
public int forwardOnlyFetchSize() {
return queryEngine.forwardOnlyFetchSize();
}
public void clearContext() {
if (!transaction.isAutoPersistUpdates()) {
beanDescriptor.contextClear(transaction.persistenceContext());
}
}
}
@@ -77,10 +77,13 @@ public final class PersistRequestOrmUpdate extends PersistRequest {
*/
@Override
public void postExecute() {
OrmUpdateType ormUpdateType = ormUpdate.ormUpdateType();
if (OrmUpdateType.INSERT != ormUpdateType && !transaction.isAutoPersistUpdates()) {
beanDescriptor.contextClear(transaction.persistenceContext());
}
if (startNanos > 0) {
persistExecute.collectOrmUpdate(label, startNanos);
}
OrmUpdateType ormUpdateType = ormUpdate.ormUpdateType();
String tableName = ormUpdate.baseTable();
if (transaction.isLogSummary()) {
transaction.logSummary("{0} table[{1}] rows[{2}] bind[{3}]", ormUpdateType, tableName, rowCount, bindLog);
@@ -3,10 +3,13 @@ package io.ebeaninternal.server.core;
import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.api.SpiSqlUpdate;
import io.ebeaninternal.api.SpiTransaction;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.persist.BatchControl;
import io.ebeaninternal.server.persist.PersistExecute;
import io.ebeaninternal.server.persist.TrimLogSql;
import java.util.List;
/**
* Persist request specifically for CallableSql.
*/
@@ -156,6 +159,14 @@ public final class PersistRequestUpdateSql extends PersistRequest {
*/
@Override
public void postExecute() {
if (sqlType != SqlType.SQL_INSERT && !transaction.isAutoPersistUpdates()) {
List<BeanDescriptor<?>> descriptors = server.descriptors(tableName);
if (descriptors != null) {
for (BeanDescriptor<?> descriptor : descriptors) {
descriptor.contextClear(transaction.persistenceContext());
}
}
}
if (startNanos > 0) {
persistExecute.collectSqlUpdate(label, startNanos);
}
@@ -2056,6 +2056,13 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
pc.clear(rootBeanType, idValue);
}
/**
* Clear a bean from the persistence context.
*/
public void contextClear(PersistenceContext pc) {
pc.clear(rootBeanType);
}
/**
* Delete a bean from the persistence context (such that we don't fetch it in the same transaction).
*/
@@ -106,6 +106,7 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
private final String asOfViewSuffix;
private final boolean jacksonCorePresent;
private final int queryPlanTTLSeconds;
private final BindMaxLength bindMaxLength;
private int entityBeanCount;
private List<BeanDescriptor<?>> immutableDescriptorList;
/**
@@ -160,6 +161,19 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
this.changeLogListener = config.changeLogListener(bootupClasses.getChangeLogListener());
this.changeLogRegister = config.changeLogRegister(bootupClasses.getChangeLogRegister());
this.jacksonCorePresent = config.isJacksonCorePresent();
this.bindMaxLength = initMaxLength();
}
BindMaxLength initMaxLength() {
LengthCheck lengthCheck = this.config.getLengthCheck();
switch (lengthCheck) {
case OFF:
return null;
case UTF8:
return BindMaxLength.ofUtf8();
default:
return BindMaxLength.ofStandard();
}
}
@Override
@@ -399,7 +413,7 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
* Return the BeanDescriptors mapped to the table.
*/
public List<BeanDescriptor<?>> descriptors(String tableName) {
return tableToDescMap.get(tableName.toLowerCase());
return tableName == null ? Collections.emptyList() : tableToDescMap.get(tableName.toLowerCase());
}
/**
@@ -1501,6 +1515,10 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
return list;
}
public BindMaxLength bindMaxLength() {
return bindMaxLength;
}
/**
* Comparator to sort the BeanDescriptors by name.
*/
@@ -1,6 +1,7 @@
package io.ebeaninternal.server.deploy;
import com.fasterxml.jackson.core.JsonToken;
import io.ebean.DataIntegrityException;
import io.ebean.ValuePair;
import io.ebean.bean.EntityBean;
import io.ebean.bean.EntityBeanIntercept;
@@ -40,8 +41,8 @@ import io.ebeanservice.docstore.api.mapping.DocMappingBuilder;
import io.ebeanservice.docstore.api.mapping.DocPropertyMapping;
import io.ebeanservice.docstore.api.mapping.DocPropertyOptions;
import io.ebeanservice.docstore.api.support.DocStructure;
import jakarta.persistence.PersistenceException;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
@@ -166,6 +167,7 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
*/
private final String dbComment;
private final DbEncryptFunction dbEncryptFunction;
private final BindMaxLength bindMaxLength;
private int deployOrder;
final boolean jsonSerialize;
final boolean jsonDeserialize;
@@ -258,6 +260,7 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
}
this.jsonSerialize = deploy.isJsonSerialize();
this.jsonDeserialize = deploy.isJsonDeserialize();
this.bindMaxLength = deploy.bindMaxLength();
}
private String tableAliasIntern(BeanDescriptor<?> descriptor, String s, boolean dbEncrypted, String dbColumn) {
@@ -345,6 +348,7 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
this.elPlaceHolderEncrypted = override.replace(source.elPlaceHolderEncrypted, source.dbColumn);
this.jsonSerialize = source.jsonSerialize;
this.jsonDeserialize = source.jsonDeserialize;
this.bindMaxLength = source.bindMaxLength;
}
/**
@@ -555,6 +559,18 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
@SuppressWarnings("unchecked")
public void bind(DataBind b, Object value) throws SQLException {
scalarType.bind(b, value);
if (bindMaxLength != null) {
Object obj = b.popLastObject();
long length = bindMaxLength.length(dbLength, obj);
if (length > dbLength) {
b.closeInputStreams();
String s = String.valueOf(value); // take original bind value here.
if (s.length() > 50) {
s = s.substring(0, 47) + "...";
}
throw new DataIntegrityException("Cannot bind value '" + s + "' (effective length=" + length + ") to column '" + dbColumn + "' (length=" + dbLength + ")");
}
}
}
@SuppressWarnings(value = "unchecked")
@@ -1166,14 +1182,14 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
* Returns true if this <code>isLob()</code> or the type will effectively map to a lob.
*/
@Override
public boolean isDbLob() {
public boolean isLobForPlatform() {
if (lob) {
return true;
}
switch (dbType) {
case DbPlatformType.JSON:
case DbPlatformType.JSONB:
return dbLength == 0; // must be analog to DbPlatformTypeMapping.lookup
return dbLength == 0 || dbLength > 4000; // must be analog to DbPlatformTypeMapping.lookup
case DbPlatformType.JSONBlob:
case DbPlatformType.JSONClob:
return true;
@@ -379,6 +379,9 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> implements ST
for (ExportedProperty exportedProperty : exportedProperties) {
row.addColumn(exportedProperty.getForeignDbColumn());
}
if (importedId == null) {
throw new PersistenceException("Missing @Id property on bean related to ManyToMany " + fullName());
}
importedId.buildImport(row);
return row.build();
}
@@ -0,0 +1,90 @@
package io.ebeaninternal.server.deploy;
import io.ebean.core.type.InputStreamInfo;
import java.nio.charset.StandardCharsets;
/**
* The max length check on bind values.
*/
public interface BindMaxLength {
/**
* Return a UTF8 based implementation.
*/
static BindMaxLength ofUtf8() {
return new UTF8();
}
/**
* Return a standard implementation.
*/
static BindMaxLength ofStandard() {
return new Standard();
}
/**
* Return the length of the object.
*/
long length(int dbLength, Object obj);
/**
* Length check based on UTF8 bytes.
*/
final class UTF8 implements BindMaxLength {
@Override
public long length(int dbLength, Object obj) {
if (obj == null) {
return -1;
} else if (obj instanceof String) {
String s = (String) obj;
return utf8String(dbLength, s);
} else if (obj instanceof byte[]) {
return ((byte[]) obj).length;
} else if (obj instanceof InputStreamInfo) {
return ((InputStreamInfo) obj).length();
} else if ("org.postgresql.util.PGobject".equals(obj.getClass().getCanonicalName())) {
String value = ((org.postgresql.util.PGobject) obj).getValue();
return value == null ? -1 : utf8String(dbLength, value);
} else {
return -1;
}
}
private static int utf8String(int dbLength, String s) {
int stringLength = s.length();
if (stringLength > dbLength) {
return stringLength;
} else if (stringLength * 4 <= dbLength) {
return -1;
} else {
return s.getBytes(StandardCharsets.UTF_8).length;
}
}
}
/**
* Standard string length implementation.
*/
final class Standard implements BindMaxLength {
@Override
public long length(int dbLength, Object obj) {
if (obj == null) {
return -1;
} else if (obj instanceof String) {
return ((String) obj).length();
} else if (obj instanceof byte[]) {
return ((byte[]) obj).length;
} else if (obj instanceof InputStreamInfo) {
return ((InputStreamInfo) obj).length();
} else if ("org.postgresql.util.PGobject".equals(obj.getClass().getCanonicalName())) {
String value = ((org.postgresql.util.PGobject) obj).getValue();
return value == null ? -1 : value.length();
} else {
return -1;
}
}
}
}
@@ -63,7 +63,7 @@ class DynamicPropertyAggregationFormula extends DynamicPropertyBase {
}
@Override
public boolean isDbLob() {
public boolean isLobForPlatform() {
return false;
}
@@ -1,10 +1,10 @@
package io.ebeaninternal.server.deploy.meta;
import io.ebean.DatabaseBuilder;
import io.ebean.annotation.Cache;
import io.ebean.annotation.DocStore;
import io.ebean.annotation.DocStoreMode;
import io.ebean.annotation.Identity;
import io.ebean.DatabaseBuilder;
import io.ebean.config.TableName;
import io.ebean.config.dbplatform.IdType;
import io.ebean.config.dbplatform.PlatformIdGenerator;
@@ -21,7 +21,6 @@ import io.ebeaninternal.server.idgen.UuidV1IdGenerator;
import io.ebeaninternal.server.idgen.UuidV1RndIdGenerator;
import io.ebeaninternal.server.idgen.UuidV4IdGenerator;
import io.ebeaninternal.server.rawsql.SpiRawSql;
import jakarta.persistence.Entity;
import jakarta.persistence.MappedSuperclass;
@@ -139,6 +138,10 @@ public class DeployBeanDescriptor<T> {
this.beanType = beanType;
}
public BindMaxLength bindMaxLength() {
return manager.bindMaxLength();
}
private String[] readPropertyNames() {
try {
Field field = beanType.getField("_ebean_props");
@@ -1,14 +1,17 @@
package io.ebeaninternal.server.deploy.meta;
import io.avaje.lang.Nullable;
import io.ebean.annotation.*;
import io.ebean.config.ScalarTypeConverter;
import io.ebean.config.dbplatform.DbDefaultValue;
import io.ebean.config.dbplatform.DbEncrypt;
import io.ebean.config.dbplatform.DbEncryptFunction;
import io.ebean.config.dbplatform.ExtraDbTypes;
import io.ebean.core.type.ScalarType;
import io.ebean.util.AnnotationUtil;
import io.ebeaninternal.server.core.InternString;
import io.ebeaninternal.server.deploy.BeanProperty;
import io.ebeaninternal.server.deploy.BindMaxLength;
import io.ebeaninternal.server.deploy.DbMigrationInfo;
import io.ebeaninternal.server.deploy.DeployDocPropertyOptions;
import io.ebeaninternal.server.deploy.generatedproperty.GeneratedProperty;
@@ -1133,4 +1136,20 @@ public class DeployBeanProperty {
boolean isJsonType() {
return mutationDetection != null;
}
@Nullable
public BindMaxLength bindMaxLength() {
if (dbLength == 0) {
return null;
}
switch (dbType) {
case Types.VARCHAR:
case Types.BLOB:
case ExtraDbTypes.JSON:
return desc.bindMaxLength();
default:
return null;
}
}
}
@@ -1,6 +1,5 @@
package io.ebeaninternal.server.expression.platform;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.server.expression.BitwiseOp;
/**
@@ -9,7 +8,7 @@ import io.ebeaninternal.server.expression.BitwiseOp;
abstract class BaseDbExpression implements DbExpressionHandler {
@Override
public void bitwise(SpiExpressionRequest request, String propName, BitwiseOp operator, long flags, String compare, long match) {
public void bitwise(DbExpressionRequest request, String propName, BitwiseOp operator, long flags, String compare, long match) {
final String bitOp = bitOp(operator);
request.append('(').property(propName).append(' ').append(bitOp).append(" ? ").append(compare).append(" ?)");
}
@@ -28,7 +27,7 @@ abstract class BaseDbExpression implements DbExpressionHandler {
/**
* Common alternative where the bitwise operation is a function (specifically bitand is used - H2 and Oracle).
*/
protected void bitwiseFunction(SpiExpressionRequest request, String propName, BitwiseOp operator, String compare) {
protected void bitwiseFunction(DbExpressionRequest request, String propName, BitwiseOp operator, String compare) {
final String funcName = functionName(operator);
request.append(funcName).append('(').property(propName).append(", ?) ").append(compare).append(" ?");
}
@@ -1,6 +1,5 @@
package io.ebeaninternal.server.expression.platform;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.server.expression.Op;
/**
@@ -9,17 +8,17 @@ import io.ebeaninternal.server.expression.Op;
class BasicDbExpression extends BaseDbExpression {
@Override
public void json(SpiExpressionRequest request, String propName, String path, Op operator, Object value) {
public void json(DbExpressionRequest request, String propName, String path, Op operator, Object value) {
throw new RuntimeException("JSON expressions only supported on Postgres and Oracle");
}
@Override
public void arrayContains(SpiExpressionRequest request, String propName, boolean contains, Object... values) {
public void arrayContains(DbExpressionRequest request, String propName, boolean contains, Object... values) {
throw new RuntimeException("ARRAY expressions only supported on Postgres");
}
@Override
public void arrayIsEmpty(SpiExpressionRequest request, String propName, boolean empty) {
public void arrayIsEmpty(DbExpressionRequest request, String propName, boolean empty) {
throw new RuntimeException("ARRAY expressions only supported on Postgres");
}
}
@@ -1,6 +1,5 @@
package io.ebeaninternal.server.expression.platform;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.server.expression.BitwiseOp;
import io.ebeaninternal.server.expression.Op;
@@ -12,22 +11,22 @@ public interface DbExpressionHandler {
/**
* Write the db platform specific json expression.
*/
void json(SpiExpressionRequest request, String propName, String path, Op operator, Object value);
void json(DbExpressionRequest request, String propName, String path, Op operator, Object value);
/**
* Add SQL for ARRAY CONTAINS expression.
*/
void arrayContains(SpiExpressionRequest request, String propName, boolean contains, Object... values);
void arrayContains(DbExpressionRequest request, String propName, boolean contains, Object... values);
/**
* Add SQL for ARRAY IS EMPTY expression.
*/
void arrayIsEmpty(SpiExpressionRequest request, String propName, boolean empty);
void arrayIsEmpty(DbExpressionRequest request, String propName, boolean empty);
/**
* Add the bitwise expression.
*/
void bitwise(SpiExpressionRequest request, String propName, BitwiseOp operator, long flags, String compare, long match);
void bitwise(DbExpressionRequest request, String propName, BitwiseOp operator, long flags, String compare, long match);
/**
* Performs a "CONCAT" operation for that platform.
@@ -0,0 +1,22 @@
package io.ebeaninternal.server.expression.platform;
/**
* Request building the expression sql.
*/
public interface DbExpressionRequest {
/**
* Append to the expression sql without any parsing.
*/
DbExpressionRequest append(String expression);
/**
* Append to the expression sql without any parsing.
*/
DbExpressionRequest append(char c);
/**
* Append to the expression sql with logical property parsing to db columns with logical path prefix.
*/
DbExpressionRequest property(String expression);
}
@@ -1,6 +1,5 @@
package io.ebeaninternal.server.expression.platform;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.server.expression.BitwiseOp;
/**
@@ -9,7 +8,7 @@ import io.ebeaninternal.server.expression.BitwiseOp;
final class H2DbExpression extends BasicDbExpression {
@Override
public void bitwise(SpiExpressionRequest request, String propName, BitwiseOp operator, long flags, String compare, long match) {
public void bitwise(DbExpressionRequest request, String propName, BitwiseOp operator, long flags, String compare, long match) {
final String funcName = functionName(operator);
request.append(funcName).append('(').property(propName).append(", cast(? as long)) ").append(compare).append(" cast(? as long)");
}
@@ -1,6 +1,5 @@
package io.ebeaninternal.server.expression.platform;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.server.expression.BitwiseOp;
import io.ebeaninternal.server.expression.Op;
@@ -10,17 +9,17 @@ import io.ebeaninternal.server.expression.Op;
final class HanaDbExpression extends BaseDbExpression {
@Override
public void bitwise(SpiExpressionRequest request, String propName, BitwiseOp operator, long flags, String compare, long match) {
public void bitwise(DbExpressionRequest request, String propName, BitwiseOp operator, long flags, String compare, long match) {
bitwiseFunction(request, propName, operator, compare);
}
@Override
public void json(SpiExpressionRequest request, String propName, String path, Op operator, Object value) {
public void json(DbExpressionRequest request, String propName, String path, Op operator, Object value) {
request.append("json_value(").property(propName).append(", '$.").append(path).append("')").append(operator.bind());
}
@Override
public void arrayIsEmpty(SpiExpressionRequest request, String propName, boolean empty) {
public void arrayIsEmpty(DbExpressionRequest request, String propName, boolean empty) {
request.append("cardinality(").property(propName).append(')');
if (empty) {
request.append(" = 0");
@@ -41,7 +40,7 @@ final class HanaDbExpression extends BaseDbExpression {
}
@Override
public void arrayContains(SpiExpressionRequest request, String propName, boolean contains, Object... values) {
public void arrayContains(DbExpressionRequest request, String propName, boolean contains, Object... values) {
for (int i = 0; i < values.length; i++) {
if (i > 0) {
request.append(" and ");
@@ -1,6 +1,5 @@
package io.ebeaninternal.server.expression.platform;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.server.expression.Op;
/**
@@ -9,7 +8,7 @@ import io.ebeaninternal.server.expression.Op;
final class MariaDbExpression extends BasicDbExpression {
@Override
public void json(SpiExpressionRequest request, String propName, String path, Op operator, Object value) {
public void json(DbExpressionRequest request, String propName, String path, Op operator, Object value) {
request.append('(').property(propName).append(" ->> '$.").append(path).append("')").append(operator.bind());
}
}
@@ -1,6 +1,5 @@
package io.ebeaninternal.server.expression.platform;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.server.expression.Op;
/**
@@ -9,7 +8,7 @@ import io.ebeaninternal.server.expression.Op;
final class MySqlDbExpression extends BasicDbExpression {
@Override
public void json(SpiExpressionRequest request, String propName, String path, Op operator, Object value) {
public void json(DbExpressionRequest request, String propName, String path, Op operator, Object value) {
request.append('(').property(propName).append(" ->> '$.").append(path).append("')").append(operator.bind());
}
@@ -1,6 +1,5 @@
package io.ebeaninternal.server.expression.platform;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.server.expression.BitwiseOp;
import io.ebeaninternal.server.expression.Op;
@@ -15,7 +14,7 @@ final class OracleDbExpression extends BaseDbExpression {
}
@Override
public void json(SpiExpressionRequest request, String propName, String path, Op operator, Object value) {
public void json(DbExpressionRequest request, String propName, String path, Op operator, Object value) {
if (operator == Op.EXISTS) {
request.append("json_exists(").property(propName).append(", '$.").append(path).append("')");
} else if (operator == Op.NOT_EXISTS) {
@@ -26,17 +25,17 @@ final class OracleDbExpression extends BaseDbExpression {
}
@Override
public void bitwise(SpiExpressionRequest request, String propName, BitwiseOp operator, long flags, String compare, long match) {
public void bitwise(DbExpressionRequest request, String propName, BitwiseOp operator, long flags, String compare, long match) {
bitwiseFunction(request, propName, operator, compare);
}
@Override
public void arrayContains(SpiExpressionRequest request, String propName, boolean contains, Object... values) {
public void arrayContains(DbExpressionRequest request, String propName, boolean contains, Object... values) {
throw new IllegalStateException("ARRAY expressions not supported on Oracle");
}
@Override
public void arrayIsEmpty(SpiExpressionRequest request, String propName, boolean empty) {
public void arrayIsEmpty(DbExpressionRequest request, String propName, boolean empty) {
throw new IllegalStateException("ARRAY expressions not supported on Oracle");
}
}
@@ -1,6 +1,5 @@
package io.ebeaninternal.server.expression.platform;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.server.expression.Op;
/**
@@ -14,7 +13,7 @@ final class PostgresDbExpression extends BaseDbExpression {
}
@Override
public void json(SpiExpressionRequest request, String propName, String path, Op operator, Object value) {
public void json(DbExpressionRequest request, String propName, String path, Op operator, Object value) {
String[] paths = path.split("\\.");
if (paths.length == 1) {
// (t0.content ->> 'title') = 'Some value'
@@ -34,7 +33,7 @@ final class PostgresDbExpression extends BaseDbExpression {
}
@Override
public void arrayContains(SpiExpressionRequest request, String propName, boolean contains, Object... values) {
public void arrayContains(DbExpressionRequest request, String propName, boolean contains, Object... values) {
if (!contains) {
request.append("not (");
}
@@ -49,7 +48,7 @@ final class PostgresDbExpression extends BaseDbExpression {
}
@Override
public void arrayIsEmpty(SpiExpressionRequest request, String propName, boolean empty) {
public void arrayIsEmpty(DbExpressionRequest request, String propName, boolean empty) {
request.append("coalesce(cardinality(").property(propName).append("),0)");
if (empty) {
request.append(" = 0");
@@ -1,6 +1,5 @@
package io.ebeaninternal.server.expression.platform;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.server.expression.Op;
/**
@@ -9,19 +8,19 @@ import io.ebeaninternal.server.expression.Op;
final class SqlServerDbExpression extends BaseDbExpression {
@Override
public void json(final SpiExpressionRequest request, final String propName,
public void json(final DbExpressionRequest request, final String propName,
final String path, final Op operator, final Object value) {
request.append("json_value(").property(propName).append(", '$.").append(path).append("')").append(operator.bind());
}
@Override
public void arrayContains(final SpiExpressionRequest request, final String propName,
public void arrayContains(final DbExpressionRequest request, final String propName,
final boolean contains, final Object... values) {
throw new RuntimeException("ARRAY expressions not supported on Microsoft SQL Server");
}
@Override
public void arrayIsEmpty(final SpiExpressionRequest request, final String propName, final boolean empty) {
public void arrayIsEmpty(final DbExpressionRequest request, final String propName, final boolean empty) {
throw new RuntimeException("ARRAY expressions not supported on Microsoft SQL Server");
}
}
@@ -402,7 +402,13 @@ public final class DJsonContext implements SpiJsonContext {
private WriteJson createWriteJson(JsonGenerator gen, JsonWriteOptions options) {
FetchPath pathProps = (options == null) ? null : options.getPathProperties();
Map<String, JsonWriteBeanVisitor<?>> visitors = (options == null) ? null : options.getVisitorMap();
return new WriteJson(server, gen, pathProps, visitors, determineObjectMapper(options), determineInclude(options));
return new WriteJson(server,
gen,
pathProps,
visitors,
determineObjectMapper(options),
determineInclude(options),
options == null || options.isIncludeLoadedImplicit());
}
private <T> void toJsonFromCollection(Collection<T> collection, String key, JsonGenerator gen, JsonWriteOptions options) throws IOException {
@@ -490,4 +496,5 @@ public final class DJsonContext implements SpiJsonContext {
JsonConfig.Include include = options.getInclude();
return (include != null) ? include : defaultInclude;
}
}
@@ -31,12 +31,15 @@ public final class WriteJson implements SpiJsonWriter {
private final ArrayStack<Object> parentBeans;
private final Object objectMapper;
private final JsonConfig.Include include;
private final boolean includeLoadedImplicit;
/**
* Construct for full bean use (normal).
*/
public WriteJson(SpiEbeanServer server, JsonGenerator generator, FetchPath fetchPath,
Map<String, JsonWriteBeanVisitor<?>> visitors, Object objectMapper, JsonConfig.Include include) {
Map<String, JsonWriteBeanVisitor<?>> visitors, Object objectMapper, JsonConfig.Include include,
boolean includeLoadedImplicit) {
this.server = server;
this.generator = generator;
@@ -44,6 +47,7 @@ public final class WriteJson implements SpiJsonWriter {
this.visitors = visitors;
this.objectMapper = objectMapper;
this.include = include;
this.includeLoadedImplicit = includeLoadedImplicit;
this.parentBeans = new ArrayStack<>();
this.pathStack = new PathStack();
}
@@ -54,6 +58,7 @@ public final class WriteJson implements SpiJsonWriter {
public WriteJson(JsonGenerator generator, JsonConfig.Include include) {
this.generator = generator;
this.include = include;
this.includeLoadedImplicit = true;
this.visitors = null;
this.server = null;
this.fetchPath = null;
@@ -443,7 +448,7 @@ public final class WriteJson implements SpiJsonWriter {
currentIncludeProps = null;
}
}
return new WriteBean(desc, explicitAllProps, currentIncludeProps, bean, visitor);
return new WriteBean(desc, explicitAllProps, includeLoadedImplicit, currentIncludeProps, bean, visitor);
}
@Override
@@ -477,6 +482,7 @@ public final class WriteJson implements SpiJsonWriter {
public static class WriteBean {
final boolean explicitAllProps;
final boolean includeLoadedImplicit;
final Set<String> currentIncludeProps;
final BeanDescriptor<?> desc;
final EntityBean currentBean;
@@ -485,14 +491,15 @@ public final class WriteJson implements SpiJsonWriter {
final JsonWriteBeanVisitor visitor;
WriteBean(BeanDescriptor<?> desc, EntityBean currentBean, JsonWriteBeanVisitor<?> visitor) {
this(desc, false, null, currentBean, visitor);
this(desc, false, true, null, currentBean, visitor);
}
WriteBean(BeanDescriptor<?> desc, boolean explicitAllProps, Set<String> currentIncludeProps, EntityBean currentBean, JsonWriteBeanVisitor<?> visitor) {
WriteBean(BeanDescriptor<?> desc, boolean explicitAllProps, boolean includeLoadedImplicit, Set<String> currentIncludeProps, EntityBean currentBean, JsonWriteBeanVisitor<?> visitor) {
super();
this.desc = desc;
this.currentBean = currentBean;
this.explicitAllProps = explicitAllProps;
this.includeLoadedImplicit = includeLoadedImplicit;
this.currentIncludeProps = currentIncludeProps;
this.visitor = visitor;
}
@@ -507,9 +514,11 @@ public final class WriteJson implements SpiJsonWriter {
if (currentIncludeProps != null) {
// explicitly controlled by pathProperties
return currentIncludeProps.contains(prop.name());
} else {
} else if (includeLoadedImplicit){
// include only loaded properties
return currentBean._ebean_getIntercept().isLoadedProperty(prop.propertyIndex());
} else {
return prop.isId();
}
}
@@ -74,6 +74,9 @@ public final class CQueryEngine {
if (request.logSql()) {
request.logSql("{0}; --bind({1}) --micros({2}) --rows({3})", query.generatedSql(), query.bindLog(), query.micros(), rows);
}
if (rows > 0) {
request.clearContext();
}
return rows;
} catch (SQLException e) {
throw translate(request, query.bindLog(), query.generatedSql(), e);
@@ -61,6 +61,7 @@ final class CQueryUpdate implements SpiProfileTransactionEvent, CancelableQuery
/**
* Execute the update or delete statement returning the row count.
*/
@SuppressWarnings("resource")
public int execute() throws SQLException {
long startNano = System.nanoTime();
try {
@@ -109,6 +110,7 @@ final class CQueryUpdate implements SpiProfileTransactionEvent, CancelableQuery
pstmt = null;
}
@SuppressWarnings("resource")
@Override
public void profile() {
transaction()
@@ -33,7 +33,7 @@ public interface STreeProperty extends ScalarDataReader<Object> {
/**
* Returns true, if this is a lob property from db-perspective.
*/
boolean isDbLob();
boolean isLobForPlatform();
/**
* Return true if the property is an embedded type.
@@ -48,7 +48,7 @@ public final class SqlTreeBuilder {
private final SpiQuery.TemporalMode temporalMode;
private SqlTreeNode rootNode;
private boolean sqlDistinct;
private final boolean distinctNoLobs;
private final boolean platformDistinctNoLobs;
private final SqlTreeCommon common;
/**
@@ -63,7 +63,7 @@ public final class SqlTreeBuilder {
this.query = null;
this.subQuery = false;
this.distinctOnPlatform = false;
this.distinctNoLobs = false;
this.platformDistinctNoLobs = false;
this.queryDetail = queryDetail;
this.predicates = predicates;
this.temporalMode = SpiQuery.TemporalMode.CURRENT;
@@ -98,7 +98,7 @@ public final class SqlTreeBuilder {
this.predicates = predicates;
this.alias = new SqlTreeAlias(request.baseTableAlias(), temporalMode);
this.distinctOnPlatform = builder.isPlatformDistinctOn();
this.distinctNoLobs = builder.isPlatformDistinctNoLobs();
this.platformDistinctNoLobs = builder.isPlatformDistinctNoLobs();
String fromForUpdate = builder.fromForUpdate(query);
CQueryHistorySupport historySupport = builder.historySupport(query);
CQueryDraftSupport draftSupport = builder.draftSupport(query);
@@ -269,8 +269,8 @@ public final class SqlTreeBuilder {
if (joinList != null) {
joinList.add(selectNode);
}
if (sqlDistinct && distinctNoLobs) {
selectNode.unselectLobs();
if (sqlDistinct && platformDistinctNoLobs) {
selectNode.unselectLobsForPlatform();
}
return selectNode;
}
@@ -82,6 +82,6 @@ interface SqlTreeNode {
/**
* Unselect lobs (for distinct queries on DB2 and Oracle).
*/
default void unselectLobs() {
default void unselectLobsForPlatform() {
}
}
@@ -379,16 +379,16 @@ class SqlTreeNodeBean implements SqlTreeNode {
@Override
public void unselectLobs() {
public void unselectLobsForPlatform() {
if (children != null) {
for (SqlTreeNode child : children) {
child.unselectLobs();
child.unselectLobsForPlatform();
}
}
if (hasLob()) {
List<STreeProperty> lst = new ArrayList<>();
for (STreeProperty prop : properties) {
if (!prop.isDbLob()) {
if (!prop.isLobForPlatform()) {
lst.add(prop);
}
}
@@ -399,7 +399,7 @@ class SqlTreeNodeBean implements SqlTreeNode {
private boolean hasLob() {
for (STreeProperty prop : properties) {
if (prop.isDbLob()) {
if (prop.isLobForPlatform()) {
return true;
}
}
@@ -2,12 +2,13 @@ package io.ebeaninternal.server.util;
import java.util.ArrayList;
import java.util.EmptyStackException;
import java.util.Iterator;
import java.util.List;
/**
* Stack based on ArrayList.
*/
public class ArrayStack<E> {
public class ArrayStack<E> implements Iterable<E> {
private final List<E> list;
@@ -89,4 +90,9 @@ public class ArrayStack<E> {
public boolean contains(E o) {
return list.contains(o);
}
@Override
public Iterator<E> iterator() {
return list.iterator();
}
}
+4 -4
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</parent>
<name>ebean ddl generation</name>
@@ -28,14 +28,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
<scope>provided</scope>
</dependency>
@@ -65,7 +65,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-all</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
<scope>test</scope>
</dependency>
+2 -2
View File
@@ -3,7 +3,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -14,7 +14,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
<scope>provided</scope>
</dependency>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</parent>
<name>ebean postgis types</name>
@@ -19,14 +19,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<!-- provided scope -->
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
<scope>provided</scope>
</dependency>
@@ -47,7 +47,7 @@
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.6.0</version>
<version>42.7.2</version>
<scope>provided</scope>
</dependency>
@@ -62,7 +62,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
<scope>test</scope>
</dependency>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</parent>
<name>ebean querybean</name>
@@ -17,7 +17,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
<scope>provided</scope>
</dependency>
@@ -63,14 +63,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
<scope>test</scope>
</dependency>
@@ -84,7 +84,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
<scope>provided</scope>
</dependency>
@@ -108,6 +108,18 @@ public abstract class TQAssocBean<T, R, QB> extends TQAssoc<T, R> {
return fetchWithProperties(FETCH_DEFAULT, properties);
}
/**
* Fetch this association with config for the type of fetch and the specified properties.
*
* @param config Fetch configuration to define the type of fetch to use
* @param properties The properties to fetch
*/
@SafeVarargs @SuppressWarnings("varargs")
public final R fetch(FetchConfig config, TQProperty<QB,?>... properties) {
return fetchWithProperties(config, properties);
}
/**
* Eagerly fetch this association using a 'query join' loading the specified properties.
*/
@@ -0,0 +1,14 @@
package org.example.domain;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Version;
@Entity
public class Alias {
@Id
long id;
@Version
long version;
}
@@ -1,6 +1,7 @@
package org.querytest;
import io.ebean.DB;
import io.ebean.FetchConfig;
import io.ebean.FetchGroup;
import io.ebean.Query;
import io.ebean.test.LoggedSql;
@@ -8,6 +9,7 @@ import org.example.domain.Customer;
import org.example.domain.Order;
import org.example.domain.OrderDetail;
import org.example.domain.otherpackage.PhoneNumber;
import org.example.domain.query.QContact;
import org.example.domain.query.QCustomer;
import org.example.domain.query.QOrder;
import org.example.domain.query.QOrderDetail;
@@ -26,10 +28,17 @@ public class QOrderTest {
private static final QOrder or = QOrder.alias();
private static final QContact co = QContact.alias();
private static final FetchGroup<Customer> fgC = QCustomer.forFetchGroup()
.select(cu.name, cu.phoneNumber)
.buildFetchGroup();
private static final FetchGroup<Customer> fgCustomerWithContacts = QCustomer.forFetchGroup()
.select(cu.name, cu.phoneNumber)
.contacts.fetch(FetchConfig.ofQuery(1000), co.firstName, co.lastName, co.email)
.buildFetchGroup();
private static final FetchGroup<Order> fgNested1 = QOrder.forFetchGroup()
.select(or.status, or.shipDate)
.customer.fetch(fgC)
@@ -70,6 +79,20 @@ public class QOrderTest {
DB.delete(customer);
}
@Test
void fetchQueryWithBatch() {
LoggedSql.start();
new QCustomer()
.select(fgCustomerWithContacts)
.findList();
final List<String> sql = LoggedSql.stop();
assertThat(sql).hasSize(2);
assertThat(sql.get(0)).contains("select t0.id, t0.name, t0.phone_number from be_customer t0");
assertThat(sql.get(1)).contains("select t0.customer_id, t0.id, t0.first_name, t0.last_name, t0.email from be_contact t0 where");
}
@Test
public void fetchCache() {
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</parent>
<artifactId>ebean-redis</artifactId>
@@ -22,28 +22,28 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
<scope>test</scope>
</dependency>
@@ -57,7 +57,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
<scope>provided</scope>
</dependency>
@@ -1,12 +1,9 @@
package org.integration;
import io.ebean.DatabaseBuilder;
import io.ebean.redis.DuelCache;
import org.domain.Person;
import io.ebean.DB;
import io.ebean.Database;
import io.ebean.DatabaseFactory;
import io.ebean.config.DatabaseConfig;
import io.ebean.redis.DuelCache;
import org.domain.Person;
import org.domain.query.QPerson;
import org.junit.jupiter.api.Test;
@@ -14,21 +11,21 @@ import javax.sql.DataSource;
import static org.assertj.core.api.Assertions.assertThat;
public class ClusterTest {
class ClusterTest {
private Database createOther(DataSource dataSource) {
DatabaseBuilder config = new DatabaseConfig();
config.setDataSource(dataSource);
config.loadFromProperties();
config.setDefaultServer(false);
config.setName("other");
config.setDdlGenerate(false);
config.setDdlRun(false);
return DatabaseFactory.create(config);
return Database.builder()
.dataSource(dataSource)
.loadFromProperties()
.defaultDatabase(false)
.name("other")
.ddlGenerate(false)
.ddlRun(false)
.build();
}
@Test
public void testBothNear() throws InterruptedException {
void testBothNear() throws InterruptedException {
// ensure the default server exists first
final Database db = DB.getDefault();
Database other = createOther(db.pluginApi().dataSource());
@@ -61,7 +58,7 @@ public class ClusterTest {
}
@Test
public void test() throws InterruptedException {
void test() throws InterruptedException {
// ensure the default server exists first
final Database db = DB.getDefault();
Database other = createOther(db.pluginApi().dataSource());
@@ -116,6 +113,6 @@ public class ClusterTest {
}
private void allowAsyncMessaging() throws InterruptedException {
Thread.sleep(100);
Thread.sleep(200);
}
}
+3 -3
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</parent>
<artifactId>ebean-spring-txn</artifactId>
@@ -28,7 +28,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
<scope>provided</scope>
</dependency>
@@ -77,7 +77,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
<scope>test</scope>
</dependency>
@@ -2,15 +2,19 @@ package org.example;
import io.ebean.DB;
import io.ebean.Transaction;
import io.ebean.test.PersistenceContextAccess;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.transaction.annotation.Transactional;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.in;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -42,6 +46,24 @@ public class EbeanSpringModuleTest {
super();
}
@Transactional
@Rollback
@Test
public void testWithRollback() {
// setup
User user = new User();
user.setName("rollback1");
DB.save(user);
// this loads the user into the [transaction scoped] persistence context
User found = DB.find(User.class, user.getOid());
found.setName("mutated");
PersistenceContextAccess.clear();
userService.insideTestRollback(user.getOid());
}
/**
* Test app.
*/
@@ -16,4 +16,6 @@ public interface UserService {
void batchInsert();
void requiresNew();
void insideTestRollback(long oid);
}
@@ -12,6 +12,8 @@ import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
/**
* The Class UserServiceImpl.
*
@@ -28,6 +30,13 @@ public class UserServiceImpl implements UserService, ApplicationContextAware {
@Autowired
private Database ebeanServer;
@Override
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Throwable.class)
public void insideTestRollback(long oid) {
User found = ebeanServer.find(User.class, oid);
assertThat(found.getName()).isEqualTo("rollback1");
}
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Throwable.class)
public void save(User user) {
ebeanServer.save(user);
+12 -12
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</parent>
<name>ebean test</name>
@@ -12,8 +12,8 @@
<artifactId>ebean-test</artifactId>
<properties>
<bytebuddy.version>1.14.9</bytebuddy.version>
<assertj.version>3.24.2</assertj.version>
<bytebuddy.version>1.14.12</bytebuddy.version>
<assertj.version>3.25.3</assertj.version>
</properties>
<dependencies>
@@ -33,20 +33,20 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
</dependency>
<dependency>
@@ -135,28 +135,28 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-joda-time</artifactId>
<version>13.24.0</version>
<version>14.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-jackson-jsonnode</artifactId>
<version>13.24.0</version>
<version>14.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-jackson-mapper</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-all</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.1</version>
<scope>test</scope>
</dependency>
@@ -213,7 +213,7 @@
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.6.0</version>
<version>42.7.2</version>
<exclusions>
<exclusion>
<groupId>org.checkerframework</groupId>
@@ -293,7 +293,7 @@
<dependency>
<groupId>io.avaje</groupId>
<artifactId>junit</artifactId>
<version>1.3</version>
<version>1.4</version>
<scope>provided</scope>
</dependency>
@@ -0,0 +1,59 @@
package io.ebean.test;
import io.ebean.Transaction;
import io.ebean.bean.PersistenceContext;
import io.ebeaninternal.api.SpiTransaction;
/**
* Provides tests access to the persistence context.
* <p>
* Expected to be used with tests that use Spring test {@code @Rollback} {@code @Transactional}.
* These tests have an outer transaction that will rollback. The issue is that test setup code
* is now running in the SAME TRANSACTION as the code under test (main code we are testing) and
* that the Ebean Persistence Context is transaction scoped - so the test setup code can load
* entities into the ebean persistence context during the test setup phase - we SHOULD clear the
* persistence context AFTER the setup phase of the test and BEFORE we run the code under test.
*
* <pre>{@code
*
* @Test
* @Transactional // spring transactional
* @Rollback // spring test rollback
* void myTestWithSpringRollback() {
*
* // Test Setup: this MIGHT load entities into the persistence context
* performTestSetup();
*
* // clear out the persistence context
* PersistenceContextAccess.clear();
*
* // Act
* performActionsWeAreTestingHere();
*
* // Assert
* assertThat(...)
*
* }
*
* }</pre>
*/
public class PersistenceContextAccess {
/**
* Clear the persistence context of the current transaction.
* <p>
* This is expected to be called after test setup phase and before
* the test executes the code we are looking to test - so
* AFTER "setup" and BEFORE "act".
*/
public static void clear() {
Transaction current = Transaction.current();
if (current != null) {
SpiTransaction spiTransaction = (SpiTransaction) current;
PersistenceContext pc = spiTransaction.persistenceContext();
if (pc != null) {
pc.clear();
}
}
}
}
@@ -1,5 +1,6 @@
package io.ebean.xtest.base;
import io.ebean.Transaction;
import io.ebean.xtest.BaseTestCase;
import io.ebean.DB;
import org.junit.jupiter.api.AfterEach;
@@ -18,15 +19,17 @@ import org.tests.model.basic.ResetBasicData;
*/
public abstract class TransactionalTestCase extends BaseTestCase {
private Transaction transaction;
@BeforeEach
public void startTransaction() {
ResetBasicData.reset();
DB.beginTransaction();
transaction = DB.beginTransaction();
}
@AfterEach
public void endTransaction() {
DB.rollbackTransaction();
DB.endTransaction();
transaction.rollback();
transaction.end();
}
}
@@ -12,12 +12,20 @@ class ContainerConfigTest {
@Test
void loadFromProperties() {
ContainerConfig containerConfig = new ContainerConfig();
Properties p = new Properties();
p.setProperty("ebean.cluster.active", "true");
p.setProperty("ebean.cluster.serviceName", "a");
p.setProperty("ebean.cluster.namespace", "b");
p.setProperty("ebean.cluster.podName", "c");
p.setProperty("ebean.cluster.port", "42");
assertThat(containerConfig.isActive()).isFalse();
assertThat(containerConfig.getServiceName()).isNull();
assertThat(containerConfig.getNamespace()).isNull();
assertThat(containerConfig.getPodName()).isNull();
assertThat(containerConfig.getPort()).isEqualTo(0);
ContainerConfig containerConfig = new ContainerConfig();
containerConfig.loadFromProperties(p);
assertThat(containerConfig.isActive()).isTrue();
assertThat(containerConfig.getServiceName()).isEqualTo("a");
assertThat(containerConfig.getNamespace()).isEqualTo("b");
assertThat(containerConfig.getPodName()).isEqualTo("c");
assertThat(containerConfig.getPort()).isEqualTo(42);
}
}
@@ -578,14 +578,6 @@ public class TDSpiEbeanServer extends TDSpiServer implements SpiEbeanServer {
public void flush() {
}
@Override
public void commitTransaction() {
}
@Override
public void rollbackTransaction() {
}
@Override
public void endTransaction() {
}
@@ -222,21 +222,6 @@ public class TDSpiServer implements SpiServer {
}
@Override
public void commitTransaction() {
}
@Override
public void rollbackTransaction() {
}
@Override
public void endTransaction() {
}
@Override
public void refresh(Object bean) {
@@ -43,7 +43,7 @@ public class WriteJsonDirtyTest {
JsonFactory jsonFactory = new JsonFactory();
JsonGenerator generator = jsonFactory.createGenerator(writer);
WriteJson writeJson = new WriteJson(server, generator, null, null, null, null);
WriteJson writeJson = new WriteJson(server, generator, null, null, null, null, true);
descriptor.jsonWriteDirty(writeJson, entityBean, dirtyProperties);
generator.flush();
@@ -79,9 +79,7 @@ public class DefaultTransactionThreadLocalTest extends BaseTestCase {
@ForPlatform({Platform.H2})
@Test
public void end_withoutActiveTransaction_isFine() {
assertNull(DB.currentTransaction());
DB.endTransaction();
}
@ForPlatform({Platform.H2})
@@ -1,5 +1,6 @@
package org.tests.basic;
import io.ebean.Transaction;
import io.ebean.xtest.BaseTestCase;
import io.ebean.BeanState;
import io.ebean.DB;
@@ -36,13 +37,11 @@ public class TestDynamicUpdate extends BaseTestCase {
server.save(b2);
server.beginTransaction();
try {
try (Transaction txn = server.beginTransaction()) {
EMain b3 = server.find(EMain.class, b.getId());
assertEquals("ABC", b3.getEmbeddable().getDescription());
} finally {
server.endTransaction();
}
EMain b4 = server.find(EMain.class, b.getId());
b4.setName("bbb");
b4.getEmbeddable().setDescription("123");
@@ -1,5 +1,6 @@
package org.tests.basic;
import io.ebean.Transaction;
import io.ebean.xtest.BaseTestCase;
import io.ebean.DB;
import org.junit.jupiter.api.Test;
@@ -17,8 +18,7 @@ public class TestInheritRef extends BaseTestCase {
@Test
public void testAssocOne() {
DB.beginTransaction();
try {
try (Transaction txn = DB.beginTransaction()) {
DB.createUpdate(Vehicle.class, "delete from vehicle");
Car c = new Car();
@@ -52,9 +52,6 @@ public class TestInheritRef extends BaseTestCase {
assertEquals(1, found);
assertTrue(foundTruck.getCapacity() == 20D);
} finally {
DB.rollbackTransaction();
}
}
}
@@ -0,0 +1,101 @@
package org.tests.basic;
import io.ebean.DB;
import io.ebean.DataIntegrityException;
import io.ebean.xtest.BaseTestCase;
import org.junit.jupiter.api.Test;
import org.tests.model.json.EBasicJsonList;
import org.tests.model.json.EBasicJsonMap;
import org.tests.model.types.SomeFileBean;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
/**
* @author Roland Praml, FOCONIS AG
*/
public class TestLength extends BaseTestCase {
@Test
void testFileSize() throws IOException {
File f1 = File.createTempFile("testfile", "tmp");
byte[] buf = new byte[1024];
try (FileOutputStream fos = new FileOutputStream(f1)) {
for (int i = 0; i < 100; i++) {
fos.write(buf);
}
}
SomeFileBean sfb1 = new SomeFileBean();
sfb1.setContent(f1);
DB.save(sfb1);
try (FileOutputStream fos = new FileOutputStream(f1)) {
for (int i = 0; i < 101; i++) {
fos.write(buf);
}
}
SomeFileBean sfb2 = new SomeFileBean();
sfb2.setContent(f1);
assertThatThrownBy(() -> DB.save(sfb2)).isInstanceOf(DataIntegrityException.class);
}
/**
* The property 'EBasicJsonMap.content' is annotated with @DbJson(length=5000). So we assume, that we cannot save Json-objects
* where the serialized form exceed that limit and we would expect an error on save.
* The length check works for platforms like h2, as H2 uses a 'varchar(5000)'. So it is impossible to save such long jsons,
* but it won't work for SqlServer, as here 'nvarchar(max)' is used. No validation happens at DB level and you might get very
* large Json objects in your database. This mostly happens unintentionally (programming error, misconfiguration)
* So they are in the database and they cannot be accessed by ebean any more, because there are new limits in Jackson:
* - Max 5 Meg per string in 2.15.0
* - Max 20 Meg per string in 2.15.1
* see https://github.com/FasterXML/jackson-core/issues/1014
*/
@Test
void testLongString() {
// s is so big, that it could not be deserialized by jackson
String s = new String(new char[20_000_001]).replace('\0', 'x');
EBasicJsonMap bean = new EBasicJsonMap();
bean.setName("b1");
bean.setContent(Map.of("string", s));
assertThatThrownBy(() -> {
// we expect, that we can NOT save the bean, this is ensured by the bind validator.
DB.save(bean);
}).isInstanceOf(DataIntegrityException.class);
}
/**
* Tests the UTF8 validation.
*/
@Test
void testUtf8() {
String s = new String(new char[40]).replace('\0', '€');
EBasicJsonList bean = new EBasicJsonList();
bean.setName("b1");
bean.setTags(List.of(s));
if (isDb2() || isOracle()) {
// by default, DB2 && oracle uses bytes in varchar, so an '€' symbol needs 3 bytes
assertThatThrownBy(() -> {
// we expect, that we can NOT save the bean, this is ensured by the bind validator.
DB.save(bean);
}).isInstanceOf(DataIntegrityException.class);
} else {
DB.save(bean);
}
}
}
@@ -47,10 +47,9 @@ public class TestPersistenceContext extends BaseTestCase {
// implicit transaction with its own persistence context
Order oBefore = DB.find(Order.class, 1);
// start a persistence context
DB.beginTransaction();
Order order;
try {
try (Transaction txn = DB.beginTransaction()) {
order = DB.find(Order.class, 1);
// not the same instance ...as a different persistence context
assertNotSame(order, oBefore);
@@ -63,9 +62,6 @@ public class TestPersistenceContext extends BaseTestCase {
// all the same instance
assertSame(order, o2);
assertSame(order, o3);
} finally {
DB.endTransaction();
}
// implicit transaction with its own persistence context
@@ -74,8 +70,7 @@ public class TestPersistenceContext extends BaseTestCase {
assertNotSame(oAfter, order);
// start a persistence context
DB.beginTransaction();
try {
try (Transaction txn = DB.beginTransaction()) {
Order testOrder = ResetBasicData.createOrderCustAndOrder("testPC");
Integer id = testOrder.getCustomer().getId();
Integer orderId = testOrder.getId();
@@ -94,9 +89,6 @@ public class TestPersistenceContext extends BaseTestCase {
assertEquals(customer.getId(), customer2.getId());
assertSame(customer, customer2);
} finally {
DB.endTransaction();
}
}
@@ -1,5 +1,6 @@
package org.tests.cache;
import io.ebean.Transaction;
import io.ebean.xtest.BaseTestCase;
import io.ebean.DB;
import org.junit.jupiter.api.Test;
@@ -26,8 +27,7 @@ public class TestCacheInterceptSaveWhenLazyLoaded extends BaseTestCase {
order.setCustomer(customer);
DB.save(order);
DB.beginTransaction();
try {
try (Transaction txn = DB.beginTransaction()) {
Order foundOrder = DB.find(Order.class)
.where().eq("id", order.getId())
@@ -47,9 +47,6 @@ public class TestCacheInterceptSaveWhenLazyLoaded extends BaseTestCase {
assertSame(foundOrder, order1);
assertTrue(DB.beanState(foundOrder).isDirty());
} finally {
DB.endTransaction();
}
// cleanup
@@ -1,6 +1,7 @@
package org.tests.genkey;
import io.ebean.DB;
import io.ebean.Transaction;
import org.junit.jupiter.api.Test;
import org.tests.model.basic.TOne;
@@ -19,12 +20,10 @@ public class TestGeneratedKeys {
c1.setName("Two");
c1.setDescription("Test Gen Key Two");
DB.beginTransaction();
try {
try (Transaction txn = DB.beginTransaction()) {
DB.save(c);
DB.save(c1);
} finally {
DB.commitTransaction();
txn.commit();
}
Integer id = c.getId();
assertNotNull(id);
@@ -1,9 +1,6 @@
package org.tests.insert;
import io.ebean.DB;
import io.ebean.Database;
import io.ebean.InsertOptions;
import io.ebean.Transaction;
import io.ebean.*;
import io.ebean.annotation.Platform;
import io.ebean.test.LoggedSql;
import io.ebean.xtest.BaseTestCase;
@@ -11,6 +8,10 @@ import io.ebean.xtest.ForPlatform;
import org.junit.jupiter.api.Test;
import org.tests.update.EPersonOnline;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import static io.ebean.InsertOptions.ON_CONFLICT_NOTHING;
@@ -288,6 +289,119 @@ class TestInsertOnConflict extends BaseTestCase {
assertThat(list.get(0).getWhenUpdated()).isEqualTo(bean.getWhenUpdated());
}
@ForPlatform({Platform.POSTGRES, Platform.YUGABYTE})
@Test
void updateQueryReturning() throws SQLException {
Database db = DB.getDefault();
db.truncate(EPersonOnline.class);
var bean1 = newBean("a1@bee.com");
var bean2 = newBean("a2@cee.com");
var bean3 = newBean("a3@bee.com");
db.saveAll(bean1, bean2, bean3);
String sql = "update e_person_online set email = concat('x',email) where email like ? returning id, email, online_status";
try (Transaction txn = db.createTransaction()) {
Connection connection = txn.connection();
try (PreparedStatement pstmt = connection.prepareStatement(sql)) {
pstmt.setString(1, "%bee.com");
try (ResultSet resultSet = pstmt.executeQuery()) {
while (resultSet.next()) {
long id = resultSet.getLong(1);
String email = resultSet.getString(2);
boolean status = resultSet.getBoolean(3);
// do something with the id, email and status
assertThat(id).isGreaterThan(0);
assertThat(email).startsWith("x");
assertThat(status).isTrue();
}
}
}
txn.commit();
}
try (Transaction txn = db.beginTransaction()) {
List<SqlRow> sqlRowList = DB.sqlQuery(sql)
.setParameter("%bee.com")
.findList();
assertThat(sqlRowList).hasSize(2);
assertThat(sqlRowList.get(0).getString("email")).startsWith("xx");
txn.addModification("e_person_online", false, true, false);
txn.commit();
}
try (Transaction txn = db.beginTransaction()) {
List<ReturnDto> dtoList = db.findDto(ReturnDto.class, sql)
.setParameter("%bee.com")
.findList();
assertThat(dtoList).hasSize(2);
assertThat(dtoList.get(0).email).startsWith("xxx");
txn.addModification("e_person_online", false, true, false);
txn.commit();
}
try (Transaction txn = db.beginTransaction()) {
List<ReturnDto2> dtoList2 = db.findDto(ReturnDto2.class, sql)
.setParameter("%bee.com")
.findList();
assertThat(dtoList2).hasSize(2);
assertThat(dtoList2.get(0).email).startsWith("xxxx");
assertThat(dtoList2.get(0).id).isGreaterThan(0);
txn.addModification("e_person_online", false, true, false);
txn.commit();
}
}
public static class ReturnDto {
private final long id;
private final String email;
private final boolean onlineStatus;
public ReturnDto(long id, String email, boolean onlineStatus) {
this.id = id;
this.email = email;
this.onlineStatus = onlineStatus;
}
}
public static class ReturnDto2 {
private long id;
private String email;
private boolean onlineStatus;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public boolean isOnlineStatus() {
return onlineStatus;
}
public void setOnlineStatus(boolean onlineStatus) {
this.onlineStatus = onlineStatus;
}
}
private static EPersonOnline newBean(String email) {
EPersonOnline bean = new EPersonOnline();
bean.setEmail(email);
@@ -35,11 +35,9 @@ public class TestPersistCascade extends BaseTestCase {
assertThat(sql.get(23)).contains("insert into pcf_city");
assertSqlBind(sql, 24, 26);
assertThat(sql.get(28)).contains("insert into pcf_event");
assertSqlBind(sql, 29, 48);
assertThat(sql.get(50)).contains("insert into pcf_event");
assertSqlBind(sql, 51, 70);
assertThat(sql.get(72)).contains("insert into pcf_event");
assertSqlBind(sql, 73, 87);
assertSqlBind(sql, 29, 128);
assertThat(sql.get(130)).contains("insert into pcf_event");
assertSqlBind(sql, 131, 150);
}
country.deletePermanent();
@@ -0,0 +1,52 @@
package org.tests.json;
import io.ebean.DB;
import io.ebean.DataIntegrityException;
import org.assertj.core.api.SoftAssertions;
import org.junit.jupiter.api.Test;
import org.tests.model.json.EBasicJsonMap;
import java.util.Map;
class TestDbJsonLength {
/**
* The property 'EBasicJsonMap.content' is annotated with @DbJson(length=5000). So we assume, that we cannot save Json-objects
* where the serialized form exceed that limit and we would expect an error on save.
* The length check works for platforms like h2, as H2 uses a 'varchar(5000)'. So it is impossible to save such long jsons,
* but it won't work for SqlServer, as here 'nvarchar(max)' is used. No validation happens at DB level and you might get very
* large Json objects in your database. This mostly happens unintentionally (programming error, misconfiguration)
* So they are in the database and they cannot be accessed by ebean any more, because there are new limits in Jackson:
* - Max 5 Meg per string in 2.15.0
* - Max 20 Meg per string in 2.15.1
* see https://github.com/FasterXML/jackson-core/issues/1014
*/
@Test
void testLongString() {
// s is so big, that it could not be deserialized by jackson
String s = new String(new char[20_000_001]).replace('\0', 'x');
EBasicJsonMap bean = new EBasicJsonMap();
bean.setName("b1");
bean.setContent(Map.of("string", s));
SoftAssertions softly = new SoftAssertions();
softly.assertThatThrownBy(() -> {
DB.save(bean);
}).isInstanceOf(DataIntegrityException.class);
if (bean.getId() != null) {
// we expect, that we could NOT save the bean, but this is not true for sqlServer.
// we will get a javax.persistence.PersistenceException: Error loading on org.tests.model.json.EBasicJsonMap.content
// when we try to load the bean back from DB
DB.find(EBasicJsonMap.class, bean.getId());
}
softly.assertAll();
}
}

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