Compare commits

..
Author SHA1 Message Date
Rob Bygrave 7addba7c93 Version 16.2.1 2026-02-02 23:22:22 +13:00
Rob Bygrave 00b45c1642 For query usingMaster support passing a boolean (#3721)
This is to support the use case where other logic is used to determine if a query
should be "forced" to use the master data source or not, and so it's easier to
pass that as a boolean to the usingMaster() method.
2026-02-02 23:17:37 +13:00
Rob Bygrave a3d9711fe6 Version 16.2.0 2025-11-23 22:18:54 +13:00
Rob Bygrave 1239c50723 Bump ebean-agent to 16.2.0 2025-11-23 22:16:29 +13:00
Rob Bygrave d85d8449e2 #3695 Behaviour change: findSingleAttribute() to throw when multiple … (#3697)
* #3695 Behaviour change: findSingleAttribute() to throw when multiple rows returned by query

On the plus, this makes the behaviour consistent with all the other findOne() methods (ORM, DTO, SqlQuery) and this very much feels like buggy behaviour [to just get the first result and ignore any subsequent results in the ResultSet]

On the negative of merging this bug fix, any application code relying on the existing behaviour with this fix will break and throw a NonUniqueResultException at RUNTIME (not ideal). However, for these cases where the application now throws an exception, people might not be aware that they were relying on this behaviour and this exception could be useful to highlight that (a potential non-deterministic query result was being used and a potential source of bugs was being).

* Change SqlQuery + Mapper + findOne() also to throw NonUniqueResultException
2025-11-23 22:14:44 +13:00
dependabot[bot] baf71cbab3 Bump com.microsoft.sqlserver:mssql-jdbc in /ebean-test (#3694)
Bumps [com.microsoft.sqlserver:mssql-jdbc](https://github.com/Microsoft/mssql-jdbc) from 10.2.0.jre8 to 11.1.0.jre8-preview.
- [Release notes](https://github.com/Microsoft/mssql-jdbc/releases)
- [Changelog](https://github.com/microsoft/mssql-jdbc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/Microsoft/mssql-jdbc/commits)

---
updated-dependencies:
- dependency-name: com.microsoft.sqlserver:mssql-jdbc
  dependency-version: 11.1.0.jre8-preview
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-23 21:01:00 +13:00
Rob Bygrave ff0ca35e54 #3701 Improve error message when missing dependency ebean-jackson-mapper (#3708) 2025-11-23 20:25:16 +13:00
Rob BygraveandRoman Parshikov 0fc9a1ac2f Bug fix and change filterMany to put predicates into JOIN clause, Fix for #3626 (#3707)
* Problem with filterMany

* Missing id

* Other test

* Fix

* Update TestQueryFilterMany.java

* #3706 Bug fix and change filterMany to put predicates into JOIN clause, Fix for #3626

* Fix tests for Postgres, Oracle, Sql Server

---------

Co-authored-by: Roman Parshikov <promansew@gmail.com>
2025-11-23 20:20:13 +13:00
Rob Bygrave f7b4edb193 Merge pull request #3704 from ebean-orm/feature/bump-test-deps-bytebuddy
Bump test dependencies byte buddy and assertj
2025-11-20 09:35:09 +13:00
robin.bygrave 284c8d4d21 Bump test dependencies byte buddy and assertj 2025-11-20 09:23:39 +13:00
Rob Bygrave 59a5c5f9bd Bump dependency avaje-config to 4.2 (#3699) 2025-11-11 07:59:40 +13:00
Rob Bygrave 5b04d6eca3 #3551 Log warning for use of mapping column to Class (#3698)
I think it was a mistake for Ebean to support Class<?> from a security perspective. Instead, Ebean should just use a String <-> Varchar and leave if up to the application to take that String and convert it to a class [and then that potential Class initialisation is owned by the application code and all security considerations around that are owned by the application code].
2025-11-11 07:57:15 +13:00
Ryszard TrojnackiandRob Bygrave d5547808a2 PGvector support (#3696)
* Add pgvector-types module.

* Add missing binder definitions.
Add missing PGbit type registration.
Few tests.

* Add cached bean test.

* Prefer final classes, minor formating only

---------

Co-authored-by: Rob Bygrave <robin.bygrave@gmail.com>
2025-11-09 16:55:51 +13:00
Rob Bygrave 5606c95de5 Version 16.1.1 2025-10-22 22:45:21 +13:00
Rob Bygrave 4c2bd408b0 Bump ebean-agent 2025-10-22 22:42:00 +13:00
Rob Bygrave db76d5c27c Test only - add Postgres JSONB raw() expression example 2025-10-22 22:03:09 +13:00
Rob Bygrave f92c2f8c14 Test only - add test for string id InsertOnConflict 2025-10-22 22:02:40 +13:00
Rob Bygrave 51c3065419 3683 - Add AggregateFormulaContext to support group_concat etc (#3691)
- Add AggregateFormulaContext with ability to override the default via DatabaseBuilder
- Add group_concat, string_agg, listagg to set of known aggregation functions
2025-10-21 22:54:55 +13:00
Rob Bygrave e46dd66292 Test only - bump to Postgres 17 for PostgresReadOnlyDatabaseTest 2025-10-21 20:55:52 +13:00
Rob Bygrave 3e1451bee7 Merge branch 'master' of github.com:ebean-orm/ebean 2025-10-21 20:54:23 +13:00
Rob Bygrave 4ac3c4ddb1 3682 @Aggregation is applied to query if entity also has a @lob column (#3689)
* Version 16.1.0

* #3682 @Aggregation is applied to query if entity also has a @Lob column

The underling issue was that Aggregation columns should have been marked as default LAZY. This impact was only hit when @Lob column are included which by default lazy fetched, and that means the default select clause determined.
2025-10-20 20:55:18 +13:00
Rob Bygrave ee8e48902b Merge branch 'master' of github.com:ebean-orm/ebean 2025-10-19 18:07:18 +13:00
Rob Bygrave c37e752ace #3681 javadoc query cache (#3687)
* Version 16.1.0

* Improve javadoc for Query setUseQueryCache() and unmodifiable

Since 16.x a query using the query cache returns unmodifiable object graphs.
2025-10-14 20:04:38 +13:00
Rob Bygrave c9a6f822ac Version 16.1.0 2025-09-19 18:48:28 +12:00
Rob Bygrave 2231ef9fd1 Bump ebean-agent to 16.1.0 with Java 25 support (#3680)
Note that the IntelliJ plugin has been updated and published. It should be public in a few days.
2025-09-19 16:25:24 +12:00
Rob Bygrave 3ff1905318 Bump ebean-test-containers to 7.15 with updated ClickHouse support 2025-09-19 16:25:00 +12:00
Rob Bygrave 9b4fecff96 Add support for AutoCommit true transactions (#3679)
* Add support for AutoCommit true transactions

* Update DocStoreTransactionManager
2025-09-19 16:22:59 +12:00
Rob Bygrave 6f356fd55e #3674 Add @Nullable to Query getId(), getForUpdateLockWait(), getForUpdateLockType() (#3675)
These methods return nullable results, add JSpecify `@Nullable` to correctly indicate this.
2025-09-06 17:22:13 +12:00
Rob Bygrave 591f260f5b Retain filterMany expression when select fetchGroup applied after filterMany (#3673) 2025-09-02 22:35:43 +12:00
Rob Bygrave b361b10571 Version 16.0.1 2025-09-02 14:09:03 +12:00
Rob Bygrave c0e4e548ee Update the kotlin-maven-plugin for tests and use EA maven profile (#3671)
* Update the kotlin-maven-plugin for tests

* Add a profile for EA that excludes kotlin-querybean-generator

* For build workflow use maven profile "default"

To ensure the kotlin-querybean-generator, test modules run

* For build workflow use maven profile "default"

To ensure the kotlin-querybean-generator, test modules run
2025-09-02 14:04:59 +12:00
Rob Bygrave 92f3245919 Bump ebean-agent to 16.0.1 2025-09-02 13:37:45 +12:00
Rob Bygrave 59c2290916 Bump ebean-migration dependency, fix for setting dbSchema on migrations (#3670)
Ref: https://github.com/ebean-orm/ebean-migration/pull/163
2025-09-02 12:52:41 +12:00
Rob Bygrave 1135eb3f99 #3665 Fix for delete() Skips Bean due to Hash Collision (#3669)
Change the underlying storage of deleting beans to be by type by id so:

  private Map<Class<?>, Set<Object>> deletingBeans;
2025-08-31 22:32:27 +12:00
Rob Bygrave 1dccdff7bf #3664 Fix / support for extra JoinColumns on ManyToOne (#3668)
* #3664 Fix / support for extra JoinColumns on ManyToOne

Allows for extra JoinColumns on ManyToOne. The extra JoinColumn(s) are
expected to be useful for the case of table partitioning where the extra
join column is used to partition the table. In the test case, the partition
column would be the org_id column and common to both tables (same partition key).

* #3664 Fix / support for extra JoinColumns on ManyToOne

Allows for extra JoinColumns on ManyToOne. The extra JoinColumn(s) are
expected to be useful for the case of table partitioning where the extra
join column is used to partition the table. In the test case, the partition
column would be the org_id column and common to both tables (same partition key).

* #3664 Extend test

* #3664 Tidy up test
2025-08-31 12:52:17 +12:00
Rob Bygrave 5f74a53e3e #3666 Fix for NPE with filterMany() containing or() (#3667)
For FilterMany with QueryBeans, it creates a queryBean to build the filterMany predicates with. This query bean needed 2 changes for this fix:

1. Needs to set it's internal "root" such that it supports chaining (required for or() etc)
2. The ExpressionFactory needs to be explicitly passed to the expression list (rather than get it from the query which is actually null in this case).
2025-08-31 10:08:07 +12:00
Rob Bygrave 1f9e652ea9 Version 16.0.0 2025-08-25 08:21:49 +12:00
Rob Bygrave 4e592c97ff Update how to deploy 2025-08-05 23:30:18 +12:00
Rob Bygrave 760d19a10d Update how to deploy 2025-08-05 23:16:42 +12:00
Rob Bygrave d2693c3ff2 Version 16.0.0-RC4 2025-08-05 23:15:20 +12:00
Rob Bygrave 3324b2bda4 Use autocommit false with findIterate for Postgres (#3662)
* Use autocommit false with findIterate for Postgres

* Use autocommit false with findIterate for Postgres

* Use autocommit false with FindDto queries for Postgres

* Use autocommit false with SqlQuery findIterate queries for Postgres

* Ensure that TransactionFactory.createReadOnlyTransaction() returns an ImplicitReadOnlyTransaction

This change changes TransactionFactoryTenant.createReadOnlyTransaction() to return a ImplicitReadOnlyTransaction, as that is now used to support Postgres use of cursors with findIterate style queries.
2025-08-05 23:03:28 +12:00
Rob Bygrave 1b5e066562 #3654 Fix querybean-generator compiler warning for unclaimed annotations (#3655)
warning: No processor claimed any of these annotations: /io.ebean.typequery.TypeQueryBean,/io.ebean.typequery.Generated

This fix is required when the compiler is run with -Werror specified

An alternative workaround is to use compiler arg -Xlint:-processing rather than -Xlint:all
2025-07-16 20:34:56 +12:00
Rob Bygrave 104e4ec756 Bump ebean-test-containers to 7.14 - Yugabyte read committed support enabled by default (#3651) 2025-07-14 09:03:39 +12:00
Rob Bygrave 74a2967a6e Tests Yugabyte - comment out the TestQueryForUpdate using repeatable read
... as its noise there is anyone else reads the logs
2025-07-12 09:38:06 +12:00
Rob Bygrave e693b12a97 Tests DB2 - ignore TestRawExpressionInterpolation for DB2 2025-07-12 09:30:16 +12:00
Rob Bygrave 48fb9b34bb Tests Yugabyte - faster test using forUpdate 2025-07-12 09:18:01 +12:00
Rob Bygrave f64400400a Tests Oracle - ignore the TestRawExpressionInterpolation for Oracle 2025-07-12 09:09:34 +12:00
Rob Bygrave d7cc081942 Tests Yugabyte - see if everything else passes 2025-07-12 09:04:02 +12:00
Rob Bygrave 3351548b60 Fix use of JSpecify Nullable annotation in query bean generation 2025-07-11 23:45:31 +12:00
Rob Bygrave 8d9858f57a Test only - Update logging for test TestQueryForUpdate 2025-07-11 23:35:03 +12:00
Rob Bygrave 9b520bc176 Bump avaje-config to 4.1 2025-07-11 23:22:16 +12:00
Rob Bygrave 44fd8e3a56 Adjust TestQueryForUpdate for Yugabyte - use markAsDirty on repeatable read test 2025-07-11 23:11:45 +12:00
Rob Bygrave 6910016c4d Adjust TestQueryForUpdate for Yugabyte - use markAsDirty
To see if the update has an impact on the 2nd thread waiting
2025-07-11 22:58:02 +12:00
Rob Bygrave 5f8a3c0591 Adjust TestQueryForUpdate for Yugabyte - check repeatable read isolation level 2025-07-11 22:05:31 +12:00
Rob Bygrave 0ae6956c1c Bump ebean-datasource 10.1 with support for initialConnections (#3650)
So in a K8s deployment, this adds support for having an initial number of connections to create initially (higher that min connections). This allows for a smoother deployment, by effectively having initially more connections than min in order to immediately take production load, and then over time trim back down towards the min connections.

So in k8s I am setting min, initial and max connections, where initial connections is high enough to take full production load straight after readiness true.
2025-07-11 21:26:58 +12:00
Rob Bygrave 2e9c5d8548 Merge branch 'query-cache-oom-for-too-large-beans' 2025-07-11 21:19:21 +12:00
Rob Bygrave 93edc840b3 Add a test that hits the new branch of code 2025-07-11 21:18:00 +12:00
Josiah NoelandRob Bygrave 34311785fa Fix Jackson NCDF Error (#3639)
* fix jackson NCDF error

split jackson SPI impl into it's own module

* Restore format

* Restore format

* Trim up dependencies

* Rename module to ebean-core-json

---------

Co-authored-by: Rob Bygrave <robin.bygrave@gmail.com>
2025-07-11 20:53:25 +12:00
Rob Bygrave 63929f8ff3 Bump test Yugabyte version to 2.20.11.0-b34 2025-07-11 20:26:12 +12:00
Jonas Fröhler d918c5117f no import changes 2025-07-01 09:05:48 +02:00
Jonas Fröhler dd845a7b0c Fix imports 2025-07-01 09:02:26 +02:00
Jonas Fröhler df0e4d57f0 Clean up 2025-06-27 12:17:19 +02:00
Jonas Fröhler 9c7fa25d49 Query Cache OOM test and potential draft for the fix 2025-06-27 12:14:01 +02:00
Rob Bygrave e82c1a4140 Version 16.0.0-rc3 2025-05-26 21:00:32 +12:00
Rob Bygrave 389bf48e3e Merge pull request #3636 from ebean-orm/feature/explicit-shutdownHook
Add DatabaseBuilder.shutdownHook option (programmatic disabling registration of JVM shutdown hook)
2025-05-26 17:24:25 +12:00
Rob Bygrave 3b3b44543e Bump ebean-test-containers, programmatically get DatabaseBuilder from test container 2025-05-26 17:23:27 +12:00
Rob Bygrave 297f334da5 Add DatabaseBuilder.shutdownHook option (programmatic disabling registration of JVM shutdown hook) 2025-05-26 17:21:15 +12:00
Rob Bygrave 78c7439445 test only - rename TestRawExpressionInterpolation 2025-05-15 08:00:52 +12:00
Rob Bygrave 2043ba6411 Merge pull request #3634 from ebean-orm/feature/native-image-otherTypes
[native-image] Modify querybean-generator to include AttributeConverters in generated reflect-config.json
2025-05-14 20:49:52 +12:00
Rob Bygrave 437c58001b [native-image] Modify querybean-generator to include AttributeConverters in generated reflect-config.json 2025-05-14 20:48:07 +12:00
Rob Bygrave 0e812efa7e Merge branch 'master' of github.com:ebean-orm/ebean 2025-05-14 20:27:56 +12:00
Rob Bygrave 80d4d21986 Merge pull request #3632 from FOCONIS/reorg-args-placeholder
Db2: Reorg args placeholder
2025-05-06 20:44:00 +12:00
Noemi Praml fe66b8c242 fix DbMigrationTest 2025-05-06 09:49:18 +02:00
Noemi Praml 206b2b2d3b migrations 2025-05-06 08:06:48 +02:00
Noemi Praml c0bc3faea0 fix test 2025-05-06 08:06:40 +02:00
Noemi Praml 3d07e7d804 add: reorgARgs Placeholder 2025-05-06 08:00:58 +02:00
Rob Bygrave fc124e8318 Tidy pom only 2025-04-30 00:02:30 +12:00
Rob Bygrave f4fd4f4b09 Version 16.0.0-RC2 2025-04-30 00:01:52 +12:00
Rob Bygrave 16f5311885 Bump parent pom to 5.1 for new maven central deploy 2025-04-29 23:41:48 +12:00
Rob Bygrave 75a0675977 Merge pull request #3630 from ebean-orm/feature/fix-ea-build-kotlin
Fix EA build, Kotlin not supporting 25-EA release
2025-04-29 23:37:10 +12:00
Rob Bygrave 80ebf4a1ee Fix EA build, Kotlin not supporting 25-EA release
It barfs trying to parse the 25-EA version, means the kotlin-querybean-generator fails the build for the Java Early Release versions.

With this, it will skip the kotlin modules for the Java Early Access release builds.
2025-04-29 23:36:22 +12:00
Rob Bygrave 4185beb5aa Merge pull request #3629 from ebean-orm/feature/bump-datasource-10
Bump ebean-datasource to 10.0 (Virtual Threads support via MR Jar)
2025-04-29 23:17:54 +12:00
Rob Bygrave 79908c0164 Bump ebean-datasource to 10.0 (Virtual Threads support via MR Jar)
Note that this still supports Java 11.

The 10.0 version of ebean-datasource uses Multi-Version jar such that if running using Java 21+ then it will use Virtual Threads for the background Heartbeat validation and also background closing of connections.
2025-04-29 23:09:49 +12:00
Rob Bygrave b5a16f42ca #3626 Add tests for bean property name instead of db column 2025-04-23 22:33:18 +12:00
Gonçalo Andrade a320a132b3 Fix incorrect usage of bean property name instead of corresponding column 2025-04-22 14:51:38 +01:00
Rob Bygrave 9e84e93511 Merge pull request #3621 from FOCONIS/new-db-versions
New db versions + testcontainers 7.8
2025-04-17 23:18:05 +12:00
Noemi Praml 6fb40c71ef update StartDb2 2025-04-16 15:22:08 +02:00
Noemi Praml 202b9ae94a update to testcontainers 7.8 2025-04-16 14:52:21 +02:00
Noemi Praml d79b452378 new db2 version 2025-04-16 14:19:11 +02:00
Noemi Praml 78a408dd10 new sqlserver version 2025-04-16 14:19:11 +02:00
Noemi Praml 6af974e432 new mariadb version 2025-04-16 14:19:11 +02:00
Rob Bygrave 04a8475291 Merge pull request #3623 from ebean-orm/feature/readOnly-DataSource-mark-nullable
Explicitly mark Database.readOnlyDataSource() as @Nullable
2025-04-15 22:25:06 +12:00
Rob Bygrave c56345f92e Explicitly mark Database.readOnlyDataSource() as @Nullable
Using JSpecify @Nullable on the return for Database.readOnlyDataSource()
2025-04-15 22:24:14 +12:00
Rob Bygrave ed0a46955e Explicitly mark Database.readOnlyDataSource() as @Nullable
Using JSpecify @Nullable on the return for Database.readOnlyDataSource()
2025-04-15 22:22:08 +12:00
Rob Bygrave 3c4b04a893 Version 16.0.0-rc1 2025-04-09 23:18:27 +12:00
Rob Bygrave ee403bdb83 Merge pull request #3620 from ebean-orm/feature/bump-ebean-agent
Bump the ebean-agent to 14.12.0, support for Lombok SuperBuilder
2025-04-09 23:02:46 +12:00
Rob Bygrave b18abe2221 Bump the ebean-agent to 14.12.0, support for Lombok SuperBuilder 2025-04-09 22:52:39 +12:00
Rob Bygrave d68f372d99 Merge pull request #3619 from ebean-orm/feature/column-length-255
For Postgres @Column(length=255) means varchar(255)
2025-04-09 20:22:56 +12:00
Rob Bygrave c8f769aa2a For Postgres @Column(length=255) means varchar(255)
The `@Column` length defaults to 0 rather than 255, this allows us to detect when it has been explicitly set and thus for Postgres we can now have:

@Column(length=255) mapping to -> varchar(255)
@Column mapping to -> varchar
2025-04-09 20:07:56 +12:00
Rob Bygrave bde626fd45 Merge pull request #3618 from ebean-orm/feature/bump-datasource-95
Bump ebean-datasource to 9.5
2025-04-09 20:04:23 +12:00
Rob Bygrave b828b73b2c Bump ebean-datasource to 9.5
When using DataSourceBuilder for both main and readOnly datasource, the maxConnections for the readOnly will default to the main pool maxConnections.
2025-04-09 20:02:14 +12:00
Rob Bygrave 2795a8578f Merge pull request #3616 from ebean-orm/feature/lazyLoadBatch-100
Increase default lazyLoadBatchSize from 10 to 100
2025-04-04 21:15:23 +13:00
Rob Bygrave bd0a3c2303 Increase default lazyLoadBatchSize from 10 to 100 2025-04-04 21:14:47 +13:00
Rob Bygrave 21e50e9d00 Merge pull request #3615 from ebean-orm/feature/3612-redis-exception
#3612 Catch all RedisException (rather than only IOException)
2025-04-04 20:47:44 +13:00
Rob Bygrave 88a47bf0a9 #3612 Catch all RedisException (rather than only IOException) 2025-04-04 20:45:59 +13:00
Rob Bygrave d9a45245f4 Version 16.0.0-beta1 2025-04-03 19:35:14 +13:00
Rob Bygrave 7be72df788 Merge pull request #3570 from ebean-orm/feature/improved-readOnly-immutable
Unmodifiable - Improved read only immutable entity beans / graphs
2025-04-02 22:24:19 +13:00
Rob Bygrave 42685335e3 Version 14.11.0 2025-04-01 21:32:48 +13:00
Rob Bygrave 478a2be405 Merge pull request #3611 from ebean-orm/feature/fix-native-image-mappedSuper
Fix NPE with native-image with @MappedSuperclass
2025-04-01 20:45:17 +13:00
Rob Bygrave ebcac9a503 Fix NPE with native-image with @MappedSuperclass
@MappedSuperclass was excluded from the generated reflect-config.json, this PR fixes that.

The missing reflect-config entry for MappedSuperclass means that with native-image the @Id property isn't found when its on a MappedSuperclass, and that ended up as a NPE in BeanPropertyAssocOne.
2025-04-01 20:29:26 +13:00
Rob Bygrave 996239c29f Merge pull request #3610 from ebean-orm/feature/configure-explain
Add support to configure EXPLAIN options for query plan capture
2025-04-01 08:07:46 +13:00
Rob Bygrave caf2772fb3 Put Postgres explain back to default format text for now 2025-04-01 08:07:04 +13:00
Rob Bygrave 1482c4c84f Add support to configure EXPLAIN options for query plan capture
e.g. DatabaseBuilder.queryPlanExplain("explain (verbose)")

Also changes Postgres default explain to be:
explain (analyze, costs, verbose, buffers, format json)
2025-03-31 23:41:16 +13:00
Rob Bygrave 792d52b794 Merge pull request #3609 from ebean-orm/feature/queryPlanInit
Change QueryPlanInit to support thresholdMicros per hash
2025-03-30 21:41:53 +13:00
Rob Bygrave aa4ea4904f Change QueryPlanInit to support thresholdMicros per hash
Effectively means that we can provide a thresholdMicros per query plan hash [for the plans that we want collected]
2025-03-30 21:35:20 +13:00
Rob Bygrave bab839fb38 Change QueryPlanInit to support thresholdMicros per hash
Effectively means that we can provide a thresholdMicros per query plan hash [for the plans that we want collected]
2025-03-30 18:33:13 +13:00
Rob Bygrave dde2567ccd Merge pull request #3608 from ebean-orm/feature/bump-postgres-16
Test only - align sqlserver test configuration
2025-03-26 22:50:48 +13:00
Rob Bygrave 7e4d070b75 Test only - update sqlserver test docker image to 2017-CU31-ubuntu-18.04 2025-03-26 22:50:22 +13:00
Rob Bygrave 3151e3f82b Test only - align sqlserver test configuration 2025-03-26 22:41:00 +13:00
Rob Bygrave c630aaff0e Merge pull request #3607 from ebean-orm/feature/bump-postgres-16
Test only - align mariadb test configuration
2025-03-26 22:37:34 +13:00
Rob Bygrave 67ec848f15 Test only - align mariadb test configuration 2025-03-26 22:37:09 +13:00
Rob Bygrave 57f0734381 Test only - align mariadb test configuration 2025-03-26 22:32:18 +13:00
Rob Bygrave cbd5bf23c9 Merge pull request #3606 from ebean-orm/feature/bump-postgres-16
Test only - align mysql and db2 test configuration
2025-03-26 22:31:51 +13:00
Rob Bygrave 5dc664a63f Test only - align mysql and db2 test configuration 2025-03-26 22:27:35 +13:00
Rob Bygrave d9b53677f2 Merge pull request #3605 from ebean-orm/feature/bump-postgres-16
Test only - add logging for datasource to BaseTestCase
2025-03-26 22:17:56 +13:00
Rob Bygrave f55c2cf3b6 Test only - add logging for datasource to BaseTestCase 2025-03-26 22:14:24 +13:00
Rob Bygrave c98def7ab7 Merge pull request #3604 from ebean-orm/feature/bump-postgres-16
Test only - add logging for datasource to BaseTestCase
2025-03-26 22:06:58 +13:00
Rob Bygrave 705e158a70 Test only - add logging for datasource to BaseTestCase 2025-03-26 22:06:35 +13:00
Rob Bygrave 569e782e99 Merge pull request #3603 from ebean-orm/feature/bump-postgres-16
Update Postgres and Postgis test containers to default to 16
2025-03-26 22:05:59 +13:00
Rob Bygrave 265b92fb12 Update Postgres and Postgis test containers to default to 16 2025-03-26 21:43:08 +13:00
Rob Bygrave 74311fad0a Update test postgres docker image to 16 2025-03-26 21:34:31 +13:00
Rob Bygrave 1eded5682a Merge pull request #3599 from ebean-orm/feature/bump-datasource-dependency2
Bump ebean-datasource dependency to 9.3
2025-03-21 18:42:53 +13:00
Rob Bygrave ff21bfe1de Bump ebean-datasource dependency to 9.3 2025-03-21 00:35:41 +13:00
Rob Bygrave 86db7fadfd Merge pull request #3598 from ebean-orm/feature/tidy-QueryCacheEntry
Tidy QueryCacheEntry, final class and use accessors
2025-03-20 23:58:56 +13:00
Rob Bygrave e48b327967 Tidy QueryCacheEntry, final class and use accessors 2025-03-20 23:57:56 +13:00
Rob Bygrave 964b3ccf8e Merge pull request #3597 from ebean-orm/feature/3515-extend
#3515 Bug in QueryCache invalidation
2025-03-20 23:55:10 +13:00
Rob Bygrave eb6906ad2b #3515 Bug in QueryCache invalidation
Effectively the bug fix is in SqlTreeNodeRoot.dependentTables() to include the baseTable in the set of dependent tables
2025-03-20 23:47:21 +13:00
Rob Bygrave 86e5ea3627 Merge pull request #3596 from ebean-orm/feature/tidy-future-queries
Change findFuture queries such that they can use the read only DataSource
2025-03-19 23:06:38 +13:00
Rob Bygrave 3a5e8290e0 Change findFuture queries such that they can use the read only DataSource
Prior to this change they made an explicit transaction if one was needed, and this would always use the Main DataSource.

With this change, when there is no transaction assigned to the query and no active transaction, then the find future query will use the ReadOnly DataSource if it has been configured (e.g. ReadOnly DataSource might point to a read replica database instance).
2025-03-19 23:00:19 +13:00
Rob Bygrave 929604e33d Merge pull request #3593 from LeComptoirDesPharmacies/feature/findFutureMap
Add feature findFutureMap
2025-03-19 22:12:06 +13:00
Rob Bygrave 2eed68ad61 Merge pull request #3595 from ebean-orm/feature/bump-avaje-config2
Bump avaje-config dependency to 4.0
2025-03-19 20:57:13 +13:00
Rob Bygrave f705560b8b Bump avaje-config dependency to 4.0 2025-03-19 20:56:40 +13:00
Thomas a35db6bdee Add feature findFutureMap 2025-03-18 09:19:15 +01:00
Noemi Praml 3ab3f81fa3 Add failing concurrent test 2024-10-31 08:21:37 +01:00
311 changed files with 4042 additions and 1259 deletions
+1 -1
View File
@@ -40,5 +40,5 @@ jobs:
# - name: Maven single test
# run: mvn --batch-mode clean verify -Dtest="io.ebeaninternal.server.core.DefaultServer_getReferenceTest" -DfailIfNoTests=false
- name: Build with Maven
run: mvn -T 8 clean test
run: mvn -T 8 clean test -Pdefault
+2 -2
View File
@@ -16,7 +16,7 @@ jobs:
strategy:
fail-fast: false
matrix:
java_version: [GA,EA,23]
java_version: [GA,EA]
os: [ubuntu-latest]
steps:
@@ -37,5 +37,5 @@ jobs:
- name: Maven version
run: mvn --version
- name: Build with Maven
run: mvn -T 8 test
run: mvn test -Pea
+1 -1
View File
@@ -34,5 +34,5 @@ jobs:
path:
~/.m2
key: build-${{ env.cache-name }}
- name: mariadb 10.6
- name: mariadb 10.11
run: mvn -T 8 clean test -Dprops.file=testconfig/ebean-mariadb.properties
+2 -2
View File
@@ -34,5 +34,5 @@ jobs:
path:
~/.m2
key: build-${{ env.cache-name }}
- name: sqlserver 2017
run: mvn -T 8 clean test -Dprops.file=testconfig/ebean-sqlserver17.properties
- name: sqlserver 2022
run: mvn -T 8 clean test -Dprops.file=testconfig/ebean-sqlserver.properties
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.10.0</version>
<version>16.2.1</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-clickhouse</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.10.0</version>
<version>16.2.1</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.10.0</version>
<version>16.2.1</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-db2</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.10.0</version>
<version>16.2.1</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.10.0</version>
<version>16.2.1</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-hana</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.10.0</version>
<version>16.2.1</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-mariadb</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.10.0</version>
<version>16.2.1</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-mysql</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
</dependencies>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.10.0</version>
<version>16.2.1</version>
<relativePath>../..</relativePath>
</parent>
@@ -22,13 +22,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
@@ -47,19 +47,19 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-net-postgis-types</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.10.0</version>
<version>16.2.1</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-nuodb</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.10.0</version>
<version>16.2.1</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-oracle</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
</dependencies>
+85
View File
@@ -0,0 +1,85 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>16.2.1</version>
<relativePath>../..</relativePath>
</parent>
<name>ebean-pgvector</name>
<description>ebean-pgvector composite</description>
<artifactId>ebean-pgvector</artifactId>
<properties>
<pgvector.version>0.1.6</pgvector.version>
<postgres.jdbc.version>42.7.2</postgres.jdbc.version>
</properties>
<dependencies>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-datasource</artifactId>
<version>${ebean-datasource.version}</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-migration</artifactId>
<version>${ebean-migration.version}</version>
</dependency>
<!-- Technically optional but most expected to use query beans -->
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-pgvector-types</artifactId>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>${postgres.jdbc.version}</version>
<exclusions>
<!-- exclude unnecessary checker framework -->
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.pgvector</groupId>
<artifactId>pgvector</artifactId>
<version>${pgvector.version}</version>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,7 @@
package io.ebean.pgvector.assembly;
/**
* Nothing interesting here - required placeholder for javadoc.
*/
public class Assembly {
}
@@ -0,0 +1,9 @@
module io.ebean.pgvector {
requires transitive io.ebean.api;
requires transitive io.ebean.core;
requires transitive io.ebean.datasource;
requires transitive io.ebean.querybean;
requires transitive io.ebean.platform.postgres;
}
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.10.0</version>
<version>16.2.1</version>
<relativePath>../..</relativePath>
</parent>
@@ -22,13 +22,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
@@ -47,19 +47,19 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgis-types</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.10.0</version>
<version>16.2.1</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.10.0</version>
<version>16.2.1</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlite</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.10.0</version>
<version>16.2.1</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlserver</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.10.0</version>
<version>16.2.1</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
@@ -42,13 +42,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
</dependencies>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.10.0</version>
<version>16.2.1</version>
<relativePath>../..</relativePath>
</parent>
@@ -17,13 +17,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
@@ -41,7 +41,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-jackson-mapper</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
@@ -60,13 +60,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-all</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
</dependencies>
+2 -1
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.10.0</version>
<version>16.2.1</version>
</parent>
<artifactId>composites</artifactId>
@@ -25,6 +25,7 @@
<module>ebean-postgres</module>
<module>ebean-postgis</module>
<module>ebean-net-postgis</module>
<module>ebean-pgvector</module>
<!-- <module>sqlanywhere</module>-->
<module>ebean-sqlite</module>
<module>ebean-sqlserver</module>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.10.0</version>
<version>16.2.1</version>
</parent>
<name>ebean api</name>
@@ -35,7 +35,7 @@
<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-config</artifactId>
<version>3.12</version>
<version>4.2</version>
</dependency>
<dependency>
@@ -137,6 +137,7 @@ public interface Database {
/**
* Return the associated read only DataSource for this Database instance (can be null).
*/
@Nullable
DataSource readOnlyDataSource();
/**
@@ -989,6 +989,14 @@ public interface DatabaseBuilder {
@Deprecated
DatabaseBuilder setNamingConvention(NamingConvention namingConvention);
/**
* Set the AggregateFormulaContext which is used to determine if a database function
* is an aggregate function (like sum, min, max, avg etc).
* <p>
* Use this to override the default known aggregation functions.
*/
DatabaseConfig aggregateFormulaContext(AggregateFormulaContext aggregateFormulaContext);
/**
* Set to true if all DB column and table names should use quoted identifiers.
* <p>
@@ -1062,6 +1070,11 @@ public interface DatabaseBuilder {
*/
DatabaseBuilder readOnlyDatabase(boolean readOnlyDatabase);
/**
* Set to false such that the instance does not register a JVM shutdown hook.
*/
DatabaseBuilder shutdownHook(boolean shutdownHook);
/**
* Set a DataSource.
*/
@@ -2019,6 +2032,11 @@ public interface DatabaseBuilder {
@Deprecated
DatabaseBuilder setQueryPlanTTLSeconds(int queryPlanTTLSeconds);
/**
* Set the EXPLAIN (with options) to use for query plan capture.
*/
DatabaseBuilder queryPlanExplain(String queryPlanExplain);
/**
* Create a new PlatformConfig based of the one held but with overridden properties by reading
* properties with the given path and prefix.
@@ -2600,6 +2618,11 @@ public interface DatabaseBuilder {
*/
NamingConvention getNamingConvention();
/**
* Return the AggregateFormulaContext.
*/
AggregateFormulaContext aggregateFormulaContext();
/**
* Return true if all DB column and table names should use quoted identifiers.
*/
@@ -2638,6 +2661,11 @@ public interface DatabaseBuilder {
*/
boolean readOnlyDatabase();
/**
* Return if a JVM shutdown hook should be registered.
*/
boolean shutdownHook();
/**
* Return the DataSource.
*/
@@ -3044,6 +3072,11 @@ public interface DatabaseBuilder {
*/
int getQueryPlanTTLSeconds();
/**
* Return the EXPLAIN (with options) to use for capturing query plans.
*/
String getQueryPlanExplain();
/**
* Return mapping locations to search for xml mapping via class path search.
*/
+12 -1
View File
@@ -234,5 +234,16 @@ public interface DtoQuery<T> extends CancelableQuery {
* source. We use {@code usingMaster()} to instead ensure that the query is executed
* against the master data source.
*/
DtoQuery<T> usingMaster();
default DtoQuery<T> usingMaster() {
return usingMaster(true);
}
/**
* Ensure the master DataSource is used when useMaster is true. Otherwise, the read only
* data source can be used if defined.
*
* @see #usingMaster()
*/
DtoQuery<T> usingMaster(boolean useMaster);
}
@@ -0,0 +1,74 @@
package io.ebean;
import jakarta.persistence.PersistenceException;
import java.util.Map;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
* FutureMap represents the result of a background query execution that will
* return a map of entities.
* <p>
* It extends the java.util.concurrent.Future with the ability to cancel the
* query, check if it is finished and get the resulting list waiting for the
* query to finish (ie. the standard features of java.util.concurrent.Future).
* </p>
* <p>
* A simple example:
* </p>
* <pre>{@code
*
* // create a query to find all orders
* Query<Long,Order> query = DB.find(Order.class)
* .setMapKey("id");
*
* // execute the query in a background thread
* // immediately returning the futureMap
* FutureMap<Long,Order> futureMap = query.findFutureMap();
*
* // do something else ...
*
* if (!futureMap.isDone()){
* // we can cancel the query execution. This will cancel
* // the underlying query if that is supported by the JDBC
* // driver and database
* futureMap.cancel(true);
* }
*
* if (!futureMap.isCancelled()){
* // wait for the query to finish and return the map
* Map<Long,Order> map = futureMap.get();
* ...
* }
*
* }</pre>
*/
public interface FutureMap<K, T> extends Future<Map<K, T>> {
/**
* Return the query that is being executed by a background thread.
*/
Query<T> getQuery();
/**
* Same as {@link #get()} but wraps InterruptedException and ExecutionException in the
* unchecked PersistenceException.
*
* @return The query list result
* @throws PersistenceException when a InterruptedException or ExecutionException occurs.
*/
Map<K, T> getUnchecked();
/**
* Same as {@link #get(long, TimeUnit)} but wraps InterruptedException
* and ExecutionException in the unchecked PersistenceException.
*
* @return The query list result
* @throws TimeoutException if the wait timed out
* @throws PersistenceException if a InterruptedException or ExecutionException occurs.
*/
Map<K, T> getUnchecked(long timeout, TimeUnit unit) throws TimeoutException;
}
@@ -1,6 +1,7 @@
package io.ebean;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
/**
* Object relational query for finding a List, Set, Map or single entity bean.
@@ -310,6 +311,7 @@ public interface Query<T> extends CancelableQuery, QueryBuilder<Query<T>, T> {
/**
* Return the Id value.
*/
@Nullable
Object getId();
/**
@@ -446,11 +448,13 @@ public interface Query<T> extends CancelableQuery, QueryBuilder<Query<T>, T> {
/**
* Return the "for update" wait mode to use.
*/
@Nullable
LockWait getForUpdateLockWait();
/**
* Return the lock type (strength) to use with "for update".
*/
@Nullable
LockType getForUpdateLockType();
/**
@@ -135,7 +135,17 @@ public interface QueryBuilder<SELF extends QueryBuilder<SELF, T>, T> extends Que
* source. We we use {@code usingMaster()} to instead ensure that the query is executed
* against the master data source.
*/
SELF usingMaster();
default SELF usingMaster() {
return usingMaster(true);
}
/**
* Ensure the master DataSource is used when useMaster is true. Otherwise, the read only
* data source can be used if defined.
*
* @see #usingMaster()
*/
SELF usingMaster(boolean useMaster);
/**
* Set the base table to use for this query.
@@ -393,6 +403,12 @@ public interface QueryBuilder<SELF extends QueryBuilder<SELF, T>, T> extends Que
* This means that the returning graph can't be mutated via setters, all the collections
* are unmodifiable collections, lazy loading is disabled and that the query uses
* {@link PersistenceContextScope#QUERY}.
* <p>
* Attempting to mutate an unmodifiable bean will throw a <code>UnmodifiableEntityException</code>.
* Attempting to load an unloaded property will throw a <code>LazyInitialisationException</code>
*
* @see LazyInitialisationException
* @see UnmodifiableEntityException
*/
SELF setUnmodifiable(boolean unmodifiable);
@@ -441,6 +457,16 @@ public interface QueryBuilder<SELF extends QueryBuilder<SELF, T>, T> extends Que
/**
* Set the {@link CacheMode} to use the query for executing this query.
* <p>
* Since version 16.x using the query bean will set the query to use unmodifiable (see
* {@link #setUnmodifiable(boolean)}) so the returned object graph is unmodifiable
* and safe to cache by the application.
* <p>
* Attempting to mutate an unmodifiable bean will throw a <code>UnmodifiableEntityException</code>.
* Attempting to load an unloaded property will throw a <code>LazyInitialisationException</code>
*
* @see LazyInitialisationException
* @see UnmodifiableEntityException
*/
SELF setUseQueryCache(CacheMode cacheMode);
@@ -956,6 +982,16 @@ public interface QueryBuilder<SELF extends QueryBuilder<SELF, T>, T> extends Que
*/
FutureList<T> findFutureList();
/**
* Execute find map query in a background thread.
* <p>
* This query will execute in it's own PersistenceContext and using its own transaction.
* What that means is that it will not share any bean instances with other queries.
*
* @return a Future object for the map result of the query
*/
<K> FutureMap<K,T> findFutureMap();
/**
* Return a PagedList for this query using firstRow and maxRows.
* <p>
+11 -1
View File
@@ -63,7 +63,17 @@ public interface SqlQuery extends Serializable, CancelableQuery {
* source. We use {@code usingMaster()} to instead ensure that the query is executed
* against the master data source.
*/
SqlQuery usingMaster();
default SqlQuery usingMaster() {
return usingMaster(true);
}
/**
* Ensure the master DataSource is used when useMaster is true. Otherwise, the read only
* data source can be used if defined.
*
* @see #usingMaster()
*/
SqlQuery usingMaster(boolean useMaster);
/**
* Execute the query returning a list.
@@ -381,6 +381,11 @@ public interface EntityBeanIntercept extends Serializable {
*/
void loadBean(int loadProperty);
/**
* Invoke the lazy loading. This method is synchronised externally.
*/
void loadBeanInternal(int loadProperty, BeanLoader loader);
/**
* Called when a BeanCollection is initialised automatically.
*/
@@ -393,6 +393,11 @@ public final class InterceptReadOnly extends InterceptBase {
}
@Override
public void loadBeanInternal(int loadProperty, BeanLoader loader) {
}
@Override
public void initialisedMany(int propertyIndex) {
loaded[propertyIndex] = true;
@@ -2,7 +2,6 @@ package io.ebean.bean;
import io.ebean.DB;
import io.ebean.Database;
import io.ebean.LazyInitialisationException;
import io.ebean.ValuePair;
import jakarta.persistence.EntityNotFoundException;
@@ -60,7 +59,7 @@ public final class InterceptReadWrite extends InterceptBase {
private EntityBean embeddedOwner;
private int embeddedOwnerIndex;
/**
* One of NEW, REFERENCE, LOADED.
* One of NEW, REF, UPD.
*/
private int state;
private boolean forceUpdate;
@@ -646,9 +645,6 @@ public final class InterceptReadWrite extends InterceptBase {
public void loadBean(int loadProperty) {
lock.lock();
try {
if (disableLazyLoad) {
throw new LazyInitialisationException("Property not loaded: " + property(loadProperty));
}
if (beanLoader == null) {
final Database database = DB.byName(ebeanServerName);
if (database == null) {
@@ -672,7 +668,8 @@ public final class InterceptReadWrite extends InterceptBase {
}
}
private void loadBeanInternal(int loadProperty, BeanLoader loader) {
@Override
public void loadBeanInternal(int loadProperty, BeanLoader loader) {
if ((flags[loadProperty] & FLAG_LOADED_PROP) != 0) {
// race condition where multiple threads calling preGetter concurrently
return;
@@ -774,7 +771,7 @@ public final class InterceptReadWrite extends InterceptBase {
@Override
public void preGetter(int propertyIndex) {
preGetterCallback(propertyIndex);
if (state == STATE_NEW) {
if (state == STATE_NEW || disableLazyLoad) {
return;
}
if (!isLoadedProperty(propertyIndex)) {
@@ -1,5 +1,6 @@
package io.ebean.cache;
import java.time.Instant;
import java.util.Set;
/**
@@ -10,11 +11,11 @@ import java.util.Set;
* the query cache entry is treated as invalid.
* </p>
*/
public class QueryCacheEntry {
public final class QueryCacheEntry {
private final Object value;
private final Set<String> dependentTables;
private final long timestamp;
private final Instant timestamp;
/**
* Create with dependent tables and timestamp.
@@ -23,7 +24,7 @@ public class QueryCacheEntry {
* @param dependentTables The extra tables the query is dependent on (joins to)
* @param timestamp The timestamp that the query uses to check for modifications
*/
public QueryCacheEntry(Object value, Set<String> dependentTables, long timestamp) {
public QueryCacheEntry(Object value, Set<String> dependentTables, Instant timestamp) {
this.value = value;
this.dependentTables = dependentTables;
this.timestamp = timestamp;
@@ -32,21 +33,21 @@ public class QueryCacheEntry {
/**
* Return the actual query result.
*/
public Object getValue() {
public Object value() {
return value;
}
/**
* Return the tables the query result is dependent on.
*/
public Set<String> getDependentTables() {
public Set<String> dependentTables() {
return dependentTables;
}
/**
* Return the timestamp used to check for modifications on the dependent tables.
*/
public long getTimestamp() {
public Instant timestamp() {
return timestamp;
}
}
@@ -0,0 +1,66 @@
package io.ebean.config;
import java.util.Set;
/**
* Used when parsing formulas to determine if they are aggregation formulas like
* sum, min, max, avg, count etc.
* <p>
* Ebean needs to determine if they are aggregation formulas to determine which
* properties should be included in a GROUP BY clause etc.
*/
public interface AggregateFormulaContext {
/**
* Return true if the outer function is an aggregate function (like sum, count, min, max, avg etc).
*/
boolean isAggregate(String outerFunction);
/**
* Return true if the aggregate function returns a BIGINT type.
* This is true for functions like count that return a numeric value regardless of the
* type of the property or expression inside the outer function.
*/
boolean isCount(String outerFunction);
/**
* Return true if the aggregate function returns a VARCHAR type.
* This is true for functions that return a string concatenation like group_concat etc
* regardless of the type of the property used inside the outer function.
*/
boolean isConcat(String outerFunction);
/**
* Return a builder for the AggregateFormulaContext.
*/
static Builder builder() {
return new AggregateFormulaContextBuilder();
}
/**
* A builder for the AggregateFormulaContext.
*/
interface Builder {
/**
* Override the default set of aggregation functions.
*/
Builder aggregateFunctions(Set<String> count);
/**
* Override the default set of concat functions.
*/
Builder concatFunctions(Set<String> concat);
/**
* Override the default set of count functions.
*/
Builder countFunctions(Set<String> count);
/**
* Build the AggregateFormulaContext.
*/
AggregateFormulaContext build();
}
}
@@ -0,0 +1,61 @@
package io.ebean.config;
import java.util.Set;
final class AggregateFormulaContextBuilder implements AggregateFormulaContext.Builder {
private Set<String> aggFunctions = Set.of("count", "max", "min", "avg", "sum", "group_concat", "string_agg", "listagg");
private Set<String> concat = Set.of("concat", "group_concat", "string_agg", "listagg");
private Set<String> count = Set.of("count");
@Override
public AggregateFormulaContext.Builder aggregateFunctions(Set<String> agg) {
this.aggFunctions = agg;
return this;
}
@Override
public AggregateFormulaContext.Builder concatFunctions(Set<String> concat) {
this.concat = concat;
return this;
}
@Override
public AggregateFormulaContext.Builder countFunctions(Set<String> count) {
this.count = count;
return this;
}
@Override
public AggregateFormulaContext build() {
return new FormulaContext(aggFunctions, concat, count);
}
private static final class FormulaContext implements AggregateFormulaContext {
private final Set<String> aggFunctions;
private final Set<String> concat;
private final Set<String> count;
private FormulaContext(Set<String> aggFunctions, Set<String> concat, Set<String> count) {
this.aggFunctions = aggFunctions;
this.concat = concat;
this.count = count;
}
@Override
public boolean isAggregate(String outerFunction) {
return aggFunctions.contains(outerFunction);
}
@Override
public boolean isCount(String outerFunction) {
return count.contains(outerFunction);
}
@Override
public boolean isConcat(String outerFunction) {
return concat.contains(outerFunction);
}
}
}
@@ -251,7 +251,7 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
/**
* The default batch size for lazy loading
*/
private int lazyLoadBatchSize = 10;
private int lazyLoadBatchSize = 100;
/**
* The default batch size for 'query joins'.
@@ -311,6 +311,7 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
private boolean skipDataSourceCheck;
private boolean readOnlyDatabase;
private boolean shutdownHook = true;
/**
* The data source (if programmatically provided).
@@ -355,6 +356,8 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
*/
private NamingConvention namingConvention = new UnderscoreNamingConvention();
private AggregateFormulaContext aggregateFormulaContext = AggregateFormulaContext.builder().build();
/**
* Behaviour of updates in JDBC batch to by default include all properties.
*/
@@ -481,6 +484,7 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
* Time to live for query plans - defaults to 5 minutes.
*/
private int queryPlanTTLSeconds = 60 * 5;
private String queryPlanExplain;
/**
* Set to true to globally disable L2 caching (typically for performance testing).
@@ -1277,6 +1281,17 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
return this;
}
@Override
public AggregateFormulaContext aggregateFormulaContext() {
return aggregateFormulaContext;
}
@Override
public DatabaseConfig aggregateFormulaContext(AggregateFormulaContext aggregateFormulaContext) {
this.aggregateFormulaContext = aggregateFormulaContext;
return this;
}
@Override
public boolean isAllQuotedIdentifiers() {
return platformConfig.isAllQuotedIdentifiers();
@@ -1364,6 +1379,17 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
return readOnlyDatabase;
}
@Override
public DatabaseBuilder shutdownHook(boolean shutdownHook) {
this.shutdownHook = shutdownHook;
return this;
}
@Override
public boolean shutdownHook() {
return shutdownHook;
}
@Override
public DataSource getDataSource() {
return dataSource;
@@ -2136,6 +2162,7 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
loadDocStoreSettings(p);
defaultServer = p.getBoolean("defaultServer", defaultServer);
shutdownHook = p.getBoolean("shutdownHook", shutdownHook);
readOnlyDatabase = p.getBoolean("readOnlyDatabase", readOnlyDatabase);
autoPersistUpdates = p.getBoolean("autoPersistUpdates", autoPersistUpdates);
loadModuleInfo = p.getBoolean("loadModuleInfo", loadModuleInfo);
@@ -2151,6 +2178,7 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
queryPlanCapturePeriodSecs = p.getLong("queryPlan.capturePeriodSecs", queryPlanCapturePeriodSecs);
queryPlanCaptureMaxTimeMillis = p.getLong("queryPlan.captureMaxTimeMillis", queryPlanCaptureMaxTimeMillis);
queryPlanCaptureMaxCount = p.getInt("queryPlan.captureMaxCount", queryPlanCaptureMaxCount);
queryPlanExplain = p.get("queryPlan.explain", queryPlanExplain);
docStoreOnly = p.getBoolean("docStoreOnly", docStoreOnly);
disableL2Cache = p.getBoolean("disableL2Cache", disableL2Cache);
localOnlyL2Cache = p.getBoolean("localOnlyL2Cache", localOnlyL2Cache);
@@ -2402,6 +2430,17 @@ public class DatabaseConfig implements DatabaseBuilder.Settings {
return queryPlanTTLSeconds;
}
@Override
public String getQueryPlanExplain() {
return queryPlanExplain;
}
@Override
public DatabaseBuilder queryPlanExplain(String queryPlanExplain) {
this.queryPlanExplain = queryPlanExplain;
return this;
}
@Override
public DatabaseConfig setQueryPlanTTLSeconds(int queryPlanTTLSeconds) {
this.queryPlanTTLSeconds = queryPlanTTLSeconds;
@@ -167,6 +167,7 @@ public class DatabasePlatform {
* findIterate() and findVisit().
*/
protected boolean forwardOnlyHintOnFindIterate;
protected boolean autoCommitFalseOnFindIterate;
/**
* If set then use the CONCUR_UPDATABLE hint when creating ResultSets.
@@ -528,6 +529,10 @@ public class DatabasePlatform {
this.forwardOnlyHintOnFindIterate = forwardOnlyHintOnFindIterate;
}
public boolean autoCommitFalseOnFindIterate() {
return autoCommitFalseOnFindIterate;
}
/**
* Return true if the ResultSet CONCUR_UPDATABLE Hint should be used on
* createNativeSqlTree() PreparedStatements.
@@ -780,4 +785,5 @@ public class DatabasePlatform {
public String inlineSqlHint(String hint) {
return "/*+ " + hint + " */ ";
}
}
@@ -46,6 +46,11 @@ public class DbPlatformTypeMapping {
private static final DbPlatformType MULTILINESTRING = new DbPlatformType("multilinestring");
private static final DbPlatformType MULTIPOLYGON = new DbPlatformType("multipolygon");
private static final DbPlatformType VECTOR = new DbPlatformType("vector", 2000, null);
private static final DbPlatformType VECTOR_HALF = new DbPlatformType("halfvec", 4000, null);
private static final DbPlatformType VECTOR_BIT = new DbPlatformType("bit", 64000, null);
private static final DbPlatformType VECTOR_SPARSE = new DbPlatformType("sparsevec", 1000, null);
private final Map<DbType, DbPlatformType> typeMap = new EnumMap<>(DbType.class);
/**
@@ -93,6 +98,10 @@ public class DbPlatformTypeMapping {
put(DbType.MULTIPOINT, MULTIPOINT);
put(DbType.MULTILINESTRING, MULTILINESTRING);
put(DbType.MULTIPOLYGON, MULTIPOLYGON);
put(DbType.VECTOR, VECTOR);
put(DbType.VECTOR_HALF, VECTOR_HALF);
put(DbType.VECTOR_BIT, VECTOR_BIT);
put(DbType.VECTOR_SPARSE, VECTOR_SPARSE);
if (logicalTypes) {
// keep it logical for 2 layer DDL generation
@@ -51,7 +51,12 @@ public enum DbType {
JSONB(ExtraDbTypes.JSONB),
JSONCLOB(ExtraDbTypes.JSONClob),
JSONBLOB(ExtraDbTypes.JSONBlob),
JSONVARCHAR(ExtraDbTypes.JSONVarchar);
JSONVARCHAR(ExtraDbTypes.JSONVarchar),
VECTOR(ExtraDbTypes.VECTOR),
VECTOR_HALF(ExtraDbTypes.VECTOR_HALF),
VECTOR_BIT(ExtraDbTypes.VECTOR_BIT),
VECTOR_SPARSE(ExtraDbTypes.VECTOR_SPARSE);
private final int id;
@@ -74,4 +74,24 @@ public interface ExtraDbTypes {
*/
int MULTILINESTRING = 6007;
/**
* PGVector base type
*/
int VECTOR = 7000;
/**
* PGVector half precision float type
*/
int VECTOR_HALF = 7001;
/**
* PGVector binary type (bit)
*/
int VECTOR_BIT = 7002;
/**
* PGVector sparse type
*/
int VECTOR_SPARSE = 7003;
}
@@ -97,8 +97,7 @@ public final class ShutdownManager {
private static void registerShutdownHook() {
lock.lock();
try {
String value = System.getProperty("ebean.registerShutdownHook");
if (value == null || !value.trim().equalsIgnoreCase("false")) {
if ("true".equalsIgnoreCase(System.getProperty("ebean.registerShutdownHook", "true"))) {
Runtime.getRuntime().addShutdownHook(shutdownHook);
}
} catch (IllegalStateException ex) {
@@ -1,18 +1,19 @@
package io.ebean.meta;
import java.util.HashSet;
import java.util.Set;
import java.util.*;
import static java.util.Objects.requireNonNull;
/**
* Initiate query plan collection for plans by their hash or all query plans.
*/
public class QueryPlanInit {
private final Map<String,Long> hashes = new HashMap<>();
private boolean all;
private Set<String> hashes = new HashSet<>();
private long thresholdMicros;
private long defaultThresholdMicros;
/**
* Return true if this initiates bind collection on all query plans.
@@ -29,39 +30,74 @@ public class QueryPlanInit {
}
/**
* Return the query execution time threshold which must be exceeded to initiate
* Return the default query execution time threshold which must be exceeded to initiate
* query plan collection.
*/
public long thresholdMicros() {
return thresholdMicros;
return defaultThresholdMicros;
}
/**
* Set the query execution time threshold which must be exceeded to initiate
* Set the default query execution time threshold which must be exceeded to initiate
* query plan collection.
*/
public void thresholdMicros(long thresholdMicros) {
this.thresholdMicros = thresholdMicros;
this.defaultThresholdMicros = thresholdMicros;
}
/**
* Return true if the query plan should be initiated based on it's hash.
*/
public boolean includeHash(String hash) {
return all || hashes.contains(hash);
return all || hashes.containsKey(hash);
}
/**
* Return the specific hashes that we want to collect query plans on.
*
* @param hash The hash of the query plan.
* @param thresholdMicros The threshold in micros to use.
*/
public Set<String> hashes() {
return hashes;
public void add(String hash, long thresholdMicros) {
requireNonNull(hash);
if (!"all".equals(hash)) {
hashes.put(hash, thresholdMicros);
} else {
all = true;
if (thresholdMicros > 0) {
defaultThresholdMicros = thresholdMicros;
}
}
}
/**
* Set the specific hashes that we want to collect query plans on.
* Remove a hash from this request.
*/
public void hashes(Set<String> hashes) {
this.hashes = hashes;
public void remove(String hash) {
hashes.remove(hash);
}
/**
* Return the threshold in micros to use for the given hash.
*/
public long thresholdMicros(String hash) {
Long threshold = hashes.get(hash);
return threshold == null || threshold < 1 ? defaultThresholdMicros : threshold;
}
/**
* Return true if there are no registered hashes and not collect <em>All</em> plans.
*/
public boolean isEmpty() {
return !all && hashes.isEmpty();
}
@Override
public String toString() {
return "QueryPlanInit{" +
"all=" + all +
", hashes=" + hashes +
", thresholdMicros=" + defaultThresholdMicros +
'}';
}
}
@@ -0,0 +1,65 @@
package io.ebean.config;
import org.junit.jupiter.api.Test;
import java.util.List;
import java.util.Set;
import static org.assertj.core.api.Assertions.assertThat;
class AggregateFormulaContextTest {
@Test
void defaultContext() {
var defaultContext = AggregateFormulaContext.builder().build();
for (String aggFunction : List.of("count", "max", "min", "avg", "sum", "group_concat", "string_agg", "listagg")) {
assertThat(defaultContext.isAggregate(aggFunction)).isTrue();
}
for (String c : List.of("concat", "group_concat", "string_agg", "listagg")) {
assertThat(defaultContext.isConcat(c)).isTrue();
}
for (String c : List.of("count")) {
assertThat(defaultContext.isCount(c)).isTrue();
}
assertThat(defaultContext.isConcat("junk")).isFalse();
assertThat(defaultContext.isCount("junk")).isFalse();
assertThat(defaultContext.isAggregate("junk")).isFalse();
}
@Test
void overrideAggregateFunctions() {
AggregateFormulaContext mySum = AggregateFormulaContext.builder()
.aggregateFunctions(Set.of("my_sum"))
.build();
assertThat(mySum.isAggregate("my_sum")).isTrue();
assertThat(mySum.isAggregate("avg")).isFalse();
assertThat(mySum.isCount("count")).isTrue();
assertThat(mySum.isConcat("group_concat")).isTrue();
}
@Test
void overrideConcatFunctions() {
AggregateFormulaContext myConcat = AggregateFormulaContext.builder()
.concatFunctions(Set.of("my_concat"))
.build();
assertThat(myConcat.isAggregate("avg")).isTrue();
assertThat(myConcat.isCount("count")).isTrue();
assertThat(myConcat.isConcat("group_concat")).isFalse();
assertThat(myConcat.isConcat("my_concat")).isTrue();
}
@Test
void overrideCountFunctions() {
AggregateFormulaContext myCount = AggregateFormulaContext.builder()
.countFunctions(Set.of("my_count"))
.build();
assertThat(myCount.isAggregate("avg")).isTrue();
assertThat(myCount.isCount("count")).isFalse();
assertThat(myCount.isCount("my_count")).isTrue();
assertThat(myCount.isConcat("group_concat")).isTrue();
}
}
@@ -77,6 +77,9 @@ class DatabaseConfigTest {
props.setProperty("readOnlyDatabase", "true");
props.setProperty("lengthCheck", "ON");
props.setProperty("includeLabelInSql", "false");
props.setProperty("lazyLoadBatchSize", "50");
props.setProperty("queryBatchSize", "60");
props.setProperty("shutdownHook", "false");
props.setProperty("queryPlan.enable", "true");
props.setProperty("queryPlan.thresholdMicros", "10000");
@@ -84,6 +87,7 @@ class DatabaseConfigTest {
props.setProperty("queryPlan.capturePeriodSecs", "42");
props.setProperty("queryPlan.captureMaxTimeMillis", "560");
props.setProperty("queryPlan.captureMaxCount", "7");
props.setProperty("queryPlan.explain", "explain (verbose)");
config.loadFromProperties(props);
@@ -97,8 +101,11 @@ class DatabaseConfigTest {
assertTrue(settings.isLoadModuleInfo());
assertTrue(settings.skipDataSourceCheck());
assertTrue(settings.readOnlyDatabase());
assertFalse(settings.shutdownHook());
assertFalse(settings.isIncludeLabelInSql());
assertThat(settings.getLengthCheck()).isEqualTo(LengthCheck.ON);
assertThat(settings.getLazyLoadBatchSize()).isEqualTo(50);
assertThat(settings.getQueryBatchSize()).isEqualTo(60);
assertTrue(settings.isIdGeneratorAutomatic());
assertFalse(settings.getPlatformConfig().isCaseSensitiveCollation());
@@ -129,15 +136,18 @@ class DatabaseConfigTest {
assertEquals(42, settings.getQueryPlanCapturePeriodSecs());
assertEquals(560, settings.getQueryPlanCaptureMaxTimeMillis());
assertEquals(7, settings.getQueryPlanCaptureMaxCount());
assertEquals("explain (verbose)", settings.getQueryPlanExplain());
assertThat(settings.getMappingLocations()).containsExactly("classpath:/foo","bar");
config.persistBatch(PersistBatch.NONE)
.persistBatchOnCascade(PersistBatch.NONE)
.lengthCheck(LengthCheck.ON)
.lengthCheck(LengthCheck.UTF8);
.lengthCheck(LengthCheck.UTF8)
.queryPlanExplain("explain (buffers)");
assertThat(config.settings().getQueryPlanExplain()).isEqualTo("explain (buffers)");
Properties props1 = new Properties();
props1.setProperty("ebean.persistBatch", "ALL");
props1.setProperty("ebean.persistBatchOnCascade", "ALL");
@@ -164,6 +174,7 @@ class DatabaseConfigTest {
DatabaseBuilder.Settings config = new DatabaseConfig().settings();
assertTrue(config.isIdGeneratorAutomatic());
assertTrue(config.isDefaultServer());
assertTrue(config.shutdownHook());
assertFalse(config.isAutoPersistUpdates());
assertFalse(config.skipDataSourceCheck());
@@ -175,6 +186,8 @@ class DatabaseConfigTest {
assertTrue(config.getPlatformConfig().isCaseSensitiveCollation());
assertTrue(config.isAutoLoadModuleInfo());
assertTrue(config.isLoadModuleInfo());
assertThat(config.getLazyLoadBatchSize()).isEqualTo(100);
assertThat(config.getQueryBatchSize()).isEqualTo(100);
assertFalse(config.isQueryPlanEnable());
assertEquals(Long.MAX_VALUE, config.getQueryPlanThresholdMicros());
@@ -182,9 +195,12 @@ class DatabaseConfigTest {
assertEquals(600, config.getQueryPlanCapturePeriodSecs());
assertEquals(10000L, config.getQueryPlanCaptureMaxTimeMillis());
assertEquals(10, config.getQueryPlanCaptureMaxCount());
assertThat(config.getQueryPlanExplain()).isNull();
assertThat(config.getLengthCheck()).isEqualTo(LengthCheck.OFF);
assertTrue(config.isIncludeLabelInSql());
config.shutdownHook(false);
assertFalse(config.shutdownHook());
config.setLoadModuleInfo(false);
assertFalse(config.isAutoLoadModuleInfo());
assertFalse(config.isLoadModuleInfo());
@@ -192,6 +208,10 @@ class DatabaseConfigTest {
assertTrue(config.isAutoPersistUpdates());
config.setSkipDataSourceCheck(true);
assertTrue(config.skipDataSourceCheck());
config.lazyLoadBatchSize(20);
assertThat(config.getLazyLoadBatchSize()).isEqualTo(20);
config.queryBatchSize(30);
assertThat(config.getQueryBatchSize()).isEqualTo(30);
}
@Test
@@ -0,0 +1,43 @@
package io.ebean.meta;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
class QueryPlanInitTest {
@Test
void initialQueryPlanInit() {
var init = new QueryPlanInit();
assertThat(init.isEmpty()).isTrue();
assertThat(init.isAll()).isFalse();
assertThat(init.thresholdMicros()).isEqualTo(0L);
}
@Test
void add_all() {
var init = new QueryPlanInit();
init.add("all", 57L);
assertThat(init.isEmpty()).isFalse();
assertThat(init.isAll()).isTrue();
assertThat(init.thresholdMicros()).isEqualTo(57L);
}
@Test
void addWithThresholds() {
var init = new QueryPlanInit();
init.thresholdMicros(1000);
init.add("xOne", 0);
init.add("xTwo", 2000L);
assertThat(init.isEmpty()).isFalse();
assertThat(init.isAll()).isFalse();
assertThat(init.includeHash("xJunk")).isFalse();
assertThat(init.includeHash("xOne")).isTrue();
assertThat(init.includeHash("xTwo")).isTrue();
assertThat(init.thresholdMicros("xJunk")).isEqualTo(1000L);
assertThat(init.thresholdMicros("xOne")).isEqualTo(1000L);
assertThat(init.thresholdMicros("xTwo")).isEqualTo(2000L);
}
}
+38 -26
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.10.0</version>
<version>16.2.1</version>
</parent>
<name>ebean bom</name>
@@ -89,25 +89,25 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
@@ -125,13 +125,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-jackson-mapper</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
@@ -155,37 +155,37 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>kotlin-querybean-generator</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-redis</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-spring-txn</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<!-- platforms -->
@@ -193,79 +193,91 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-clickhouse</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-db2</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-h2</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-hana</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-mariadb</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-mysql</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-nuodb</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-oracle</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgres</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgis</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgis-types</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-pgvector</artifactId>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-pgvector-types</artifactId>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-sqlite</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-sqlserver</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
</dependencies>
+32
View File
@@ -0,0 +1,32 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>io.ebean</groupId>
<artifactId>ebean-parent</artifactId>
<version>16.2.1</version>
</parent>
<artifactId>ebean-core-json</artifactId>
<name>ebean-core-json</name>
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>HEAD</tag>
</scm>
<dependencies>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>16.2.1</version>
</dependency>
<!-- Jackson core used internally by Ebean -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson.version}</version>
<optional>true</optional>
</dependency>
</dependencies>
</project>
@@ -8,11 +8,7 @@ import io.ebean.service.SpiJsonService;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
/**
* Utility that converts between JSON content and simple java Maps/Lists.
@@ -52,8 +48,8 @@ public final class DJsonService implements SpiJsonService {
}
/**
* Parse the json and return as a Map additionally specifying if the returned map should
* be modify aware meaning that it can detect when it has been modified.
* Parse the json and return as a Map additionally specifying if the returned map should be modify
* aware meaning that it can detect when it has been modified.
*/
@Override
public Map<String, Object> parseObject(String json, boolean modifyAware) throws IOException {
@@ -94,9 +90,8 @@ public final class DJsonService implements SpiJsonService {
/**
* Parse the json and return as a Map taking a JsonParser and a starting token.
* <p>
* Used when the first token is checked to see if the value is null prior to calling this.
* </p>
*
* <p>Used when the first token is checked to see if the value is null prior to calling this.
*/
@Override
public Map<String, Object> parseObject(JsonParser parser, JsonToken token) throws IOException {
@@ -8,15 +8,23 @@ import io.ebean.ModifyAwareType;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.*;
final class EJsonReader {
static final JsonFactory json = new JsonFactory();
private final JsonParser parser;
private final boolean modifyAware;
private final ModifyAwareFlag modifyAwareOwner;
private int depth;
private Stack stack;
private Context currentContext;
EJsonReader(JsonParser parser, boolean modifyAware) {
this.parser = parser;
this.modifyAware = modifyAware;
this.modifyAwareOwner = modifyAware ? new ModifyAwareFlag() : null;
}
@SuppressWarnings("unchecked")
static Map<String, Object> parseObject(String json, boolean modifyAware) throws IOException {
@@ -102,24 +110,6 @@ final class EJsonReader {
return new EJsonReader(parser, modifyAware).parseJson(token);
}
private final JsonParser parser;
private final boolean modifyAware;
private final ModifyAwareFlag modifyAwareOwner;
private int depth;
private Stack stack;
private Context currentContext;
EJsonReader(JsonParser parser, boolean modifyAware) {
this.parser = parser;
this.modifyAware = modifyAware;
this.modifyAwareOwner = (modifyAware) ? new ModifyAwareFlag() : null;
}
private void startArray() {
depth++;
stack.push(currentContext);
@@ -197,7 +187,6 @@ final class EJsonReader {
*/
private void processJsonToken(JsonToken token) throws IOException {
switch (token) {
case START_ARRAY:
startArray();
break;
@@ -273,17 +262,17 @@ final class EJsonReader {
}
}
private static abstract class Context {
private abstract static class Context {
Context next;
abstract void popContext(Context temp);
abstract Object getValue();
abstract void setKey(String key);
abstract void setValue(Object value);
abstract void setKey(String key);
abstract void setValueNull();
}
@@ -312,13 +301,13 @@ final class EJsonReader {
}
@Override
void setKey(String key) {
this.key = key;
void setValue(Object value) {
map.put(key, value);
}
@Override
void setValue(Object value) {
map.put(key, value);
void setKey(String key) {
this.key = key;
}
@Override
@@ -364,5 +353,4 @@ final class EJsonReader {
// not expected
}
}
}
@@ -20,6 +20,11 @@ final class EJsonWriter {
* Base jsonFactory implementation used when it is not passed in.
*/
static final JsonFactory jsonFactory = new JsonFactory();
private final JsonGenerator jsonGenerator;
private EJsonWriter(JsonGenerator jsonGenerator) {
this.jsonGenerator = jsonGenerator;
}
static String write(Object object) throws IOException {
StringWriter writer = new StringWriter(200);
@@ -42,12 +47,6 @@ final class EJsonWriter {
new EJsonWriter(jsonGenerator).writeCollection(null, collection);
}
private final JsonGenerator jsonGenerator;
private EJsonWriter(JsonGenerator jsonGenerator) {
this.jsonGenerator = jsonGenerator;
}
private void writeJson(Object object) {
writeJson(null, object);
}
@@ -210,5 +209,4 @@ final class EJsonWriter {
}
jsonGenerator.writeEndObject();
}
}
@@ -22,5 +22,4 @@ public final class ModifyAwareFlag implements ModifyAwareType, Serializable {
public void setMarkedDirty(boolean markedDirty) {
this.markedDirty = markedDirty;
}
}
@@ -14,9 +14,8 @@ public final class ModifyAwareIterator<E> implements Iterator<E> {
/**
* Create with an Owner and the underlying Iterator this wraps.
* <p>
* The owner is notified of the removals.
* </p>
*
* <p>The owner is notified of the removals.
*/
public ModifyAwareIterator(ModifyAwareType owner, Iterator<E> it) {
this.owner = owner;
@@ -38,5 +37,4 @@ public final class ModifyAwareIterator<E> implements Iterator<E> {
owner.setMarkedDirty(true);
it.remove();
}
}
@@ -34,11 +34,11 @@ public final class ModifyAwareMap<K, V> implements Map<K, V>, ModifyAwareType, S
public boolean equals(Object o) {
if (this == o) return true;
if (o instanceof ModifyAwareMap) {
ModifyAwareMap<?,?> that = (ModifyAwareMap<?,?>) o;
ModifyAwareMap<?, ?> that = (ModifyAwareMap<?, ?>) o;
return Objects.equals(map, that.map);
}
if (!(o instanceof Map)) return false;
Map<?,?> that = (Map<?,?>) o;
Map<?, ?> that = (Map<?, ?>) o;
return Objects.equals(map, that);
}
@@ -112,7 +112,6 @@ public final class ModifyAwareMap<K, V> implements Map<K, V>, ModifyAwareType, S
map.putAll(m);
}
@Override
public void clear() {
if (!map.isEmpty()) {
@@ -135,5 +134,4 @@ public final class ModifyAwareMap<K, V> implements Map<K, V>, ModifyAwareType, S
public Set<Map.Entry<K, V>> entrySet() {
return new ModifyAwareSet<>(this, map.entrySet());
}
}
@@ -0,0 +1,9 @@
module io.ebean.core.json {
requires io.ebean.api;
requires transitive com.fasterxml.jackson.core;
exports io.ebeaninternal.json to io.ebean.test, io.ebean.core;
provides io.ebean.service.BootstrapService with io.ebeaninternal.json.DJsonService;
}
@@ -0,0 +1 @@
io.ebeaninternal.json.DJsonService
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.10.0</version>
<version>16.2.1</version>
</parent>
<artifactId>ebean-core-type</artifactId>
@@ -16,7 +16,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
+12 -6
View File
@@ -3,7 +3,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>14.10.0</version>
<version>16.2.1</version>
</parent>
<artifactId>ebean-core</artifactId>
@@ -22,7 +22,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-json</artifactId>
<version>16.2.1</version>
</dependency>
<dependency>
@@ -46,7 +52,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
</dependency>
<dependency>
@@ -159,21 +165,21 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlserver</artifactId>
<version>14.10.0</version>
<version>16.2.1</version>
<scope>test</scope>
</dependency>
@@ -1,5 +1,6 @@
package io.ebeaninternal.api;
import io.ebean.bean.EntityBean;
import java.util.ArrayList;
import java.util.List;
@@ -13,10 +14,23 @@ public final class BindValuesKey {
private final List<Object> values = new ArrayList<>();
private final SpiEbeanServer server;
public BindValuesKey(SpiEbeanServer server) {
this.server = server;
}
/**
* Add a bind value.
*/
public BindValuesKey add(Object value) {
if (value instanceof EntityBean) {
// only interested in id to keep the memory footprint low
Object id = server.beanId(value);
if (id != null) {
value = id;
}
}
values.add(value);
return this;
}
@@ -31,5 +45,4 @@ public final class BindValuesKey {
return values.hashCode();
}
}
@@ -0,0 +1,10 @@
package io.ebeaninternal.api;
import io.ebean.config.AggregateFormulaContext;
import io.ebeaninternal.server.query.STreeProperty;
public interface FormulaBuilder {
STreeProperty create(AggregateFormulaContext context, String formula, String path);
}
@@ -14,4 +14,9 @@ public interface SpiBeanType {
* or removals from the collection.
*/
boolean isToManyDirty(EntityBean bean);
/**
* Return the FormulaBuilder for this type.
*/
FormulaBuilder formulaBuilder();
}
@@ -1,5 +1,6 @@
package io.ebeaninternal.api;
import io.ebeaninternal.server.query.STreeProperty;
import org.jspecify.annotations.Nullable;
import io.ebean.*;
import io.ebean.bean.BeanCollectionLoader;
@@ -348,6 +349,8 @@ public interface SpiEbeanServer extends SpiServer, BeanCollectionLoader {
<T> FutureList<T> findFutureList(SpiQuery<T> query);
<K, T> FutureMap<K, T> findFutureMap(SpiQuery<T> query);
<T> PagedList<T> findPagedList(SpiQuery<T> query);
<T> Set<T> findSet(SpiQuery<T> query);
@@ -375,4 +378,6 @@ public interface SpiEbeanServer extends SpiServer, BeanCollectionLoader {
@Nullable
SqlRow findOne(SpiSqlQuery query);
<T> STreeProperty createFormulaProperty(SpiBeanType desc, String formula, String path);
}
@@ -15,8 +15,4 @@ public interface SpiQueryManyJoin {
*/
String fetchOrderBy();
/**
* Wrap the filter many expression with a condition allowing lEFT JOIN null matching row.
*/
String idNullOr(String filterManyExpression);
}
@@ -14,6 +14,7 @@ import io.ebeanservice.docstore.api.DocStoreTransaction;
import jakarta.persistence.PersistenceException;
import java.sql.Connection;
import java.sql.SQLException;
import java.time.Instant;
/**
* Extends Transaction with additional API required on server.
@@ -64,12 +65,12 @@ public interface SpiTransaction extends Transaction {
* <p>
* This is to handle bi-directional relationships where both sides Cascade.
*/
void registerDeleteBean(Integer hash);
void registerDeleteBean(Class<?> type, Object id);
/**
* Return true if this is a bean that has already been saved/deleted.
*/
boolean isRegisteredDeleteBean(Integer hash);
boolean isRegisteredDeleteBean(Class<?> type, Object id);
/**
* Unregister the persisted beans. Expected after persisting top level beans
@@ -95,7 +96,7 @@ public interface SpiTransaction extends Transaction {
/**
* Return the start timestamp for the transaction (JVM side).
*/
long startNanoTime();
Instant startTime();
/**
* Return true if this transaction has updateAllLoadedProperties set.
@@ -361,4 +362,14 @@ public interface SpiTransaction extends Transaction {
* Set the transaction to be inactive via external transaction manager.
*/
void deactivateExternal();
/**
* Set autocommit to false for a findIterate query.
* <p>
* This is done for specific platforms that need it, in order to make
* use cursors to stream a large or unbounded query result to the client.
*/
default void setAutoCommitOnFindIterate() {
throw new UnsupportedOperationException();
}
}
@@ -14,6 +14,7 @@ import io.ebeanservice.docstore.api.DocStoreTransaction;
import jakarta.persistence.PersistenceException;
import java.sql.Connection;
import java.sql.SQLException;
import java.time.Instant;
/**
* Proxy for an underlying SpiTransaction (most of the API).
@@ -28,8 +29,8 @@ public abstract class SpiTransactionProxy implements SpiTransaction {
}
@Override
public long startNanoTime() {
return transaction.startNanoTime();
public Instant startTime() {
return transaction.startTime();
}
@Override
@@ -194,13 +195,13 @@ public abstract class SpiTransactionProxy implements SpiTransaction {
}
@Override
public void registerDeleteBean(Integer hash) {
transaction.registerDeleteBean(hash);
public void registerDeleteBean(Class<?> type, Object id) {
transaction.registerDeleteBean(type, id);
}
@Override
public boolean isRegisteredDeleteBean(Integer hash) {
return transaction.isRegisteredDeleteBean(hash);
public boolean isRegisteredDeleteBean(Class<?> type, Object id) {
return transaction.isRegisteredDeleteBean(type, id);
}
@Override
@@ -23,7 +23,7 @@ public class DefaultServerQueryCache extends DefaultServerCache {
@Override
protected Object unwrapEntry(CacheEntry entry) {
return ((QueryCacheEntry) entry.getValue()).getValue();
return ((QueryCacheEntry) entry.getValue()).value();
}
@Override
@@ -1,7 +1,6 @@
package io.ebeaninternal.server.core;
import io.ebean.CancelableQuery;
import io.ebean.Transaction;
import io.ebean.util.JdbcClose;
import io.ebeaninternal.api.*;
import io.ebeaninternal.server.persist.Binder;
@@ -98,6 +97,13 @@ public abstract class AbstractSqlQueryRequest implements CancelableQuery {
public void setDefaultFetchBuffer(int fetchSize) {
query.setDefaultFetchBuffer(fetchSize);
}
public void setAutoCommitOnFindIterate() {
if (createdTransaction) {
transaction.setAutoCommitOnFindIterate();
}
}
/**
* Close the underlying resources.
*/
@@ -113,6 +113,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
private final long slowQueryMicros;
private final SlowQueryListener slowQueryListener;
private final boolean disableL2Cache;
private final AggregateFormulaContext formulaContext;
private boolean shutdown;
/**
@@ -128,6 +129,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
this.backgroundExecutor = config.getBackgroundExecutor();
this.extraMetrics = config.getExtraMetrics();
this.serverName = this.config.getName();
this.formulaContext = config.getConfig().aggregateFormulaContext();
this.lazyLoadBatchSize = this.config.getLazyLoadBatchSize();
this.cqueryEngine = config.getCQueryEngine();
this.expressionFactory = config.getExpressionFactory();
@@ -162,8 +164,10 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
this.scriptRunner = new DScriptRunner(this);
configureServerPlugins();
// Register with the JVM Shutdown hook
ShutdownManager.registerDatabase(this);
if (this.config.shutdownHook() && "true".equalsIgnoreCase(System.getProperty("ebean.registerShutdownHook", "true"))) {
// register with the JVM Shutdown hook
ShutdownManager.registerDatabase(this);
}
}
/**
@@ -278,6 +282,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
}
@Override
@Nullable
public DataSource readOnlyDataSource() {
return transactionManager.readOnlyDataSource();
}
@@ -925,6 +930,11 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
return findId(query);
}
@Override
public <T> STreeProperty createFormulaProperty(SpiBeanType desc, String formula, String path) {
return desc.formulaBuilder().create(formulaContext, formula, path);
}
<T> SpiOrmQueryRequest<T> createQueryRequest(Type type, SpiQuery<T> query) {
SpiOrmQueryRequest<T> request = buildQueryRequest(type, query);
request.prepareQuery();
@@ -1249,66 +1259,55 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
}
}
private <T> SpiQuery<T> configureForFuture(SpiQuery<T> query) {
query.usingFuture();
if (query.transaction() == null) {
// use a current transaction if active
query.usingTransaction(currentServerTransaction());
}
return query;
}
@Override
public <T> FutureRowCount<T> findFutureCount(SpiQuery<T> query) {
SpiQuery<T> copy = query.copy();
copy.usingFuture();
boolean createdTransaction = false;
SpiTransaction transaction = query.transaction();
if (transaction == null) {
transaction = currentServerTransaction();
if (transaction == null) {
transaction = (SpiTransaction) createTransaction();
createdTransaction = true;
}
copy.usingTransaction(transaction);
}
var queryFuture = new QueryFutureRowCount<>(new CallableQueryCount<>(this, copy, createdTransaction));
SpiQuery<T> copy = configureForFuture(query.copy());
var queryFuture = new QueryFutureRowCount<>(new CallableQueryCount<>(this, copy));
backgroundExecutor.execute(queryFuture.futureTask());
return queryFuture;
}
@Override
public <T> FutureIds<T> findFutureIds(SpiQuery<T> query) {
SpiQuery<T> copy = query.copy();
copy.usingFuture();
boolean createdTransaction = false;
SpiTransaction transaction = query.transaction();
if (transaction == null) {
transaction = currentServerTransaction();
if (transaction == null) {
transaction = (SpiTransaction) createTransaction();
createdTransaction = true;
}
copy.usingTransaction(transaction);
}
QueryFutureIds<T> queryFuture = new QueryFutureIds<>(new CallableQueryIds<>(this, copy, createdTransaction));
SpiQuery<T> copy = configureForFuture(query.copy());
final var queryFuture = new QueryFutureIds<T>(new CallableQueryIds<>(this, copy));
backgroundExecutor.execute(queryFuture.futureTask());
return queryFuture;
}
@Override
public <T> FutureList<T> findFutureList(SpiQuery<T> query) {
SpiQuery<T> spiQuery = query.copy();
spiQuery.usingFuture();
// FutureList query always run in it's own persistence content
SpiQuery<T> spiQuery = configureForFuture(query.copy());
// FutureList query always run in its own persistence content
spiQuery.setPersistenceContext(new DefaultPersistenceContext());
if (!spiQuery.isDisableReadAudit()) {
BeanDescriptor<T> desc = descriptorManager.descriptor(spiQuery.getBeanType());
desc.readAuditFutureList(spiQuery);
}
// Create a new transaction solely to execute the findList() at some future time
boolean createdTransaction = false;
SpiTransaction transaction = query.transaction();
if (transaction == null) {
transaction = currentServerTransaction();
if (transaction == null) {
transaction = (SpiTransaction) createTransaction();
createdTransaction = true;
}
spiQuery.usingTransaction(transaction);
final var queryFuture = new QueryFutureList<T>(new CallableQueryList<>(this, spiQuery));
backgroundExecutor.execute(queryFuture.futureTask());
return queryFuture;
}
@Override
public <K, T> FutureMap<K, T> findFutureMap(SpiQuery<T> query) {
SpiQuery<T> spiQuery = configureForFuture(query.copy());
// FutureMap query always run in it's own persistence content
spiQuery.setPersistenceContext(new DefaultPersistenceContext());
if (!spiQuery.isDisableReadAudit()) {
BeanDescriptor<T> desc = descriptorManager.descriptor(spiQuery.getBeanType());
desc.readAuditFutureList(spiQuery);
}
QueryFutureList<T> queryFuture = new QueryFutureList<>(new CallableQueryList<>(this, spiQuery, createdTransaction));
final var queryFuture = new QueryFutureMap<K, T>(new CallableQueryMap<>(this, spiQuery));
backgroundExecutor.execute(queryFuture.futureTask());
return queryFuture;
}
@@ -301,12 +301,12 @@ public final class InternalConfiguration {
}
DtoQueryEngine createDtoQueryEngine() {
return new DtoQueryEngine(binder, config.getJdbcFetchSizeFindEach(), config.getJdbcFetchSizeFindList());
return new DtoQueryEngine(binder, config.getJdbcFetchSizeFindEach(), config.getJdbcFetchSizeFindList(), databasePlatform.autoCommitFalseOnFindIterate());
}
RelationalQueryEngine createRelationalQueryEngine() {
return new DefaultRelationalQueryEngine(binder, config.getDatabaseBooleanTrue(), config.getPlatformConfig().getDbUuid().useBinaryOptimized(),
config.getJdbcFetchSizeFindEach(), config.getJdbcFetchSizeFindList());
config.getJdbcFetchSizeFindEach(), config.getJdbcFetchSizeFindList(), databasePlatform.autoCommitFalseOnFindIterate());
}
OrmQueryEngine createOrmQueryEngine() {
@@ -585,27 +585,32 @@ public final class InternalConfiguration {
return QueryPlanManager.NOOP;
}
long threshold = config.getQueryPlanThresholdMicros();
return new CQueryPlanManager(transactionManager, threshold, queryPlanLogger(databasePlatform.platform()), extraMetrics);
return new CQueryPlanManager(transactionManager, threshold, queryPlanLogger(databasePlatform.platform(), config), extraMetrics);
}
/**
* Returns the logger to log query plans for the given platform.
*/
QueryPlanLogger queryPlanLogger(Platform platform) {
QueryPlanLogger queryPlanLogger(Platform platform, DatabaseBuilder.Settings config) {
switch (platform.base()) {
case SQLSERVER:
return new QueryPlanLoggerSqlServer();
case ORACLE:
return new QueryPlanLoggerOracle();
case POSTGRES:
return new QueryPlanLoggerExplain("explain (analyze, buffers) ");
return new QueryPlanLoggerExplain(explain(config, "explain (analyze, costs, verbose, buffers) "));
case YUGABYTE:
return new QueryPlanLoggerExplain("explain (analyze, buffers, dist) ");
return new QueryPlanLoggerExplain(explain(config,"explain (analyze, buffers, dist) "));
default:
return new QueryPlanLoggerExplain("explain ");
return new QueryPlanLoggerExplain(explain(config,"explain "));
}
}
private static String explain(DatabaseBuilder.Settings config, String defaultExplain) {
String explain = config.getQueryPlanExplain();
return explain == null ? defaultExplain : explain + ' ';
}
/**
* Return the DDL generator.
*/
@@ -665,7 +665,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
}
public void putToQueryCache(Object result) {
beanDescriptor.queryCachePut(cacheKey, new QueryCacheEntry(result, dependentTables, transaction.startNanoTime()));
beanDescriptor.queryCachePut(cacheKey, new QueryCacheEntry(result, dependentTables, transaction.startTime()));
}
/**
@@ -786,4 +786,10 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
beanDescriptor.freeze(bean);
}
}
public void setAutoCommitOnFindIterate() {
if (createdTransaction) {
transaction.setAutoCommitOnFindIterate();
}
}
}
@@ -54,10 +54,6 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
* The unique id used for logging summary.
*/
private Object idValue;
/**
* Hash value used to handle cascade delete both ways in a relationship.
*/
private Integer beanHash;
private boolean statelessUpdate;
private boolean notifyCache;
/**
@@ -285,7 +281,9 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
private void onFailedUpdateUndoGeneratedProperties() {
for (BeanProperty prop : beanDescriptor.propertiesGenUpdate()) {
Object oldVal = intercept.origValue(prop.propertyIndex());
prop.setValue(entityBean, oldVal);
if (oldVal != null) {
prop.setValue(entityBean, oldVal);
}
}
}
@@ -553,34 +551,17 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
}
}
/**
* The hash used to register the bean with the transaction.
* <p>
* Takes into account the class type and id value.
*/
private Integer beanHash() {
if (beanHash == null) {
Object id = beanDescriptor.getId(entityBean);
int hc = 92821 * bean.getClass().getName().hashCode();
if (id != null) {
hc += id.hashCode();
}
beanHash = hc;
}
return beanHash;
}
public void registerDeleteBean() {
Integer hash = beanHash();
transaction.registerDeleteBean(hash);
final Object id = beanDescriptor.id(entityBean);
transaction.registerDeleteBean(beanDescriptor.type(), id);
}
public boolean isRegisteredForDeleteBean() {
if (transaction == null) {
return false;
} else {
Integer hash = beanHash();
return transaction.isRegisteredDeleteBean(hash);
final Object id = beanDescriptor.id(entityBean);
return transaction.isRegisteredDeleteBean(beanDescriptor.type(), id);
}
}
@@ -809,7 +790,9 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
public void checkRowCount(int rowCount) {
if (rowCount != 1 && rowCount != Statement.SUCCESS_NO_INFO) {
if (ConcurrencyMode.VERSION == concurrencyMode) {
onFailedUpdateUndoGeneratedProperties();
if (type == Type.UPDATE) {
onFailedUpdateUndoGeneratedProperties();
}
throw new OptimisticLockException("Data has changed. updated row count " + rowCount, null, bean);
} else if (rowCount == 0 && type == Type.UPDATE) {
throw new EntityNotFoundException("No rows updated");
@@ -1471,7 +1471,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
void queryPlanInit(QueryPlanInit request, List<MetaQueryPlan> list) {
for (CQueryPlan queryPlan : queryPlanCache.values()) {
if (request.includeHash(queryPlan.hash())) {
queryPlan.queryPlanInit(request.thresholdMicros());
queryPlan.queryPlanInit(request.thresholdMicros(queryPlan.hash()));
list.add(queryPlan.createMeta(null, null));
}
}
@@ -2410,7 +2410,12 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
*/
private STreeProperty findSqlTreeFormula(String formula, String path) {
String key = formula + "-" + path;
return dynamicProperty.computeIfAbsent(key, (fullKey) -> FormulaPropertyPath.create(this, formula, path));
return dynamicProperty.computeIfAbsent(key, (fullKey) -> ebeanServer.createFormulaProperty(this, formula, path));
}
@Override
public FormulaBuilder formulaBuilder() {
return new DFormulaBuilder(this);
}
/**
@@ -58,7 +58,7 @@ final class BeanEmbeddedMetaFactory {
}
private static int dbLength(Column override, BeanProperty source) {
return (override != null && (override.length() != 255)) ? override.length() : source.dbLength();
return (override != null && (override.length() != 0)) ? override.length() : source.dbLength();
}
private static int dbScale(Column override, BeanProperty source) {
@@ -36,11 +36,6 @@ public final class BeanFkeyProperty implements ElPropertyValue {
return "prefix:" + prefix + " name:" + name + " dbColumn:" + dbColumn + " ph:" + placeHolder;
}
@Override
public String idNullOr(String filterManyExpression) {
throw new UnsupportedOperationException();
}
@Override
public boolean isAggregation() {
return false;
@@ -513,11 +513,6 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
return owningType.isAssignableFrom(type);
}
@Override
public String idNullOr(String filterManyExpression) {
throw new UnsupportedOperationException();
}
@Override
public void loadIgnore(DbReadContext ctx) {
ctx.dataReader().incrementPos(1);
@@ -436,14 +436,15 @@ public abstract class BeanPropertyAssoc<T> extends BeanProperty implements STree
}
TableJoinColumn[] cols = join.columns();
if (!idProp.isEmbedded()) {
// simple single scalar id
if (cols.length != 1) {
CoreLog.log.log(ERROR, "No Imported Id column for {0} in table {1}", idProp, join.getTable());
return null;
} else {
BeanProperty[] idProps = {idProp};
return createImportedScalar(owner, cols[0], idProps, others);
// simple single scalar id, match on the foreign column, allow extra TableJoinColumn for #3664
String matchColumn = idProp.dbColumn();
for (TableJoinColumn col : cols) {
if (matchColumn.equals(col.getForeignDbColumn())) {
return createImportedScalar(owner, col, new BeanProperty[]{idProp}, others);
}
}
CoreLog.log.log(ERROR, "No Imported Id column for {0} in table {1}", idProp, join.getTable());
return null;
} else {
// embedded id
BeanPropertyAssocOne<?> embProp = (BeanPropertyAssocOne<?>) idProp;
@@ -634,11 +634,6 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> implements ST
return fetchOrderBy;
}
@Override
public String idNullOr(String filterManyExpression) {
return targetIdBinder.idNullOr(name, filterManyExpression);
}
/**
* Return the order by for use when lazy loading the associated collection.
*/
@@ -1,6 +1,5 @@
package io.ebeaninternal.server.deploy;
import io.ebean.Query;
import io.ebean.SqlUpdate;
import io.ebean.Transaction;
import io.ebean.ValuePair;
@@ -125,15 +124,9 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> implements STr
// no imported or exported information
} else if (!oneToOneExported) {
importedId = createImportedId(this, targetDescriptor, tableJoin);
if (importedId.isScalar()) {
// limit JoinColumn mapping to the @Id / primary key
TableJoinColumn[] columns = tableJoin.columns();
String foreignJoinColumn = columns[0].getForeignDbColumn();
String foreignIdColumn = targetDescriptor.idProperty().dbColumn();
if (!foreignJoinColumn.equalsIgnoreCase(foreignIdColumn)) {
throw new PersistenceException("Mapping limitation - @JoinColumn on " + fullName() + " needs to map to a primary key as per Issue #529 "
+ " - joining to " + foreignJoinColumn + " and not " + foreignIdColumn);
}
if (importedId == null) {
throw new PersistenceException("Cannot find imported id for " + fullName() + " from " + targetDescriptor
+ ". If using native-image, possibly missing reflect-config for the Id property.");
}
} else {
exportedProperties = createExported();
@@ -0,0 +1,19 @@
package io.ebeaninternal.server.deploy;
import io.ebean.config.AggregateFormulaContext;
import io.ebeaninternal.api.FormulaBuilder;
import io.ebeaninternal.server.query.STreeProperty;
final class DFormulaBuilder implements FormulaBuilder {
private final BeanDescriptor<?> descriptor;
DFormulaBuilder(BeanDescriptor<?> descriptor) {
this.descriptor = descriptor;
}
@Override
public STreeProperty create(AggregateFormulaContext context, String formula, String path) {
return FormulaPropertyPath.create(descriptor, context, formula, path);
}
}
@@ -154,4 +154,9 @@ public interface DbSqlContext {
* as it was already added to the query.
*/
boolean joinAdded();
/**
* Include the filter many predicates if specified into the JOIN clause.
*/
void includeFilterMany();
}
@@ -1,6 +1,7 @@
package io.ebeaninternal.server.deploy;
import io.ebean.core.type.ScalarType;
import io.ebean.config.AggregateFormulaContext;
import io.ebeaninternal.server.el.ElPropertyDeploy;
import io.ebeaninternal.server.query.STreeProperty;
@@ -9,11 +10,10 @@ import java.util.Set;
final class FormulaPropertyPath {
private static final String[] AGG_FUNCTIONS = {"count", "max", "min", "avg", "sum"};
private static final String DISTINCT_ = "distinct ";
private final BeanDescriptor<?> descriptor;
private final AggregateFormulaContext context;
private final String formula;
private final String outerFunction;
private final String internalExpression;
@@ -24,12 +24,13 @@ final class FormulaPropertyPath {
private String cast;
private String alias;
static STreeProperty create(BeanDescriptor<?> descriptor, String formula, String path) {
return new FormulaPropertyPath(descriptor, formula, path).build();
static STreeProperty create(BeanDescriptor<?> descriptor, AggregateFormulaContext context, String formula, String path) {
return new FormulaPropertyPath(descriptor, context, formula, path).build();
}
FormulaPropertyPath(BeanDescriptor<?> descriptor, String formula, String path) {
FormulaPropertyPath(BeanDescriptor<?> descriptor, AggregateFormulaContext context, String formula, String path) {
this.descriptor = descriptor;
this.context = context;
this.formula = formula;
int openBracket = formula.indexOf('(');
int closeBracket = formula.lastIndexOf(')');
@@ -106,10 +107,10 @@ final class FormulaPropertyPath {
}
return create(scalarType);
}
if (isCount()) {
if (context.isCount(outerFunction)) {
return create(descriptor.scalarType(Types.BIGINT));
}
if (isConcat()) {
if (context.isConcat(outerFunction)) {
return create(descriptor.scalarType(Types.VARCHAR));
}
if (firstProp == null) {
@@ -144,12 +145,7 @@ final class FormulaPropertyPath {
}
private boolean isAggregate() {
for (String aggFunction : AGG_FUNCTIONS) {
if (aggFunction.equals(outerFunction)) {
return true;
}
}
return false;
return context.isAggregate(outerFunction);
}
private String buildFormula(String parsed) {
@@ -27,11 +27,6 @@ public interface IdBinder {
*/
void initialise();
/**
* Wrap the filter many expression with a condition allowing lEFT JOIN null matching row.
*/
String idNullOr(String name, String filterManyExpression);
String idSelect();
/**
@@ -45,20 +45,6 @@ public final class IdBinderEmbedded implements IdBinder {
this.idInValueSql = idInExpandedForm ? idInExpanded() : idInCompressed();
}
@Override
public String idNullOr(String prefix, String filterManyExpression) {
StringBuilder sb = new StringBuilder(100);
sb.append("((");
for (int i = 0; i < props.length; i++) {
if (i > 0) {
sb.append(" and ");
}
sb.append("${").append(prefix).append('}').append(props[i].dbColumn()).append(" is null");
}
sb.append(") or (").append(filterManyExpression).append("))");
return sb.toString();
}
@Override
public String idSelect() {
return embIdProperty.name();
@@ -28,11 +28,6 @@ final class IdBinderEmpty implements IdBinder {
public void initialise() {
}
@Override
public String idNullOr(String name, String filterManyExpression) {
throw new UnsupportedOperationException();
}
@Override
public String idSelect() {
return "";
@@ -261,9 +261,4 @@ public final class IdBinderSimple implements IdBinder {
final Object value = idProperty.getValue(bean);
return scalarType.format(value);
}
@Override
public String idNullOr(String prefix, String filterManyExpression) {
return "(${" + prefix + "}" + idProperty.name() + " is null or (" + filterManyExpression + "))";
}
}
@@ -804,11 +804,9 @@ public class DeployBeanDescriptor<T> {
* Return the defaultSelectClause using FetchType.LAZY and FetchType.EAGER.
*/
public String getDefaultSelectClause() {
StringBuilder sb = new StringBuilder();
boolean hasLazyFetch = false;
for (DeployBeanProperty prop : propMap.values()) {
if (!prop.isTransient() && !(prop instanceof DeployBeanPropertyAssocMany<?>)) {
if (prop.isFetchEager()) {
@@ -617,6 +617,8 @@ public class DeployBeanProperty {
this.dbRead = true;
this.dbInsertable = false;
this.dbUpdateable = false;
// aggregation by default not fetchEager
this.fetchEager = false;
}
/**
@@ -98,7 +98,7 @@ public abstract class AnnotationParser extends AnnotationBase {
prop.setUnique(columnAnn.unique());
if (columnAnn.precision() > 0) {
prop.setDbLength(columnAnn.precision());
} else if (columnAnn.length() != 255) {
} else if (columnAnn.length() != 0) {
// set default 255 on DbTypeMap
prop.setDbLength(columnAnn.length());
}
@@ -286,8 +286,4 @@ public final class ElPropertyChain implements ElPropertyValue {
}
}
@Override
public String idNullOr(String filterManyExpression) {
throw new UnsupportedOperationException();
}
}
@@ -726,7 +726,7 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
*/
@Override
public <T> Junction<T> conjunction(Query<T> query) {
return new JunctionExpression<>(Junction.Type.AND, query, query.where());
return new JunctionExpression<>(Junction.Type.AND, query, this, query.where());
}
/**
@@ -734,7 +734,7 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
*/
@Override
public <T> Junction<T> disjunction(Query<T> query) {
return new JunctionExpression<>(Junction.Type.OR, query, query.where());
return new JunctionExpression<>(Junction.Type.OR, query, this, query.where());
}
/**
@@ -742,7 +742,7 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
*/
@Override
public <T> Junction<T> conjunction(Query<T> query, ExpressionList<T> parent) {
return new JunctionExpression<>(Junction.Type.AND, query, parent);
return new JunctionExpression<>(Junction.Type.AND, query, this, parent);
}
/**
@@ -750,14 +750,14 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
*/
@Override
public <T> Junction<T> disjunction(Query<T> query, ExpressionList<T> parent) {
return new JunctionExpression<>(Junction.Type.OR, query, parent);
return new JunctionExpression<>(Junction.Type.OR, query, this, parent);
}
/**
* Return a list of expressions that are wrapped by NOT.
*/
public <T> Junction<T> junction(Junction.Type type, Query<T> query) {
return new JunctionExpression<>(type, query, query.where());
return new JunctionExpression<>(type, query, this, query.where());
}
/**
@@ -765,6 +765,6 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
*/
@Override
public <T> Junction<T> junction(Junction.Type type, Query<T> query, ExpressionList<T> parent) {
return new JunctionExpression<>(type, query, parent);
return new JunctionExpression<>(type, query, this, parent);
}
}
@@ -40,12 +40,8 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
/**
* Construct for Text root expression list - this handles implicit Bool Should, Must etc.
*/
public DefaultExpressionList(Query<T> query) {
this(query, query.getExpressionFactory(), null, new ArrayList<>(), true);
}
public DefaultExpressionList(Query<T> query, ExpressionList<T> parentExprList) {
this(query, query.getExpressionFactory(), parentExprList, new ArrayList<>());
public DefaultExpressionList(Query<T> query, boolean textRoot) {
this(query, query.getExpressionFactory(), null, new ArrayList<>(), textRoot);
}
DefaultExpressionList(Query<T> query, ExpressionFactory expr, ExpressionList<T> parentExprList, List<SpiExpression> list) {
@@ -24,9 +24,9 @@ final class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expr
DefaultExpressionList<T> exprList;
Junction.Type type;
JunctionExpression(Junction.Type type, Query<T> query, ExpressionList<T> parent) {
JunctionExpression(Junction.Type type, Query<T> query, ExpressionFactory expr, ExpressionList<T> parent) {
this.type = type;
this.exprList = new DefaultExpressionList<>(query, parent);
this.exprList = new DefaultExpressionList<>(query, expr, parent, new ArrayList<>());
}
/**
@@ -97,7 +97,7 @@ public final class DLoadContext implements LoadContext {
this.profilingListener = query.profilingListener();
this.planLabel = query.planLabel();
this.profileLocation = query.profileLocation();
this.secondaryProperties = query.isUnmodifiable() || query.isDisableLazyLoading() ? new HashSet<>() : null;
this.secondaryProperties = query.isUnmodifiable() ? new HashSet<>() : null;
ObjectGraphNode parentNode = query.parentNode();
if (parentNode != null) {
@@ -329,6 +329,13 @@ public final class Binder {
geoTypeBinder.bind(b, dataType, data);
break;
case DbPlatformType.VECTOR:
case DbPlatformType.VECTOR_HALF:
case DbPlatformType.VECTOR_BIT:
case DbPlatformType.VECTOR_SPARSE:
b.setObject(data);
break;
case java.sql.Types.OTHER:
b.setObject(data, dataType);
break;

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