Compare commits

...
70 Commits
Author SHA1 Message Date
Rob Bygrave ab45ad34e0 Version 14.0.2 2024-03-21 22:07:12 +13:00
Rob Bygrave 24b514f851 Bump ebean-agent, no effective change 2024-03-21 21:55:02 +13:00
Rob BygraveandGitHub 582fec7ce4 For #3363 disable flushOnQuery before BeanPersistAdapter post-processors (#3367) 2024-03-21 21:51:10 +13:00
Rob BygraveandGitHub 0b11c541c8 fix: #3142 Cascading a OneToMany, set the relationship when the child isn't new or dirty (#3366)
That is, previously the relationship back from the child to the parent was being updated when the child bean was new or dirty BUT NOT in the case when the child bean was loaded and unchanged.

This fix includes that case updating the ManyToOne side of the relationship on the child when the save is cascaded.
2024-03-21 00:14:54 +13:00
Rob BygraveandGitHub 540ceab96f feat: Add query.setHint() to support sql hint as inline comment in select queries (#3365)
* feat: Add query.setHint() to support sql hint as inline comment in select queries

This is for ORM queries only.

An ORM query like:

    new QCustomer()
      .setHint("FirstRows")
      .select(QCustomer.Alias.id, QCustomer.Alias.name)
      .findList();

Produces SQL that includes the hint as an inline comment like:

  select /*+ FirstRows */ t0.id, t0.name
  from customer t0

* Fix test QOrderTest
2024-03-20 21:48:43 +13:00
Rob BygraveandGitHub 8b858a073a feat: Add includeLabelInSql configuration option to include query label as inline comment in generated sql select (#3362)
* feat: Add includeLabelInSql configuration option to include query label as inline comment in generated sql select

The generated select queries can look like:

select /* MyInnerTest.insert_and_find */ t0.id, ...

Using either query.setLabel() or profile location (which all query beans get by default). This means that tooling looking at sql in the database can more easily relate that sql back to application code.

* More tests for labels with includeLabelInSql=true

* Remove trim when using profileLocation label
2024-03-18 07:38:30 +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
181 changed files with 1841 additions and 842 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.2</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.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</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.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-clickhouse</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</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.2</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.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</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.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</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.2</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.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</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.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-db2</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</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.2</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.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</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.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</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.2</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.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</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.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-hana</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</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.2</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.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</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.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-mariadb</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</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.2</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.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</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.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-mysql</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</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.2</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.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</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.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-nuodb</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</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.2</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.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</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.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-oracle</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</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.2</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.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</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.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgis-types</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</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.2</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.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</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.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</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.2</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.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</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.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlite</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</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.2</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.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</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.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlserver</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</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.2</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.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</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.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</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.2</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.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</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.2</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.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-all</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</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.2</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.2</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.
*/
@@ -2208,6 +2209,15 @@ public interface DatabaseBuilder {
@Deprecated
DatabaseBuilder setLoadModuleInfo(boolean loadModuleInfo);
/**
* Set if generated SQL SELECT should include the query label as an
* inline SQL comment (to help reference back from the SQL to the code
* that executed the query.
*
* @param includeLabelInSql When true include a SQL inline comment in generated SELECT queries.
*/
DatabaseConfig includeLabelInSql(boolean includeLabelInSql);
/**
* Set the naming convention to apply to metrics names.
*/
@@ -2221,6 +2231,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.
@@ -3098,10 +3113,20 @@ public interface DatabaseBuilder {
*/
boolean isLoadModuleInfo();
/**
* Return true if generated sql select query should include an inline sql comment with the
* query label or profile location label.
*/
boolean isIncludeLabelInSql();
/**
* Return the naming convention to apply to metrics names.
*/
Function<String, String> getMetricNaming();
/**
* Returns the length check mode.
*/
LengthCheck getLengthCheck();
}
}
@@ -1601,6 +1601,14 @@ public interface Query<T> extends CancelableQuery {
*/
Query<T> setLabel(String label);
/**
* Set a SQL query hint.
* <p>
* This results in an inline comment that immediately follows
* after the select keyword in the form: {@code /*+ hint *\/ }
*/
Query<T> setHint(String hint);
/**
* Set to true if this query should execute against the doc store.
* <p>
@@ -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)));
}
}
@@ -125,6 +125,12 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
*/
private boolean loadModuleInfo = true;
/**
* When true then include a sql comment in generated SELECT queries with the query
* label or profile location label.
*/
private boolean includeLabelInSql;
/**
* Interesting classes such as entities, embedded, ScalarTypes,
* Listeners, Finders, Controllers, AttributeConverters etc.
@@ -236,7 +242,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 +551,8 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
private String dumpMetricsOptions;
private LengthCheck lengthCheck = LengthCheck.OFF;
private Function<String, String> metricNaming = MetricNamingMatch.INSTANCE;
/**
@@ -2131,6 +2139,7 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
readOnlyDatabase = p.getBoolean("readOnlyDatabase", readOnlyDatabase);
autoPersistUpdates = p.getBoolean("autoPersistUpdates", autoPersistUpdates);
loadModuleInfo = p.getBoolean("loadModuleInfo", loadModuleInfo);
includeLabelInSql = p.getBoolean("includeLabelInSql", includeLabelInSql);
maxCallStack = p.getInt("maxCallStack", maxCallStack);
dumpMetricsOnShutdown = p.getBoolean("dumpMetricsOnShutdown", dumpMetricsOnShutdown);
dumpMetricsOptions = p.get("dumpMetricsOptions", dumpMetricsOptions);
@@ -2195,6 +2204,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);
@@ -2544,6 +2554,11 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
return loadModuleInfo;
}
@Override
public boolean isIncludeLabelInSql() {
return includeLabelInSql;
}
/**
* @deprecated - migrate to {@link #isLoadModuleInfo()}.
*/
@@ -2560,6 +2575,12 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
return this;
}
@Override
public DatabaseConfig includeLabelInSql(boolean includeLabelInSql) {
this.includeLabelInSql = includeLabelInSql;
return this;
}
@Override
public Function<String, String> getMetricNaming() {
return metricNaming;
@@ -2571,6 +2592,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
}
@@ -769,4 +769,15 @@ public class DatabasePlatform {
public boolean supportsNativeJavaTime() {
return supportsNativeJavaTime;
}
public String inlineSqlComment(String label) {
if (label == null) {
return "";
}
return "/* " + label + " */ ";
}
public String inlineSqlHint(String hint) {
return "/*+ " + hint + " */ ";
}
}
@@ -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,8 @@ class DatabaseConfigTest {
props.setProperty("defaultServer", "false");
props.setProperty("skipDataSourceCheck", "true");
props.setProperty("readOnlyDatabase", "true");
props.setProperty("lengthCheck", "ON");
props.setProperty("includeLabelInSql", "true");
props.setProperty("queryPlan.enable", "true");
props.setProperty("queryPlan.thresholdMicros", "10000");
@@ -95,6 +97,8 @@ class DatabaseConfigTest {
assertTrue(settings.isLoadModuleInfo());
assertTrue(settings.skipDataSourceCheck());
assertTrue(settings.readOnlyDatabase());
assertTrue(settings.isIncludeLabelInSql());
assertThat(settings.getLengthCheck()).isEqualTo(LengthCheck.ON);
assertTrue(settings.isIdGeneratorAutomatic());
assertFalse(settings.getPlatformConfig().isCaseSensitiveCollation());
@@ -128,8 +132,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 +153,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 +182,8 @@ class DatabaseConfigTest {
assertEquals(600, config.getQueryPlanCapturePeriodSecs());
assertEquals(10000L, config.getQueryPlanCaptureMaxTimeMillis());
assertEquals(10, config.getQueryPlanCaptureMaxCount());
assertThat(config.getLengthCheck()).isEqualTo(LengthCheck.OFF);
assertFalse(config.isIncludeLabelInSql());
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.2</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.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</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.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</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.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>kotlin-querybean-generator</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-redis</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-spring-txn</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</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.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-db2</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-h2</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-hana</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-mariadb</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-mysql</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-nuodb</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-oracle</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgres</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgis</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgis-types</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-sqlite</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-sqlserver</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</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.2</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.2</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.2</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.2</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.2</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.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlserver</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</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);
/**
@@ -226,6 +226,11 @@ public interface SpiQuery<T> extends Query<T>, SpiQueryFetch, TxnProfileEventCod
*/
ProfileLocation profileLocation();
/**
* Return the SQL hint to include in the query.
*/
String hint();
/**
* Return the label set on the query.
*/
@@ -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());
}
}
}
@@ -919,21 +919,27 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
}
private void controllerPost() {
switch (type) {
case INSERT:
controller.postInsert(this);
break;
case UPDATE:
controller.postUpdate(this);
break;
case DELETE_SOFT:
controller.postSoftDelete(this);
break;
case DELETE:
controller.postDelete(this);
break;
default:
break;
boolean old = transaction.isFlushOnQuery();
transaction.setFlushOnQuery(false);
try {
switch (type) {
case INSERT:
controller.postInsert(this);
break;
case UPDATE:
controller.postUpdate(this);
break;
case DELETE_SOFT:
controller.postSoftDelete(this);
break;
case DELETE:
controller.postDelete(this);
break;
default:
break;
}
} finally {
transaction.setFlushOnQuery(old);
}
}
@@ -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();
}
@@ -585,10 +588,9 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> implements ST
}
/**
* Set the join properties from the parent bean to the child bean.
* This is only valid for OneToMany and NOT valid for ManyToMany.
* Set the parent bean to the child (update the relationship).
*/
public void setJoinValuesToChild(EntityBean parent, EntityBean child, Object mapKeyValue) {
public void setParentToChild(EntityBean parent, EntityBean child, Object mapKeyValue) {
if (mapKeyProperty != null) {
mapKeyProperty.setValue(child, mapKeyValue);
}
@@ -599,6 +601,31 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> implements ST
}
}
/**
* Return true if the parent bean has been set to the child (updated the relationship).
*/
public boolean setParentToChild(EntityBean parent, EntityBean child, Object mapKeyValue, BeanDescriptor<?> parentDesc) {
if (manyToMany
|| childMasterProperty == null
|| !child._ebean_getIntercept().isLoadedProperty(childMasterProperty.propertyIndex())) {
return false;
}
Object currentParent = childMasterProperty.getValue(child);
if (currentParent != null) {
Object newId = parentDesc.getId(parent);
Object oldId = parentDesc.id(currentParent);
if (Objects.equals(newId, oldId)) {
return false;
}
}
childMasterProperty.setValueIntercept(child, parent);
if (mapKeyProperty != null) {
mapKeyProperty.setValue(child, mapKeyValue);
}
return true;
}
/**
* Return the order by clause used to order the fetching of the data for
* this list, set or map.
@@ -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();
}
}
@@ -226,7 +226,7 @@ public final class BatchControl {
void executeNow(ArrayList<PersistRequest> list) throws BatchedSqlException {
boolean old = transaction.isFlushOnQuery();
transaction.setFlushOnQuery(false);
// disable flush on query due transsaction callbacks
// disable flush on query due transaction callbacks
try {
for (int i = 0; i < list.size(); i++) {
if (i % batchSize == 0) {
@@ -172,7 +172,9 @@ final class SaveManyBeans extends SaveManyBase {
} else if (ebi.isNewOrDirty()) {
skipSavingThisBean = false;
// set the parent bean to detailBean
many.setJoinValuesToChild(parentBean, detail, mapKeyValue);
many.setParentToChild(parentBean, detail, mapKeyValue);
} else if (many.setParentToChild(parentBean, detail, mapKeyValue, request.descriptor())) {
skipSavingThisBean = false;
} else {
skipSavingThisBean = saveRecurseSkippable;
}
@@ -1,9 +1,6 @@
package io.ebeaninternal.server.query;
import io.ebean.CountDistinctOrder;
import io.ebean.Query;
import io.ebean.RawSql;
import io.ebean.RawSqlBuilder;
import io.ebean.*;
import io.ebean.annotation.Platform;
import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebean.config.dbplatform.SqlLimitRequest;
@@ -52,11 +49,13 @@ final class CQueryBuilder {
private final CQueryDraftSupport draftSupport;
private final DatabasePlatform dbPlatform;
private final boolean selectCountWithColumnAlias;
private final boolean includeLabelInSql;
/**
* Create the SqlGenSelect.
*/
CQueryBuilder(DatabasePlatform dbPlatform, Binder binder, CQueryHistorySupport historySupport, CQueryDraftSupport draftSupport) {
CQueryBuilder(DatabaseBuilder.Settings config, DatabasePlatform dbPlatform, Binder binder, CQueryHistorySupport historySupport, CQueryDraftSupport draftSupport) {
this.includeLabelInSql = config.isIncludeLabelInSql();
this.dbPlatform = dbPlatform;
this.binder = binder;
this.draftSupport = draftSupport;
@@ -596,7 +595,7 @@ final class CQueryBuilder {
}
private void appendSelectDistinct() {
sb.append("select ");
sb.append("select ").append(hint()).append(inlineSqlComment());
if (distinct && !countSingleAttribute) {
if (request.isInlineCountDistinct()) {
sb.append("count(");
@@ -609,6 +608,30 @@ final class CQueryBuilder {
}
}
private String hint() {
String hint = query.hint();
return hint == null ? "" : dbPlatform.inlineSqlHint(hint);
}
private String inlineSqlComment() {
if (!includeLabelInSql) {
return "";
}
SpiQuery.Type type = query.type();
if (type == SpiQuery.Type.SQ_EX || type == SpiQuery.Type.SQ_EXISTS) {
return "";
}
final var label = query.label();
if (label != null) {
return dbPlatform.inlineSqlComment(label);
}
final var profileLocation = query.profileLocation();
if (profileLocation != null) {
return dbPlatform.inlineSqlComment(profileLocation.label());
}
return "";
}
private void appendFrom() {
if (selectClause == null || !selectClause.startsWith("update")) {
sb.append(" from ");
@@ -44,7 +44,7 @@ public final class CQueryEngine {
this.defaultFetchSizeFindList = config.getJdbcFetchSizeFindList();
this.forwardOnlyHintOnFindIterate = dbPlatform.forwardOnlyHintOnFindIterate();
this.historySupport = new CQueryHistorySupport(dbPlatform.historySupport(), asOfTableMapping, config.getAsOfSysPeriod());
this.queryBuilder = new CQueryBuilder(dbPlatform, binder, historySupport, new CQueryDraftSupport(draftTableMap));
this.queryBuilder = new CQueryBuilder(config, dbPlatform, binder, historySupport, new CQueryDraftSupport(draftTableMap));
}
public int forwardOnlyFetchSize() {
@@ -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()
@@ -133,6 +133,11 @@ final class DefaultFetchGroupQuery<T> implements SpiFetchGroupQuery<T>, SpiQuery
return this;
}
@Override
public Query<T> setHint(String hint) {
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
}
// Everything else deemed invalid
@Override
@@ -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;
}
}
@@ -250,6 +250,9 @@ public final class DefaultDtoQuery<T> extends AbstractQuery implements SpiDtoQue
@Override
public DtoQuery<T> setLabel(String label) {
this.label = label;
if (ormQuery != null) {
ormQuery.setLabel(label);
}
return this;
}
@@ -57,6 +57,7 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
private ProfilingListener profilingListener;
private Type type;
private String label;
private String hint;
private Mode mode = Mode.NORMAL;
private boolean usingFuture;
private Object tenantId;
@@ -235,6 +236,11 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
return label;
}
@Override
public final String hint() {
return hint;
}
@Override
public final String planLabel() {
if (label != null) {
@@ -258,6 +264,12 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
return this;
}
@Override
public final Query<T> setHint(String hint) {
this.hint = hint;
return this;
}
@Override
public final boolean isAutoTunable() {
return nativeSql == null && beanDescriptor.isAutoTunable();
@@ -732,6 +744,7 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
copy.timeout = timeout;
copy.mapKey = mapKey;
copy.id = id;
copy.hint = hint;
copy.label = label;
copy.nativeSql = nativeSql;
copy.useBeanCache = useBeanCache;
@@ -1069,6 +1082,9 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
if (manualId) {
sb.append("/md");
}
if (hint != null) {
sb.append("/h:").append(hint);
}
if (distinct) {
sb.append("/dt");
}
@@ -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();
}
}
@@ -29,6 +29,27 @@ public class OrmQueryPlanKeyTest extends BaseTest {
assertSame(query().createQueryPlanKey(), query().createQueryPlanKey());
}
@Test
public void equals_when_hintIsDifferent_expect_different() {
DefaultOrmQuery<Customer> q1 = query();
q1.setHint("a");
assertDifferent(q1, query());
DefaultOrmQuery<Customer> q2 = query();
q2.setHint("b");
assertDifferent(q1, q2);
}
@Test
public void equals_when_hintIsSame() {
DefaultOrmQuery<Customer> q1 = query();
q1.setHint("b");
DefaultOrmQuery<Customer> q2 = query();
q2.setHint("b");
assertSame(q1, q2);
}
@Test
public void equals_when_diffTableJoinNull() {
+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.2</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.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</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.2</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.2</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.2</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.2</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.2</version>
</dependency>
<!-- provided scope -->
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</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.2</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.2</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.2</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.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</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.2</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.
*/
@@ -912,6 +912,17 @@ public abstract class TQRootBean<T, R> {
return root;
}
/**
* Set a SQL query hint.
* <p>
* This results in an inline comment that immediately follows
* after the select keyword in the form: {@code /*+ hint *\/ }
*/
public R setHint(String hint) {
query.setHint(hint);
return root;
}
/**
* Set the profile location.
* <p>
@@ -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;
}
@@ -68,9 +68,9 @@ class MyInnerTest {
List<String> sql = LoggedSql.stop();
assertThat(sql).hasSize(4);
assertThat(sql.get(0)).contains("select t0.id, t0.one, t0.id, t0.one, t0.description from my_inner t0 where t0.one = ?;");
assertThat(sql.get(1)).contains("select t0.id, t0.one, t0.id, t0.one, t0.description from my_inner t0 where t0.description = ?;");
assertThat(sql.get(2)).contains("select t0.id, t0.one, t0.id, t0.one, t0.description from my_inner t0 where t0.id < ? and t0.description = ?;");
assertThat(sql.get(3)).contains("select t0.id, t0.one, t0.id, t0.one, t0.description from my_inner t0 where t0.id < ? and t0.one > ? and t0.one >= ? and t0.one < ? and t0.one <= ? and t0.id > ?;");
assertThat(sql.get(0)).contains("select /* MyInnerTest.insert_and_find:36 */ t0.id, t0.one, t0.id, t0.one, t0.description from my_inner t0 where t0.one = ?;");
assertThat(sql.get(1)).contains("select /* MyInnerTest.insert_and_find:43 */ t0.id, t0.one, t0.id, t0.one, t0.description from my_inner t0 where t0.description = ?;");
assertThat(sql.get(2)).contains("select /* MyInnerTest.insert_and_find:54 */ t0.id, t0.one, t0.id, t0.one, t0.description from my_inner t0 where t0.id < ? and t0.description = ?;");
assertThat(sql.get(3)).contains("select /* MyInnerTest.insert_and_find:65 */ t0.id, t0.one, t0.id, t0.one, t0.description from my_inner t0 where t0.id < ? and t0.one > ? and t0.one >= ? and t0.one < ? and t0.one <= ? and t0.id > ?;");
}
}
@@ -62,6 +62,7 @@ public class QCustomerAndOrTest {
@Test
public void testOrWithExists() {
QCustomer query = Customer.find.typed()
.setLabel("hiLabel")
.alias("_cust")
.or()
.name.eq("Superman")
@@ -72,12 +73,12 @@ public class QCustomerAndOrTest {
.query()
)
.endOr()
.select(QCustomer.alias().id);
.select(QCustomer.Alias.id);
query.findList();
assertThat(query.getGeneratedSql()).isEqualTo(
"select _cust.id from be_customer _cust where (" +
"select /* hiLabel */ _cust.id from be_customer _cust where (" +
"_cust.name = ? or exists (select 1 from be_contact contact where " +
"contact.first_name = ? and contact.customer_id = _cust.id))"
);
@@ -284,7 +284,7 @@ public class QCustomerTest {
.query();
q.findList();
assertThat(q.getGeneratedSql()).isEqualTo("select t0.id, t0.name, t1.id, t1.first_name, t1.last_name from be_customer t0 left join be_contact t1 on t1.customer_id = t0.id where t1.first_name like ? escape'|' and t1.email is not null order by t0.id");
assertThat(q.getGeneratedSql()).isEqualTo("select /* QCustomerTest.filterMany */ t0.id, t0.name, t1.id, t1.first_name, t1.last_name from be_customer t0 left join be_contact t1 on t1.customer_id = t0.id where t1.first_name like ? escape'|' and t1.email is not null order by t0.id");
}
@Test
@@ -296,7 +296,7 @@ public class QCustomerTest {
.query();
q.findList();
assertThat(q.getGeneratedSql()).isEqualTo("select t0.id, t0.name, t1.id, t1.first_name, t1.last_name from be_customer t0 left join be_contact t1 on t1.customer_id = t0.id where t1.first_name like ? escape'|' order by t0.id");
assertThat(q.getGeneratedSql()).isEqualTo("select /* QCustomerTest.filterManySingle */ t0.id, t0.name, t1.id, t1.first_name, t1.last_name from be_customer t0 left join be_contact t1 on t1.customer_id = t0.id where t1.first_name like ? escape'|' order by t0.id");
}
@Test
@@ -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;
@@ -20,16 +22,23 @@ import java.util.List;
import static io.ebean.StdOperators.*;
import static org.assertj.core.api.Assertions.assertThat;
public class QOrderTest {
class QOrderTest {
private static final QCustomer cu = QCustomer.alias();
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)
@@ -71,7 +80,34 @@ public class QOrderTest {
}
@Test
public void fetchCache() {
void hint() {
LoggedSql.start();
new QCustomer()
.setHint("FirstRows")
.select(QCustomer.Alias.id, QCustomer.Alias.name)
.findList();
List<String> sql = LoggedSql.stop();
assertThat(sql).hasSize(1);
assertThat(sql.get(0)).contains("select /*+ FirstRows */ /* QOrderTest.hint */ t0.id, t0.name from be_customer t0");
}
@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 /* QOrderTest.fetchQueryWithBatch */ t0.id, t0.name, t0.phone_number from be_customer t0");
assertThat(sql.get(1)).contains("select /* QOrderTest.fetchQueryWithBatch_contacts__query */ t0.customer_id, t0.id, t0.first_name, t0.last_name, t0.email from be_contact t0 where");
}
@Test
void fetchCache() {
new QOrder()
.status.eq(Order.Status.NEW)
@@ -85,7 +121,7 @@ public class QOrderTest {
}
@Test
public void viaFetchGraph() {
void viaFetchGraph() {
DB.getDefault();
LoggedSql.start();
@@ -98,11 +134,11 @@ public class QOrderTest {
final List<String> sql = LoggedSql.stop();
assertThat(sql).hasSize(1);
assertThat(sql.get(0)).contains("select t0.id, t0.status, t0.ship_date, t0.customer_id from o_order t0 where");
assertThat(sql.get(0)).contains("select /* QOrderTest.viaFetchGraph */ t0.id, t0.status, t0.ship_date, t0.customer_id from o_order t0 where");
}
@Test
public void viaFetchGraph_withJoin() {
void viaFetchGraph_withJoin() {
DB.getDefault();
LoggedSql.start();
@@ -115,11 +151,11 @@ public class QOrderTest {
final List<String> sql = LoggedSql.stop();
assertThat(sql).hasSize(1);
assertThat(sql.get(0)).contains("select t0.id, t0.status, t1.id, t1.name from o_order t0 join be_customer t1 on t1.id = t0.customer_id where");
assertThat(sql.get(0)).contains("select /* QOrderTest.viaFetchGraph_withJoin */ t0.id, t0.status, t1.id, t1.name from o_order t0 join be_customer t1 on t1.id = t0.customer_id where");
}
@Test
public void viaFetchGraph_withNested() {
void viaFetchGraph_withNested() {
DB.getDefault();
LoggedSql.start();
@@ -131,13 +167,12 @@ public class QOrderTest {
final List<String> sql = LoggedSql.stop();
assertThat(sql).hasSize(1);
assertThat(sql.get(0)).contains("select t0.id, t0.status, t0.ship_date, t1.id, t1.name, t1.phone_number from o_order t0 join be_customer t1 on t1.id = t0.customer_id where");
assertThat(sql.get(0)).contains("select /* QOrderTest.viaFetchGraph_withNested */ t0.id, t0.status, t0.ship_date, t1.id, t1.name, t1.phone_number from o_order t0 join be_customer t1 on t1.id = t0.customer_id where");
}
@Test
public void viaFetchGraph_withNested_fetchQuery() {
DB.getDefault();
void viaFetchGraph_withNested_fetchQuery() {
DB.cacheManager().clearAll();
LoggedSql.start();
final Order found = new QOrder()
@@ -149,17 +184,16 @@ public class QOrderTest {
// assert fetching customer via fetchQuery
assertThat(sql).hasSize(2);
assertThat(sql.get(0)).contains("select t0.id, t0.status, t0.customer_id from o_order t0 where t0.id = ?");
assertThat(sql.get(1)).contains("select t0.id, t0.name, t0.phone_number from be_customer t0 where t0.id = ?");
assertThat(sql.get(0)).contains("select /* QOrderTest.viaFetchGraph_withNested_fetchQuery */ t0.id, t0.status, t0.customer_id from o_order t0 where t0.id = ?");
assertThat(sql.get(1)).contains("select /* QOrderTest.viaFetchGraph_withNested_fetchQuery_customer__query */ t0.id, t0.name, t0.phone_number from be_customer t0 where t0.id = ?");
assertThat(found.getCustomer().getPhoneNumber().getMsisdn()).isEqualTo("Ph1");
}
@Test
public void viaFetchGraph_withNested_fetchCache() {
DB.getDefault();
void viaFetchGraph_withNested_fetchCache() {
DB.cacheManager().clearAll();
// ensure the customer is loaded in the L2 cache
new QCustomer().id.eq(customer.getId()).findOne();
@@ -178,11 +212,11 @@ public class QOrderTest {
// assert we only hit DB for order
assertThat(sql).hasSize(1);
assertThat(sql.get(0)).contains("select t0.id, t0.status, t0.customer_id from o_order t0 where t0.id = ?");
assertThat(sql.get(0)).contains("select /* QOrderTest.viaFetchGraph_withNested_fetchQuery */ t0.id, t0.status, t0.customer_id from o_order t0 where t0.id = ?");
}
@Test
public void select_partial() {
void select_partial() {
DB.getDefault();
LoggedSql.start();
@@ -195,11 +229,11 @@ public class QOrderTest {
final List<String> sql = LoggedSql.stop();
assertThat(sql).hasSize(1);
assertThat(sql.get(0)).contains("select t0.id, t0.status, t0.order_date from o_order t0");
assertThat(sql.get(0)).contains("select /* QOrderTest.select_partial */ t0.id, t0.status, t0.order_date from o_order t0");
}
@Test
public void fetch_partial() {
void fetch_partial() {
DB.getDefault();
LoggedSql.start();
@@ -214,12 +248,12 @@ public class QOrderTest {
final List<String> sql = LoggedSql.stop();
assertThat(sql).hasSize(1);
assertThat(sql.get(0)).contains("select t0.id, t0.status, t1.id, t1.email, t1.name from o_order t0 join be_customer t1 on t1.id = t0.customer_id");
assertThat(sql.get(0)).contains("select /* QOrderTest.fetch_partial */ t0.id, t0.status, t1.id, t1.email, t1.name from o_order t0 join be_customer t1 on t1.id = t0.customer_id");
}
@Test
public void updateQuery() {
void updateQuery() {
LoggedSql.start();
new QOrder()
.status.eq(Order.Status.COMPLETE)
@@ -235,7 +269,7 @@ public class QOrderTest {
}
@Test
public void stdExpression_iLikeConcatCoalesce() {
void stdExpression_iLikeConcatCoalesce() {
QOrder o = QOrder.alias();
// LOWER(CONCAT(COALESCE(a.name, ""), ":", a.description)) LIKE LOWER(:param)
@@ -250,7 +284,7 @@ public class QOrderTest {
}
@Test
public void stdExpression_gtCoalesce() {
void stdExpression_gtCoalesce() {
QOrder o = QOrder.alias();
Query<Order> query = new QOrder()
@@ -265,7 +299,7 @@ public class QOrderTest {
String sql = query.getGeneratedSql();
assertThat(sql).contains(" where (coalesce(t1.version,0) > ? or t0.id < ?)");
assertThat(sql).isEqualTo("select t0.id, t0.status from o_order t0 join be_customer t1 on t1.id = t0.customer_id where (coalesce(t1.version,0) > ? or t0.id < ?)");
assertThat(sql).isEqualTo("select /* QOrderTest.stdExpression_gtCoalesce */ t0.id, t0.status from o_order t0 join be_customer t1 on t1.id = t0.customer_id where (coalesce(t1.version,0) > ? or t0.id < ?)");
}
@Test
@@ -278,7 +312,7 @@ public class QOrderTest {
.query();
query.findList();
assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.registered >= (select max(o.order_date) as foo from o_order o)");
assertThat(query.getGeneratedSql()).contains("select /* QOrderTest.geSqlSubQuery */ t0.id from be_customer t0 where t0.registered >= (select max(o.order_date) as foo from o_order o)");
}
@Test
@@ -291,7 +325,7 @@ public class QOrderTest {
.query();
query.findList();
assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.registered > (select max(o.order_date) as foo from o_order o)");
assertThat(query.getGeneratedSql()).contains("select /* QOrderTest.gtSqlSubQuery */ t0.id from be_customer t0 where t0.registered > (select max(o.order_date) as foo from o_order o)");
}
@Test
@@ -304,7 +338,7 @@ public class QOrderTest {
.query();
query.findList();
assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.registered <= (select max(o.order_date) as foo from o_order o)");
assertThat(query.getGeneratedSql()).contains("select /* QOrderTest.leSqlSubQuery */ t0.id from be_customer t0 where t0.registered <= (select max(o.order_date) as foo from o_order o)");
}
@Test
@@ -317,7 +351,7 @@ public class QOrderTest {
.query();
query.findList();
assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.registered < (select max(o.order_date) as foo from o_order o)");
assertThat(query.getGeneratedSql()).contains("select /* QOrderTest.ltSqlSubQuery */ t0.id from be_customer t0 where t0.registered < (select max(o.order_date) as foo from o_order o)");
}
@Test
@@ -330,7 +364,7 @@ public class QOrderTest {
.query();
query.findList();
assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.registered = (select max(o.order_date) as foo from o_order o)");
assertThat(query.getGeneratedSql()).contains("select /* QOrderTest.eqSqlSubQuery */ t0.id from be_customer t0 where t0.registered = (select max(o.order_date) as foo from o_order o)");
}
@Test
@@ -343,7 +377,7 @@ public class QOrderTest {
.query();
query.findList();
assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.registered <> (select max(o.order_date) as foo from o_order o)");
assertThat(query.getGeneratedSql()).contains("select /* QOrderTest.neSqlSubQuery */ t0.id from be_customer t0 where t0.registered <> (select max(o.order_date) as foo from o_order o)");
}
@Test
@@ -361,7 +395,7 @@ public class QOrderTest {
.query();
query.findList();
assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.registered >= (select max(t0.order_date) from o_order t0)");
assertThat(query.getGeneratedSql()).contains("select /* QOrderTest.geSubQuery */ t0.id from be_customer t0 where t0.registered >= (select max(t0.order_date) from o_order t0)");
}
@Test
@@ -376,7 +410,7 @@ public class QOrderTest {
.query();
query.findList();
assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.version > (select sum(t0.version) from o_order t0)");
assertThat(query.getGeneratedSql()).contains("select /* QOrderTest.gtSubQuery */ t0.id from be_customer t0 where t0.version > (select sum(t0.version) from o_order t0)");
}
@Test
@@ -391,7 +425,7 @@ public class QOrderTest {
.query();
query.findList();
assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.registered <= (select max(t0.order_date) from o_order t0)");
assertThat(query.getGeneratedSql()).contains("select /* QOrderTest.leSubQuery */ t0.id from be_customer t0 where t0.registered <= (select max(t0.order_date) from o_order t0)");
}
@Test
@@ -406,7 +440,7 @@ public class QOrderTest {
.query();
query.findList();
assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.registered < (select max(t0.order_date) from o_order t0)");
assertThat(query.getGeneratedSql()).contains("select /* QOrderTest.ltSubQuery */ t0.id from be_customer t0 where t0.registered < (select max(t0.order_date) from o_order t0)");
}
@Test
@@ -421,7 +455,7 @@ public class QOrderTest {
.query();
query.findList();
assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.registered = (select max(t0.order_date) from o_order t0)");
assertThat(query.getGeneratedSql()).contains("select /* QOrderTest.eqSubQuery */ t0.id from be_customer t0 where t0.registered = (select max(t0.order_date) from o_order t0)");
}
@Test
@@ -436,7 +470,7 @@ public class QOrderTest {
.query();
query.findList();
assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.registered <> (select max(t0.order_date) from o_order t0)");
assertThat(query.getGeneratedSql()).contains("select /* QOrderTest.neSubQuery */ t0.id from be_customer t0 where t0.registered <> (select max(t0.order_date) from o_order t0)");
}
@Test
@@ -20,7 +20,7 @@ class QueryAlsoIfTest {
.query();
q.findList();
assertThat(q.getGeneratedSql()).isEqualTo("select t0.id, t0.name from be_customer t0 where t0.name is not null and t0.status = ?");
assertThat(q.getGeneratedSql()).isEqualTo("select /* QueryAlsoIfTest.apply */ t0.id, t0.name from be_customer t0 where t0.name is not null and t0.status = ?");
}
@Test
@@ -32,6 +32,6 @@ class QueryAlsoIfTest {
.query();
q.findList();
assertThat(q.getGeneratedSql()).isEqualTo("select t0.id, t0.name from be_customer t0 where t0.name is not null");
assertThat(q.getGeneratedSql()).isEqualTo("select /* QueryAlsoIfTest.notApply */ t0.id, t0.name from be_customer t0 where t0.name is not null");
}
}
@@ -3,6 +3,7 @@ ebean.ddl.run=true
ebean.ddl.initSql=init-db.sql
ebean.dumpMetricsOnShutdown=true
ebean.dumpMetricsOptions=sql,hash,loc
ebean.includeLabelInSql=true
datasource.default=h2
+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.2</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.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</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.2</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.2</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.2</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.2</version>
<scope>test</scope>
</dependency>
+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.2</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.2</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</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.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-all</artifactId>
<version>13.26.1-jakarta</version>
<version>14.0.2</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>
@@ -164,8 +164,14 @@ public class DtoQueryFromOrmTest extends BaseTestCase {
DtoQuery<ContactDto> query = DB.find(Contact.class)
// we must explicitly add the id property for DTO query (if we want it)
.select("id, email, " + concat("lastName", ", ", "firstName") + " as fullName").where().isNotNull("email")
.isNotNull("lastName").order().asc("lastName").asDto(ContactDto.class).setLabel("explicitId")
.setHint("SomeHint")
.select("id, email, " + concat("lastName", ", ", "firstName") + " as fullName")
.where()
.isNotNull("email")
.isNotNull("lastName")
.orderBy().asc("lastName")
.asDto(ContactDto.class)
.setLabel("explicitId")
.setRelaxedMode();
List<ContactDto> dtos = query.findList();
@@ -178,7 +184,7 @@ public class DtoQueryFromOrmTest extends BaseTestCase {
}
List<String> sql = LoggedSql.stop();
assertSql(sql.get(0)).contains("select t0.id, t0.email, " + concat("t0.last_name", ", ", "t0.first_name")
assertSql(sql.get(0)).contains("select /*+ SomeHint */ /* explicitId */ t0.id, t0.email, " + concat("t0.last_name", ", ", "t0.first_name")
+ " fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name");
}
@@ -26,11 +26,12 @@ public class FetchGroupTest extends BaseTestCase {
.query()
.where()
.ilike("name", "rob")
.setLabel("hello")
.select(fetch);
query.findList();
assertThat(sqlOf(query)).contains("select t0.id, t0.name, t0.status from");
assertThat(sqlOf(query)).contains("select /* hello */ t0.id, t0.name, t0.status from");
}

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