Compare commits

...
Author SHA1 Message Date
Rob Bygrave 2a96a59deb [maven-release-plugin] prepare release ebean-parent-12.15.1 2022-03-01 22:46:55 +13:00
Rob Bygrave ffad9abeef #2577 - Refactor internals remove no longer needed DdlAutoCommit platform option 2022-03-01 22:32:09 +13:00
Rob Bygrave e8df81d78a DbMigrationTest ignore Yugabyte at this stage 2022-03-01 21:29:17 +13:00
Rob Bygrave ed19a96801 Tidy DbMigrationTest after fix for #2576 2022-03-01 21:01:48 +13:00
Rob Bygrave 6d27e30b88 [H2] Use LocalDateTime in H2HistoryTrigger with microsecond precision - fix DbMigrationTest 2022-03-01 20:52:39 +13:00
Rob Bygrave 52aa1a2d91 For Multi-jdk build failure - tweak DbMigrationTest, add another hack 1 milli sleep 2022-03-01 20:30:49 +13:00
Rob Bygrave ddbd816f6d For Multi-jdk build failure - tweak DbMigrationTest, add hack comment 2022-03-01 16:23:58 +13:00
Rob Bygrave 00940c2b31 For Multi-jdk build failure - tweak DbMigrationTest 2022-03-01 12:10:28 +13:00
Rob Bygrave 708ec64893 For Multi-jdk build failure - check if H2HistoryTrigger should bump 1ms if needed 2022-03-01 11:59:37 +13:00
Rob Bygrave d0dd2d8203 Add a more useful implementation for Version.toString() 2022-03-01 11:34:07 +13:00
Rob Bygrave faa921ac27 Update DbMigrationTest to include platform for some asserts 2022-03-01 11:22:40 +13:00
Rob Bygrave f2a99c7b01 Update DbMigrationTest to include platform for some asserts 2022-03-01 11:03:37 +13:00
Rob BygraveandGitHub b6ea9df444 Merge pull request #2574 from FOCONIS/ddl-cockroach
[DDL-Cockroach] Fixes for Cockroach platform
2022-02-28 11:25:21 +13:00
Rob BygraveandGitHub e6cde5862d Merge pull request #2573 from FOCONIS/ddl-hana
[DDL-hana] HANA always requires stored procedures
2022-02-28 11:24:05 +13:00
Rob BygraveandGitHub dec927bf9a Merge pull request #2571 from FOCONIS/ddl-sqlite
[DDL-SqLite] Modified SqLite platform to generate at least non failing migration scripts
2022-02-28 11:20:20 +13:00
Rob BygraveandGitHub ae41471c74 Merge pull request #2570 from FOCONIS/ddl-oracle-fixes
[DDL-Oracle] Fix drop default and ignore erros when trying to drop non existent objects
2022-02-28 11:19:43 +13:00
Rob BygraveandGitHub 843d9d2700 Merge pull request #2569 from FOCONIS/ddl-extend-test
[DDL-common] Extended DbMigrationTest to run on all platforms
2022-02-28 11:16:59 +13:00
Roland Praml 475fd38be5 FIX: PlatformDdl-tests 2022-02-25 15:44:54 +01:00
Roland Praml c82f3783f0 Fixes for Cockroach platform 2022-02-25 12:10:06 +01:00
Roland Praml bf99f9d08d Fix: HANA always requires stored procedures (similar to SqlServer), Fix: default value on intermediate alters 2022-02-25 12:09:09 +01:00
Roland Praml f30c3869b6 Modified SqLite platform to generate at least non failing migration scripts.
Note: If you want to alter a table in SqLite, the best option is to recreate the table with the new layout
2022-02-25 12:07:06 +01:00
Roland Praml 3b32e4c018 Oracle: Fix DB name to match with docker container 2022-02-25 12:06:09 +01:00
Roland Praml e0669e9a9f DDL generation fixes fpr oracle platform (fix drop default, do "drop if exists" with error handlers) 2022-02-25 12:05:53 +01:00
Roland Praml 95b1488aed Extended DbMigrationTest to run on all platforms 2022-02-25 12:04:24 +01:00
Rob BygraveandGitHub 897a97d415 Merge pull request #2568 from FOCONIS/Tidy-up-code
Removed unused imports and add missing Override statements (no effective code change)
2022-02-25 14:29:30 +13:00
Rob BygraveandGitHub 1d71f617c2 Merge pull request #2567 from FOCONIS/tidy-up-ddl-generation
Tidy up ddl generation (no effective code change)
2022-02-25 14:28:20 +13:00
Roland Praml 1ca5789112 Removed unused imports and add missing Override statements (no effective code change) 2022-02-24 08:03:26 +01:00
Roland Praml 70ec8a3891 Removed unused code 2022-02-23 11:17:16 +01:00
Roland Praml 2dfa9d2e77 No effective code change: Normalized "DdlWrite write" to "DdlWrite writer" 2022-02-23 11:14:22 +01:00
Rob Bygrave 29a5a13dd9 Merge branch 'master' of github.com:ebean-orm/ebean 2022-02-22 14:52:14 +13:00
Rob Bygrave 7a3494ebd9 Update to the newer Apache2 licence text (from older Apache2 license text) 2022-02-22 14:51:54 +13:00
Rob BygraveandGitHub 915bf29eaf Merge pull request #2557 from FOCONIS/add-reorg-support
Refactored DDL generation
2022-02-22 13:19:51 +13:00
Rob Bygrave dad4837b50 No change - format code only 2022-02-22 13:15:28 +13:00
Rob BygraveandGitHub 8fa8c687e9 Merge pull request #2563 from FOCONIS/platform-specific-columndefinition
Different ColumnDefinition for different platforms
2022-02-22 13:13:43 +13:00
Rob Bygrave aff54f5cf7 Merge branch 'FOCONIS-bug-save-one-to-one-version-cascade' 2022-02-22 13:08:05 +13:00
Rob Bygrave fa0336a404 Merge branch 'bug-save-one-to-one-version-cascade' of https://github.com/FOCONIS/ebean into FOCONIS-bug-save-one-to-one-version-cascade 2022-02-22 13:00:41 +13:00
Noemi Szemenyei 7ccea9ff7e migrations 2022-02-18 10:03:04 +01:00
Noemi Szemenyei c2e4f862bc default columnDef should be calculated from ebean 2022-02-18 10:02:48 +01:00
Roland Praml 36bda117a6 No effective code change: Tidy up (organize imports/fix java warnings) 2022-02-17 14:47:05 +01:00
Roland Praml 08838770e9 No effective code change: Removed obsolete IOExceptions 2022-02-17 14:45:02 +01:00
Noemi Szemenyei 137a7950ff new migrations 2022-02-17 09:53:26 +01:00
Noemi Szemenyei e3980a14a2 review changes 2022-02-17 09:52:23 +01:00
Rob BygraveandGitHub ca9f48d019 Merge pull request #2562 from ebean-orm/dependabot/maven/ebean-test/org.postgresql-postgresql-42.3.3
Bump postgresql from 42.3.2 to 42.3.3 in /ebean-test
2022-02-17 21:44:01 +13:00
Rob BygraveandGitHub e83e6b0f8f Merge pull request #2561 from ebean-orm/dependabot/maven/ebean-core/org.postgresql-postgresql-42.3.3
Bump postgresql from 42.3.2 to 42.3.3 in /ebean-core
2022-02-17 21:43:49 +13:00
Rob BygraveandGitHub 7d18329c18 Merge pull request #2560 from ebean-orm/dependabot/maven/ebean-postgis/org.postgresql-postgresql-42.3.3
Bump postgresql from 42.3.2 to 42.3.3 in /ebean-postgis
2022-02-17 21:43:37 +13:00
Noemi Szemenyei c6fa60f28c migrations 2022-02-17 08:16:35 +01:00
Noemi Szemenyei 3ab7ebe5e6 new property for test 2022-02-17 08:14:51 +01:00
Noemi Szemenyei 48e875714b solution v1
(cherry picked from commit 3d83c6bd0e2bcca6fc04f73ce08983266b9df636)
2022-02-17 08:13:39 +01:00
dependabot[bot]andGitHub 5ba93ed927 Bump postgresql from 42.3.2 to 42.3.3 in /ebean-test
Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.2 to 42.3.3.
- [Release notes](https://github.com/pgjdbc/pgjdbc/releases)
- [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md)
- [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.2...REL42.3.3)

---
updated-dependencies:
- dependency-name: org.postgresql:postgresql
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-16 01:19:58 +00:00
dependabot[bot]andGitHub 9974102f1a Bump postgresql from 42.3.2 to 42.3.3 in /ebean-core
Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.2 to 42.3.3.
- [Release notes](https://github.com/pgjdbc/pgjdbc/releases)
- [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md)
- [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.2...REL42.3.3)

---
updated-dependencies:
- dependency-name: org.postgresql:postgresql
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-16 01:19:22 +00:00
dependabot[bot]andGitHub ba27e09179 Bump postgresql from 42.3.2 to 42.3.3 in /ebean-postgis
Bumps [postgresql](https://github.com/pgjdbc/pgjdbc) from 42.3.2 to 42.3.3.
- [Release notes](https://github.com/pgjdbc/pgjdbc/releases)
- [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md)
- [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.3.2...REL42.3.3)

---
updated-dependencies:
- dependency-name: org.postgresql:postgresql
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-16 01:18:59 +00:00
Alexander Wagner 90066eee0c Possible fix 2022-02-11 10:31:24 +01:00
Roland Praml 53c8827a52 Refactor: remove MConfiguration from BaseDdlBuffer (it is unused, and may/should be re-added to the DdlWrite when needed) 2022-02-08 16:21:25 +01:00
Alexander Wagner 3bb6f0ca65 Bug: save with cascade of @OneToOne + @Version model sets version to 1
(cherry picked from commit 1570e1800d)
2022-02-08 16:08:13 +01:00
Roland Praml 6e5eb6b963 Refactor: BaseDdlBuffer uses StringBuilder instead of StringWriter. Makes IOException obsolete. 2022-02-08 16:04:14 +01:00
Rob BygraveandGitHub 7bea0d0eb2 Merge pull request #2551 from FOCONIS/move-testcase
Move DbMigration-Tests to ebean-test
2022-02-08 10:23:40 +13:00
Rob BygraveandGitHub 5a07a54544 Merge pull request #2555 from FOCONIS/clickhouse-dbarray-type-missing
ClickHouseDb - decimal[] array type missing
2022-02-08 10:12:46 +13:00
Rob BygraveandGitHub 684508b7ea Merge pull request #2554 from FOCONIS/add-stored-procs-mysql
generate mysql StoredProcs for column deletion also for mariadb
2022-02-08 10:12:13 +13:00
Rob BygraveandGitHub ab72fd97b9 Merge pull request #2553 from FOCONIS/add-yugabyte-platform
Add Yugabyte-Platform to DefaultDbMigration
2022-02-08 10:11:33 +13:00
Rob BygraveandGitHub 8486415249 Merge pull request #2552 from FOCONIS/flaky-dtimedmetrictest
DTimedMetricTest fails sometimes (flaky test)
2022-02-08 10:10:36 +13:00
Roland Praml 6a74b84b8c Comments and mysql fixes 2022-02-07 17:07:01 +01:00
Roland Praml 999be3e0a7 ClickHouseDb - decimal[] array type missing 2022-02-07 16:40:11 +01:00
Roland Praml a656b55526 generate mysql StoredProcs for column deletion also for mariadb 2022-02-07 16:37:15 +01:00
Roland Praml dabb1451e9 Add Yugabyte-Platform to DefaultDbMigration 2022-02-07 16:34:39 +01:00
Roland Praml cde00650ca DTimedMetricTest fails sometimes 2022-02-07 16:27:09 +01:00
Roland Praml 6b96bea480 Disabled Yugabyte 2022-02-07 16:23:50 +01:00
Roland Praml a731bfdfaf Multi-platform tests 2022-02-07 16:04:59 +01:00
Roland Praml 0ee153d6bc Add: ElementCollection 2022-02-07 14:08:26 +01:00
Roland Praml cb89b903fd Regenerated scripts & tests 2022-02-07 14:07:10 +01:00
Roland Praml a93e2e05c5 Moved DbMigrationtests test to "ebean-tests" 2022-02-07 11:55:41 +01:00
Rob BygraveandGitHub 05ad6da7e6 Merge pull request #2550 from ebean-orm/feature/cockroach-like
CockroachDB - Now supports LIKE ESCAPE and no longer needs Autocommit for DDL
2022-02-04 17:02:33 +13:00
Rob Bygrave 0d3ea9626c CockroachDB - Now supports LIKE ESCAPE and no longer needs Autocommit for DDL 2022-02-04 17:02:01 +13:00
Rob Bygrave b8b83c2ec8 Update more tests for CockroachDB 2022-02-04 16:59:16 +13:00
Rob Bygrave d05dfae1d7 Merge branch 'master' of github.com:ebean-orm/ebean 2022-02-04 15:55:26 +13:00
Rob Bygrave d0fcd4a13a #2549 - Fix DefaultPersister to expose non RuntimeExceptions on insert/update/delete. Not hide NoClassDefFoundError etc 2022-02-04 15:55:00 +13:00
Rob BygraveandGitHub b02adeccc1 Merge pull request #2548 from ebean-orm/feature/tests-for-cockroach
CockroachDB - Modify tests, use BigDecimal over Double etc
2022-02-04 11:04:55 +13:00
Rob Bygrave b3f110b7a5 CockroachDB - Modify tests, use BigDecimal over Double etc 2022-02-04 10:42:07 +13:00
Rob Bygrave daf0ba67a4 #2547 - CockroachDB - Use ON DISTINCT ... like Postgres and Yugabyte 2022-02-04 08:58:21 +13:00
Rob Bygrave cf3499f0e4 #2547 - Update BaseTestCase to include CockroachDB 2022-02-04 08:41:34 +13:00
Rob Bygrave a72cbaf243 #2547 - Cockroach identity DDL - Changing to use standard GENERATED ... AS IDENTITY syntax 2022-02-04 08:40:23 +13:00
Rob Bygrave 9ea2811aa3 Add H2Database build badge 2022-02-03 17:13:45 +13:00
Rob Bygrave 0abef7396f Add H2Database build workflow 2022-02-03 16:41:58 +13:00
Rob Bygrave 101d9e85ef Add H2Database build workflow 2022-02-03 16:38:17 +13:00
Rob Bygrave 7a3be45efd Add Yugabyte build badge to README 2022-02-03 16:22:53 +13:00
Rob Bygrave f4d92eed18 Bump test modules to 12.15.1-SNAPSHOT after release 2022-02-03 09:19:10 +13:00
Rob Bygrave db6f2cba75 [maven-release-plugin] prepare for next development iteration 2022-02-03 09:02:38 +13:00
Rob Bygrave 6f694eb6ca [maven-release-plugin] prepare release ebean-parent-12.15.0 2022-02-03 09:02:30 +13:00
Rob Bygrave 539633c963 Adjust Multi-database platform 2022-02-02 23:40:58 +13:00
Rob Bygrave 8e05956f6b Default tests to use H2 2022-02-02 23:39:15 +13:00
Rob Bygrave 94951a5476 Yugabyte - use distinct on clause with Yugabyte (like Postgres) 2022-02-02 23:38:50 +13:00
Rob BygraveandGitHub 2cd769d00f Merge pull request #2546 from ebean-orm/feature/yugabyte-mutlivaluebind
Modify tests to use isPostgresCompatible() (to effectively include Yugabyte)
2022-02-02 23:26:12 +13:00
Rob Bygrave 389f2bcd2f Modify tests to use isPostgresCompatible() (to effectively include Yugabyte) 2022-02-02 23:25:13 +13:00
Rob BygraveandGitHub 1ba259d15d Merge pull request #2545 from ebean-orm/feature/yugabyte-mutlivaluebind
Yugabyte - Use MultiValueBind like Postgres (that is, ANY(?) clause in sqlQuery/sqlUpdate)
2022-02-02 23:03:33 +13:00
Rob Bygrave 4899f23773 Yugabyte - Use MultiValueBind like Postgres (that is, ANY(?) clause in sqlQuery/sqlUpdate) 2022-02-02 23:02:32 +13:00
Rob Bygrave 771e9ff069 Tidy tests only - EqlParserTest, EbeanServer_deleteAllByIdTest 2022-02-02 23:00:06 +13:00
Rob Bygrave 7d27c06483 Bump jaxb-runtime dependency 2022-02-02 22:30:37 +13:00
Rob Bygrave d6a8643fe4 Support @DbArray of BigDecimal 2022-02-02 22:22:42 +13:00
Rob BygraveandGitHub 97c714d945 Merge pull request #2544 from ebean-orm/feature/dbarray_bigdecimal
Support @DbArray of BigDecimal
2022-02-02 22:08:48 +13:00
Rob Bygrave 57f6668b37 Support @DbArray of BigDecimal 2022-02-02 21:57:39 +13:00
Rob Bygrave 9d506b4397 Bump test dependencies 2022-02-02 20:48:55 +13:00
Rob Bygrave 5a12cc58d1 Bump Postgres test dependencies to 42.3.2 2022-02-02 17:18:14 +13:00
Rob Bygrave f7c83411c2 #2415 - SQL for Index and Foreign Key didn't get generated if I map ID column after @ManyToOne
Allow declaring the column twice with scalar type after ManyToOne type
2022-02-02 17:12:18 +13:00
Rob BygraveandGitHub a02fee7de0 Merge pull request #2539 from ebean-orm/feature/performance-pathmaps
#2507 - Script runner does not work with file system path
2022-02-02 13:03:45 +13:00
Rob Bygrave 170e323ee9 #2507 - Script runner does not work with file system path 2022-02-02 13:02:49 +13:00
Rob BygraveandGitHub 4555f3da51 Merge pull request #2538 from ebean-orm/feature/performance-pathmaps
Performance - cache the path maps used for load context
2022-02-02 12:30:56 +13:00
Rob Bygrave 376b3a9f13 #2538 - Tidy CQuery use of path() 2022-02-02 12:20:33 +13:00
Rob Bygrave 43af5343a4 Performance - cache the path maps used for load context
- Cache the path maps
- Include the ToOne paths
- Use empty map for null prefix
2022-02-02 12:10:02 +13:00
Rob Bygrave 886f539fc4 Refactor tidy SqlTreeNodeBean 2022-02-02 11:30:56 +13:00
Rob Bygrave 1035d74113 Bump to 12.15.0-SNAPSHOT 2022-02-02 11:20:59 +13:00
Rob Bygrave 26a4feb5ba Bump to 12.15.0-SNAPSHOT 2022-02-02 11:14:36 +13:00
Rob Bygrave a1c0e21234 Bump to 12.15.0-SNAPSHOT 2022-02-02 10:59:04 +13:00
Rob Bygrave cbe133dd68 #2509 - Bump jedis client to 4.1.1 2022-02-02 10:56:59 +13:00
Rob BygraveandGitHub 4b1fe063b0 Merge pull request #2531 from FOCONIS/db2/persist-batch-on-cascade
Set persistBatchOnCascade to ALL for newer DB2 versions
2022-02-02 09:06:39 +13:00
Rob Bygrave 15f1bd310b #2521 - Refactor inline index++ 2022-02-02 09:05:14 +13:00
Rob Bygrave 6e3e9bd4f7 git push origin masterMerge branch 'FOCONIS-db2/fix-get-generated-keys' 2022-02-02 09:00:01 +13:00
Rob Bygrave fddcc64741 #2521 - Move horrible DB2 hack into DB2GetKeys 2022-02-02 08:59:41 +13:00
Rob Bygrave ed917c55f1 Merge branch 'db2/fix-get-generated-keys' of https://github.com/FOCONIS/ebean into FOCONIS-db2/fix-get-generated-keys 2022-02-02 08:46:42 +13:00
Rob Bygrave 17fed0ebd8 Tidy test only - TestNestedBeginRequiresNew 2022-02-01 15:18:06 +13:00
Rob BygraveandGitHub 2dcd17830a Merge pull request #2536 from ebean-orm/feature/ebeantest-pg14
ebean-test - bump Postgres default container to 14
2022-02-01 13:46:09 +13:00
Rob Bygrave a412873da6 ebean-test - bump Postgres default container to 14 2022-02-01 13:36:37 +13:00
Rob BygraveandGitHub 7f5370c709 Merge pull request #2535 from ebean-orm/feature/yugabyte-workflow-build
Yugabyte - Add specific github workflow build
2022-02-01 13:33:28 +13:00
Rob Bygrave 9470a1376c Yugabyte - Add specific github workflow build 2022-02-01 13:32:55 +13:00
Rob BygraveandGitHub 7f5b65cf45 Merge pull request #2534 from ebean-orm/feature/yugabyte-test
Yugabyte - ebean-test support via ebean.test.platform=yugabyte
2022-02-01 13:30:49 +13:00
Rob Bygrave 6d0f5aea82 Yugabyte - ebean-test support via ebean.test.platform=yugabyte 2022-02-01 13:26:05 +13:00
Rob Bygrave 530a75b591 DB - test ddl changes 2022-02-01 13:24:50 +13:00
Rob Bygrave 13cfaba0c8 Yugabyte - Disable commit and continue test for Yugabyte (failing occasionally, need to review) 2022-02-01 11:55:26 +13:00
Rob Bygrave 1fa92efb63 Yugabyte - Adjust DbJsonTest wrt ordering in content, use JSON assertContainsResource()
Highlights that the DbJson assertContains() asserts are better longer term approach (over content matching asserts)
2022-02-01 11:55:15 +13:00
Rob Bygrave bc477c64cb Yugabyte - Disable commit and continue test for Yugabyte (failing occasionally, need to review) 2022-02-01 11:53:03 +13:00
Rob Bygrave 804098149e Yugabyte - Tidy tests with element collections not maintaining ordering 2022-02-01 11:51:46 +13:00
Rob Bygrave 567ad92050 Yugabyte - Tidy tests 2022-02-01 10:41:29 +13:00
Rob BygraveandGitHub 3a84cb8623 Merge pull request #2533 from ebean-orm/feature/yugabyte-json-hstore
Yugabyte - Fix some tests for running against Yugabyte
2022-02-01 09:50:05 +13:00
Rob Bygrave b4ddbe38ee Yugabyte - Fix some tests for running against Yugabyte 2022-02-01 09:49:23 +13:00
Rob BygraveandGitHub 01722b334b Merge pull request #2532 from FOCONIS/db2/unique_indices_with_null_columns
DB2 Support for unique indices with null columns
2022-02-01 08:16:43 +13:00
Rob BygraveandGitHub 0a780523cf Merge pull request #2529 from ebean-orm/feature/yugabyte-json-hstore
Yugabyte - Use Postgres ScalarTypes for JSON/JSONB but not HSTORE
2022-02-01 07:56:26 +13:00
Roland PramlandJonas Pöhler f2e04d9fbf DB2. Support for unique indices with null columns
(cherry picked from commit 23a5d577a6)
2022-01-31 13:58:40 +01:00
Jonas Pöhler 4b8565e7c7 FIX: we can set persistBatchOnCascade to ALL for newer DB2 versions 2022-01-31 11:32:22 +01:00
Rob Bygrave 1359d534d5 Yugabyte - Use Postgres ScalarTypes for JSON/JSONB but not HSTORE 2022-01-29 17:05:12 +13:00
Rob BygraveandGitHub 94ae513d85 Merge pull request #2522 from FOCONIS/db2/check-exception-chain
DB2: SqlCodeTranslator must check exception chain
2022-01-29 15:33:46 +13:00
Rob BygraveandGitHub d58c56484e Merge pull request #2517 from FOCONIS/fix-datasource
FIX: Datasource was not initialized in offline mode.
2022-01-29 15:28:53 +13:00
Rob BygraveandGitHub 75a27fa2d6 Merge pull request #2511 from FOCONIS/unselect-lobs
Unselect LOBs when making a distinct select
2022-01-29 15:25:00 +13:00
Rob BygraveandGitHub cc1c08cd34 Merge pull request #2528 from FOCONIS/db2/disabled-tests
DB2 Fix tests for DB2
2022-01-29 15:19:01 +13:00
Rob BygraveandGitHub 029cde12db Merge pull request #2527 from FOCONIS/db2/fix-sequence
DB2: Fix Sequence generator
2022-01-29 15:16:24 +13:00
Rob BygraveandGitHub b33914ab2f Merge pull request #2526 from FOCONIS/db2/no-null-values
DB2: Do not try to update deferred null values (Discovered by TestPrinterStateIssue)
2022-01-29 15:15:33 +13:00
Rob BygraveandGitHub d571a6c354 Merge pull request #2525 from FOCONIS/db2/truncate
DB2: truncate needs commit after each statement
2022-01-29 15:13:29 +13:00
Rob BygraveandGitHub 95b19569e4 Merge pull request #2524 from FOCONIS/db2/nocompressedid
DB2 does not support ids in compressed form
2022-01-29 15:12:25 +13:00
Rob BygraveandGitHub a9560c6664 Merge pull request #2523 from FOCONIS/db2/sqllimiter
DB2: FIX Db2SqlLimiter & tests
2022-01-29 15:11:33 +13:00
Rob BygraveandGitHub 235822bcb2 Merge pull request #2520 from FOCONIS/db2/fix-raw-like
DB2: Fix Raw like
2022-01-29 15:07:41 +13:00
Rob BygraveandGitHub 5a024ea19f Merge pull request #2519 from FOCONIS/db2/fix-default-values
DB2: Fix default values for auto generated ids
2022-01-29 15:06:54 +13:00
Rob BygraveandGitHub 399f8b92fa Merge pull request #2518 from FOCONIS/db2/fix-concat-operator
DB2: Fix Concat operator
2022-01-29 15:05:58 +13:00
Rob BygraveandGitHub be93263015 Merge pull request #2513 from FOCONIS/h2-backward-compat
Test against H2 1.4.199
2022-01-29 11:23:19 +13:00
Roland Praml b4fe4ec8b9 ADD.profile and autodetect code 2022-01-28 16:04:35 +01:00
Roland Praml 8c9f5f4a22 Disabled more tests for DB2 2022-01-28 11:38:11 +01:00
Roland Praml 953f8054e6 FIX: Clean up tests 2022-01-28 11:38:01 +01:00
Roland Praml aadb791980 FIX: isSame replaceed by isEqualTo 2022-01-28 11:37:48 +01:00
Roland Praml 7430f97c9c fix compile errors for EqlParserTest 2022-01-28 11:37:30 +01:00
Roland Praml ba21eeaadb DB2: Do not try to update deferred null values (Discovered by TestPrinterStateIssue) 2022-01-28 10:59:16 +01:00
Roland Praml c0e827ffda DB2: Fix Sequence generator 2022-01-28 10:57:41 +01:00
Roland Praml 3b30708dfc DB2: truncate needs commit after each statement 2022-01-28 10:56:01 +01:00
Roland Praml 9f9184ac6a DB2 does not support ids in compressed form 2022-01-28 10:53:51 +01:00
Roland Praml 5845f94303 DB2:ignored tests 2022-01-28 10:28:02 +01:00
Roland Praml dd824ffe52 DB2: Fix EqlParserTests similar to HANA 2022-01-28 10:27:50 +01:00
Roland Praml e5d29afa4c DB2: Disabled test for encryption, as it is not supported for Db2 2022-01-28 10:27:39 +01:00
Roland Praml 5ae5e408e3 DB2: FIX Db2SqlLimiter & tests 2022-01-28 10:23:22 +01:00
Roland Praml 90f6d0707f DB2: SqlCodeTranslator must check exception chain 2022-01-28 10:21:55 +01:00
Roland Praml 0310601e31 DB2: Fix getGenerateKeys (ungly workaround) 2022-01-28 10:06:34 +01:00
Roland Praml 015dd00b8e DB2: Fix Raw like 2022-01-28 10:04:20 +01:00
Roland Praml 6d978add29 DB2: Fix default values 2022-01-28 09:47:49 +01:00
Roland Praml e529232f76 DB2: Fix insert default values 2022-01-28 09:47:04 +01:00
Roland Praml d982ac73b7 DB2: Fix Concat operator 2022-01-28 09:38:41 +01:00
Roland Praml ddaff81b9c FIX: Datasource was not initialized in offline mode. 2022-01-28 09:29:12 +01:00
Rob BygraveandGitHub 1d11666945 Merge pull request #2516 from ebean-orm/feature/yugabyte-platform-ddl
Yugabyte platform support - Automatic detection and DDL support
2022-01-28 17:45:46 +13:00
Rob Bygrave 223e5160dc #2516 - Touch StartYugabyte 2022-01-28 17:26:58 +13:00
Rob Bygrave 64605b5090 Yugabyte platform support - Automatic detection and DDL support
- Automatic detection similar to Cockroach
- DDL very similar to Postgres but no CREATE TABLE LIKE support (for history DDL)
2022-01-28 17:04:19 +13:00
Rob Bygrave 425124d8f7 Adjust README for build badge changes 2022-01-28 10:55:22 +13:00
Rob Bygrave 6af8968280 Adjust workflow build for Oracle 18 2022-01-28 10:44:25 +13:00
Rob Bygrave a9bee03ba7 Add workflow build for Oracle 18 2022-01-28 09:57:49 +13:00
Rob BygraveandGitHub 302cc426bd Merge pull request #2515 from ebean-orm/feature/oracle-maxInBinding
Add maxInBinding - Oracle support for large delete by ids
2022-01-28 09:50:01 +13:00
Rob Bygrave 44462e3513 Add maxInBinding - Oracle support for large delete by ids 2022-01-28 09:46:03 +13:00
Rob Bygrave b748c598a1 build workflow rename for DB2 LUW 2022-01-28 09:04:56 +13:00
Rob Bygrave dbac184b4c Rename build workflows 2022-01-28 08:58:25 +13:00
Rob Bygrave 29c5916203 Add build workflow for db2 2022-01-28 08:54:21 +13:00
Rob BygraveandGitHub 827315a11d Merge pull request #2509 from ebean-orm/feature/jedis-4x
Support jedis 4.1.0 client (ScanParams, ScanResult in different package now)
2022-01-28 08:37:28 +13:00
Rob BygraveandGitHub 14ef8f6e0d Merge pull request #2512 from FOCONIS/introduce-db2
ADD: different DB2 platforms
2022-01-28 08:17:03 +13:00
Roland Praml 5b63434f13 reindent code and linked #2514 2022-01-27 16:43:35 +01:00
Roland Praml 3e8cc87f01 Add: github workflow for db2 2022-01-27 16:02:18 +01:00
Roland Praml 190b4ef588 Made some fixes in wrong ddl generation 2022-01-27 15:58:44 +01:00
Roland Praml 4a20c9eb99 Test against H2 1.4.199 2022-01-27 13:56:21 +01:00
Roland Praml d8c2b3d583 FIX: Compile errors 2022-01-27 10:34:25 +01:00
Roland Praml 48c8f5e2ca ADD: different DB2 platforms 2022-01-27 10:09:31 +01:00
Noemi SzemenyeiandRoland Praml 69a753fc4f DB2:Unselect LOBs when making a distinct select 2022-01-27 08:34:51 +01:00
Roland Praml b9ba6b2db5 DB2: Adapted Noemi's patch to new ebean version 2022-01-27 07:57:35 +01:00
Rob Bygrave 7a6071ac9a Support jedis 4.1.0 client (ScanParams, ScanResult in different package now) 2022-01-27 09:20:23 +13:00
Rob Bygrave 404b167bcc #2508 - Bump ebean-datasource to 7.5 2022-01-27 09:13:20 +13:00
Rob Bygrave 7278db56ea Modify test TestUuidGenerator to allow odd jvm variance in root error message 2022-01-27 09:12:57 +13:00
Rob BygraveandGitHub 1dc5ecc81f Merge pull request #2506 from FOCONIS/fix-localdate-databind
DB2: Fix: DataBind/Read of native LocalDates
2022-01-27 09:02:04 +13:00
Rob BygraveandGitHub c39661e2c2 Merge pull request #2505 from FOCONIS/refactor-uuid-v1-generator
Refactor UUID generator. Add uuid-property to serverConfig (#57)
2022-01-27 08:55:48 +13:00
Rob BygraveandGitHub a702bbb5ee Merge pull request #2504 from FOCONIS/sqlserver-delete-problem
Cannot delete bean with more than 2100 child beans on SqlServer
2022-01-27 08:54:27 +13:00
Roland PramlandRoland Praml 1982027300 Organized imports 2022-01-26 16:55:50 +01:00
Roland PramlandRoland Praml 2e1a6eec04 DB2: Fix: DataBind/Read of native LocalDates 2022-01-26 16:51:55 +01:00
Roland PramlandRoland Praml e5f37e638c Refactor UUID generator. Add uuid-property to serverConfig (#57)
Co-authored-by: Roland Praml <roland.praml@foconis.de>
2022-01-26 12:05:12 +01:00
Roland Praml 7ffea8e922 FIX: DeleteBatch for SQLServer 2022-01-26 11:59:35 +01:00
Roland Praml 315640df6b ADD: Failing test case 2022-01-26 11:59:17 +01:00
Rob Bygrave 78a647a72e Merge branch 'master' of github.com:ebean-orm/ebean 2022-01-26 22:42:10 +13:00
Rob Bygrave 7ffd2f1886 #2501 Modify pom use ${h2database.version} 2022-01-26 22:41:55 +13:00
Rob BygraveandGitHub 0087eabb4e Merge pull request #2502 from FOCONIS/fix-composite-id-in-select-distinct
Fix: composite id in select distinct queries
2022-01-26 22:22:18 +13:00
Rob BygraveandGitHub 5f0731f975 Merge pull request #2499 from ebean-orm/dependabot/maven/ebean-core/com.h2database-h2-2.1.210
Bump h2 from 1.4.199 to 2.1.210 in /ebean-core
2022-01-26 22:19:14 +13:00
Rob BygraveandGitHub 85e31899b9 Merge pull request #2498 from ebean-orm/dependabot/maven/ebean-test/com.h2database-h2-2.1.210
Bump h2 from 1.4.199 to 2.1.210 in /ebean-test
2022-01-26 22:18:50 +13:00
Rob BygraveandGitHub 3337541ac4 Merge pull request #2497 from ebean-orm/dependabot/maven/ebean-api/com.h2database-h2-2.1.210
Bump h2 from 1.4.199 to 2.1.210 in /ebean-api
2022-01-26 22:18:18 +13:00
Rob Bygrave b123b06f4d Merge branch 'wip/h2database-v2' 2022-01-26 22:08:52 +13:00
Rob Bygrave 17df5a2c16 Merge branch 'master' into wip/h2database-v2 2022-01-26 22:07:20 +13:00
Rob BygraveandGitHub e13aaefee1 Merge pull request #2500 from ebean-orm/feature/refactor-sqltreeload
Refactor internals split result load functionality from SqlTreeNode into SqlTreeLoad
2022-01-26 22:04:42 +13:00
Rob Bygrave 09ce693da2 Merge branch 'feature/refactor-sqltreeload' of github.com:ebean-orm/ebean into feature/refactor-sqltreeload 2022-01-26 22:00:40 +13:00
Rob Bygrave 17f7be72f4 Touch README.md 2022-01-26 22:00:28 +13:00
Rob Bygrave 23061473c7 Refactor internals split result load functionality from SqlTreeNode into SqlTreeLoad 2022-01-26 22:00:28 +13:00
Rob Bygrave 0944b87283 Merge branch 'wip/h2database-v2' of github.com:ebean-orm/ebean into wip/h2database-v2 2022-01-26 21:58:12 +13:00
Rob Bygrave 86768dfe4d Touch application-test.properties 2022-01-26 21:57:41 +13:00
Rob Bygrave ffdafc796b Touch README.md 2022-01-26 21:54:19 +13:00
Rob Bygrave 5466c6a350 Reduce logging when running Build tests 2022-01-26 21:51:48 +13:00
Rob Bygrave 7e0ac5a73a Fix issues with tests - tidy ResetBasicData 2022-01-26 21:47:00 +13:00
Noemi Szemenyei 008e1849a2 FIX: other queries for other platforms 2022-01-26 08:25:38 +01:00
Noemi Szemenyei dcf60a3d1c Trigger Build 2022-01-26 08:09:42 +01:00
Rob Bygrave 774cab327d Fix issues with test ordering - ordering in ResetBasicData 2022-01-26 17:23:18 +13:00
Rob Bygrave 2f824c99ea Fix issues with test ordering 2022-01-26 16:53:38 +13:00
Rob Bygrave 1a54fc12ad Test logging enabled for investigating CI Build issue 2022-01-26 15:48:03 +13:00
Rob Bygrave a1d6b280bc Bump test parent poms 2022-01-26 14:58:38 +13:00
Rob Bygrave fa561e5197 CI Build with single test and bump enhancement tiles 2022-01-26 14:52:32 +13:00
Rob Bygrave 4a8231a6cc CI Build using adopt distribution 2022-01-26 14:38:52 +13:00
Rob Bygrave 5cb486c745 CI Build without maven cache 2022-01-26 14:18:02 +13:00
Noemi Szemenyei dd26dc342d FIX: select properties of the embedded Id
(cherry picked from commit 58e952b1ec)
2022-01-25 09:42:27 +01:00
Noemi Szemenyei 7733e9382c ADD: failing test with select distinct with composite key and T0.NULL
(cherry picked from commit a08ba194b7)
2022-01-25 09:42:04 +01:00
Rob BygraveandGitHub bc6d2fb3be Merge branch 'master' into wip/h2database-v2 2022-01-25 21:30:36 +13:00
Rob Bygrave a9dbc036e9 Support H2database 2.x 2022-01-25 21:28:09 +13:00
Rob Bygrave 8d29a3a575 Bind LocalDate directly using JDBC driver to convert
This addresses issues with dates before 1900-01-01 with H2Database
2022-01-25 21:27:32 +13:00
Rob Bygrave 4158ac4665 Refactor internals split result load functionality from SqlTreeNode into SqlTreeLoad 2022-01-25 13:44:23 +13:00
dependabot[bot]andGitHub ddab6e65b7 Bump h2 from 1.4.199 to 2.1.210 in /ebean-core
Bumps [h2](https://github.com/h2database/h2database) from 1.4.199 to 2.1.210.
- [Release notes](https://github.com/h2database/h2database/releases)
- [Commits](https://github.com/h2database/h2database/compare/version-1.4.199...version-2.1.210)

---
updated-dependencies:
- dependency-name: com.h2database:h2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-01-21 23:47:28 +00:00
dependabot[bot]andGitHub bbede04a56 Bump h2 from 1.4.199 to 2.1.210 in /ebean-test
Bumps [h2](https://github.com/h2database/h2database) from 1.4.199 to 2.1.210.
- [Release notes](https://github.com/h2database/h2database/releases)
- [Commits](https://github.com/h2database/h2database/compare/version-1.4.199...version-2.1.210)

---
updated-dependencies:
- dependency-name: com.h2database:h2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-01-21 23:47:27 +00:00
dependabot[bot]andGitHub 9df96b0294 Bump h2 from 1.4.199 to 2.1.210 in /ebean-api
Bumps [h2](https://github.com/h2database/h2database) from 1.4.199 to 2.1.210.
- [Release notes](https://github.com/h2database/h2database/releases)
- [Commits](https://github.com/h2database/h2database/compare/version-1.4.199...version-2.1.210)

---
updated-dependencies:
- dependency-name: com.h2database:h2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-01-21 23:47:27 +00:00
Rob Bygrave 6a6b6b8200 Bump ebean-kotlin to 12.14.2-SNAPSHOT 2022-01-21 17:38:59 +13:00
Rob Bygrave e26e093680 Bump test poms to 12.14.2-SNAPSHOT 2022-01-21 17:38:03 +13:00
Rob BygraveandGitHub fc107115c6 Merge pull request #2494 from ebean-orm/FOCONIS-pr/enh/stored_procedures_mysql_drop_column
Optionally allow use of stored procedures for MySql to drop columns in db migration
2022-01-21 17:26:22 +13:00
Rob Bygrave 0139ad891e #2403 - table partitioning (Postgres only at this point) is always included + simplify skip logic 2022-01-21 17:20:21 +13:00
Rob Bygrave 4f70c09690 Merge branch 'pr/enh/stored_procedures_mysql_drop_column' of https://github.com/FOCONIS/ebean into FOCONIS-pr/enh/stored_procedures_mysql_drop_column 2022-01-21 17:06:48 +13:00
Rob Bygrave df8ae18bf6 [maven-release-plugin] prepare for next development iteration 2022-01-17 22:31:00 +13:00
Rob Bygrave 8edaabf755 [maven-release-plugin] prepare release ebean-parent-12.14.1 2022-01-17 22:30:53 +13:00
Rob Bygrave 25eea42211 Bump to ebean-migration 12.13.0 and ebean-agent 12.14.1 2022-01-17 22:28:36 +13:00
Rob Bygrave 263f6cdeba Tidy OraclePlatform only 2022-01-17 22:10:53 +13:00
Rob Bygrave 38f1967e60 #2473 - Oracle - column alias - Change such that OraclePlatform doesn't use column alias
So with #2254 we regressed OraclePlatform to use column alias. This really should have introduced an Oracle12 platform instead. 18c onwards and we don't want the column alias.
2022-01-17 22:10:21 +13:00
Rob Bygrave 6eb8eb0dd2 #2473 Tidy BasicSqlAnsiLimiter only, no functional change 2022-01-17 21:58:33 +13:00
Rob Bygrave 1165d857d8 Fix test ParentQueryTest 2022-01-17 21:57:14 +13:00
Rob Bygrave 874c2f5231 #2492 - Fix for Oracle platform when insert only default values 2022-01-17 21:42:09 +13:00
Rob Bygrave 88ab852855 No real change, tidy DbExpressionHandlerFactory only 2022-01-17 21:28:45 +13:00
Rob Bygrave b577331524 #2492 - Fix for Oracle platform when insert only default values 2022-01-17 21:27:42 +13:00
Rob Bygrave ec45fc1c86 Fix tests for Oracle - BITADD in @Where clause expression 2022-01-17 21:26:19 +13:00
Rob Bygrave e65876e8ed #2477 - Add failing test case (disable for the moment) 2022-01-17 20:58:19 +13:00
Rob BygraveandGitHub 5453037172 Merge pull request #2491 from ebean-orm/feature/2476-elementCollectionConstructor
#2476 - Fix for element collection on bean with default constructor
2022-01-17 15:41:33 +13:00
Rob Bygrave 9b116c9bf6 #2476 - tidy tests 2022-01-17 15:38:41 +13:00
Rob Bygrave 82862deccc #2476 - Fix for element collection on bean with default constructor
Note that we can look for a better longer term fix which might would look at treating element collection more like ToMany collections in terms of enhancement.
2022-01-17 15:36:26 +13:00
Rob Bygrave 1c83bbe0b0 #2476 - Failing test for element collection on bean with default constructor 2022-01-17 15:33:13 +13:00
Rob BygraveandGitHub f16f34f35f Merge pull request #2488 from ebean-orm/feature/2487
#2487 - ebean-test support Docker In Docker - docker container's hostname rather than hardcoded "localhost"
2022-01-14 16:32:04 +13:00
Rob Bygrave 38bc5b2fea #2488 - refactor extract logic into DockerHost helper, fix RedisSetup, pass docker host to ebean-test-docker 2022-01-14 16:27:04 +13:00
Rob Bygrave 356dc5eb19 #2487 - ebean-test support Docker In Docker - docker container's hostname rather than hardcoded "localhost" 2022-01-13 15:02:38 +13:00
Rob BygraveandGitHub c5779133bc Merge pull request #2485 from FOCONIS/fix-utf8-problems-with-specialchars
Fix utf8 problems with specialchars
2022-01-13 11:05:27 +13:00
Rob BygraveandGitHub b8b6311348 Merge pull request #2447 from FOCONIS/fix-scalartype-problem2
Traverse class hierarchy, when searching for ScalarType
2022-01-13 10:58:05 +13:00
FOCONIS\szemenyei 8eed983fbb restore old test 2022-01-12 08:37:46 +01:00
Rob BygraveandGitHub 7cfecb83a9 Merge pull request #2486 from bigjimlefou/fixWindows
Fix some tests failing on Windows
2022-01-12 09:17:37 +13:00
bigjimlefou e92939a34d Fix failing test on Windows platform 2022-01-11 15:41:20 +01:00
bigjimlefou 408b982eb3 Use of platform-specific specific file separator 2022-01-11 15:41:19 +01:00
bigjimlefou dd7e7711a8 Use of platform-specific specific file separator 2022-01-11 15:41:19 +01:00
bigjimlefou 5a3f7853a6 Fix failing test on Windows platform. 2022-01-11 15:41:19 +01:00
Roland PramlandFOCONIS\szemenyei 01847e44de Always use UTF-8 2022-01-11 10:11:13 +01:00
FOCONIS\szemenyei 0cf9f0bf58 Revert "at first revert solution"
This reverts commit b01b44af10.
2022-01-11 09:49:02 +01:00
FOCONIS\szemenyei b01b44af10 at first revert solution 2022-01-11 09:48:47 +01:00
FOCONIS\szemenyei 8d85000970 Fix Checksum calculate() with special characters
(cherry picked from commit e9efd5a702)
2022-01-11 09:47:44 +01:00
Jonas Pöhler e7f9c63502 Clear up some possible confusion in the test 2022-01-05 15:46:34 +01:00
Jonas Pöhler eb21b41fba Refactor and fixes for interfaces (like Path) + extend existing tests 2022-01-05 14:22:24 +01:00
Jonas Pöhler 3dc6c567a0 Merge remote-tracking branch 'ebean/master' into fix-scalartype-problem2 2022-01-05 13:34:29 +01:00
Rob BygraveandGitHub 18eed47306 Merge pull request #2475 from bigjimlefou/fixLocale
Fix locale problem with TestCsvReader and TestCsvReaderWithCallback.
2021-12-24 11:10:05 +13:00
Cédric Sougné 9ddf1333ed Fix locale problem with TestCsvReader and TestCsvReaderWithCallback. 2021-12-23 17:19:44 +01:00
Rob Bygrave 73896d375f Bump test modules to 12.14.1-SNAPSHOT after release 2021-12-20 16:49:18 +13:00
Rob Bygrave 3f645211a6 [maven-release-plugin] prepare for next development iteration 2021-12-20 16:34:23 +13:00
Rob Bygrave 860aad11ce WIP h2database v2 2021-12-17 23:22:25 +13:00
Roland Praml f830662cce Improve TypeManager - cache typeNotFound information. 2021-12-02 11:18:22 +01:00
Roland Praml 84ac737ceb ADD: Testcase for Calendar 2021-12-02 10:42:49 +01:00
Roland Praml 483f0398b2 Fix: 'No ScalarType registered for class java.util.GregorianCalendar' - check all registered scalar type if no exact match was found 2021-12-02 08:30:24 +01:00
Jonas Pöhler c67e66c0ca Merge remote-tracking branch 'ebean/master' into pr/enh/stored_procedures_mysql_drop_column 2021-11-26 15:58:50 +01:00
Jonas Pöhler b60f9201a9 FIX: MysqlGenerateMigrationTest now clears pendingDrops System-Property 2021-11-26 15:58:20 +01:00
Jonas Pöhler 3fe521c53a Merge remote-tracking branch 'ebean/master' into pr/enh/stored_procedures_mysql_drop_column 2021-09-29 16:13:49 +02:00
Jonas Pöhler 091b5fbf26 Optionally allow use of stored procedures for MySql to drop columns in db migration 2021-09-27 17:08:22 +02:00
628 changed files with 13582 additions and 5415 deletions
+5 -1
View File
@@ -31,6 +31,10 @@ jobs:
path:
~/.m2
key: build-${{ env.cache-name }}
- name: Maven version
run: mvn --version
# - 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 package
run: mvn clean package
+38
View File
@@ -0,0 +1,38 @@
name: DB2 LUW
on:
workflow_dispatch:
schedule:
- cron: '10 8 * * 2,5'
jobs:
build:
runs-on: ${{ matrix.os }}
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
java_version: [11]
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v2
- name: Set up Java
uses: actions/setup-java@v2
with:
java-version: ${{ matrix.java_version }}
distribution: 'adopt'
- name: Maven cache
uses: actions/cache@v2
env:
cache-name: maven-cache
with:
path:
~/.m2
key: build-${{ env.cache-name }}
- name: db2
run: mvn clean test -Dprops.file=testconfig/ebean-db2.properties
+41
View File
@@ -0,0 +1,41 @@
name: H2Database
on:
workflow_dispatch:
schedule:
- cron: '10 1 * * *'
jobs:
build:
runs-on: ${{ matrix.os }}
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
java_version: [11]
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v2
- name: Set up Java
uses: actions/setup-java@v2
with:
java-version: ${{ matrix.java_version }}
distribution: 'zulu'
- name: Maven cache
uses: actions/cache@v2
env:
cache-name: maven-cache
with:
path:
~/.m2
key: build-${{ env.cache-name }}
- name: Maven version
run: mvn --version
- name: H2Database
run: mvn clean package
@@ -1,5 +1,5 @@
name: MariaDB 10.6
name: MariaDB
on:
workflow_dispatch:
@@ -1,5 +1,5 @@
name: Multi-database platform test
name: Multi-database platform
on: [workflow_dispatch]
@@ -31,15 +31,21 @@ jobs:
path:
~/.m2
key: build-${{ env.cache-name }}
- name: h2
- name: h2database
run: mvn clean test
- name: postgres
run: mvn clean test -Dprops.file=testconfig/ebean-postgres.properties
- name: mysql
run: mvn clean test -Dprops.file=testconfig/ebean-mysql.properties
- name: sqlserver 2019
run: mvn clean test -Dprops.file=testconfig/ebean-sqlserver19.properties
- name: sqlserver 2017
run: mvn clean test -Dprops.file=testconfig/ebean-sqlserver17.properties
- name: mariadb
run: mvn clean test -Dprops.file=testconfig/ebean-mariadb.properties
- name: yugabyte
run: mvn clean test -Dprops.file=testconfig/ebean-yugabyte.properties
- name: sqlserver
run: mvn clean test -Dprops.file=testconfig/ebean-sqlserver17.properties
# - name: sqlserver19
# run: mvn clean test -Dprops.file=testconfig/ebean-sqlserver19.properties
# - name: db2
# run: mvn clean test -Dprops.file=testconfig/ebean-db2.properties
# - name: oracle
# run: mvn clean test -Dprops.file=testconfig/ebean-oracle.properties
+38
View File
@@ -0,0 +1,38 @@
name: Oracle18
on:
workflow_dispatch:
schedule:
- cron: '10 6 * * 1,4'
jobs:
build:
runs-on: ${{ matrix.os }}
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
java_version: [11]
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v2
- name: Set up Java
uses: actions/setup-java@v2
with:
java-version: ${{ matrix.java_version }}
distribution: 'zulu'
- name: Maven cache
uses: actions/cache@v2
env:
cache-name: maven-cache
with:
path:
~/.m2
key: build-${{ env.cache-name }}
- name: oracle
run: mvn clean test -Dprops.file=testconfig/ebean-oracle.properties
@@ -1,5 +1,5 @@
name: SqlServer 2019 latest
name: SqlServer 2019
on: [workflow_dispatch]
@@ -1,5 +1,5 @@
name: SqlServer 2017 latest
name: SqlServer
on:
workflow_dispatch:
@@ -34,7 +34,5 @@ jobs:
path:
~/.m2
key: build-${{ env.cache-name }}
# - name: sqlserver 2019 latest
# run: mvn clean test -Dprops.file=testconfig/ebean-sqlserver.properties
- name: sqlserver 2017 latest
- name: sqlserver 2017
run: mvn clean test -Dprops.file=testconfig/ebean-sqlserver17.properties
+38
View File
@@ -0,0 +1,38 @@
name: Yugabyte
on:
workflow_dispatch:
schedule:
- cron: '10 3 * * *'
jobs:
build:
runs-on: ${{ matrix.os }}
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
java_version: [11]
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v2
- name: Set up Java
uses: actions/setup-java@v2
with:
java-version: ${{ matrix.java_version }}
distribution: 'adopt'
- name: Maven cache
uses: actions/cache@v2
env:
cache-name: maven-cache
with:
path:
~/.m2
key: build-${{ env.cache-name }}
- name: yugabyte
run: mvn clean test -Dprops.file=testconfig/ebean-yugabyte.properties
+201
View File
@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2012 Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-15
View File
@@ -1,15 +0,0 @@
EbeanORM
Copyright 2012 Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+4 -5
View File
@@ -4,10 +4,12 @@
[![Multi-JDK Build](https://github.com/ebean-orm/ebean/actions/workflows/multi-jdk-build.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/multi-jdk-build.yml)
[![JDK 18-ea](https://github.com/ebean-orm/ebean/actions/workflows/jdk-18-ea.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/jdk-18-ea.yml)
[![H2Database](https://github.com/ebean-orm/ebean/actions/workflows/h2database.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/h2database.yml)
[![Postgres](https://github.com/ebean-orm/ebean/actions/workflows/postgres.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/postgres.yml)
[![MySql](https://github.com/ebean-orm/ebean/actions/workflows/mysql.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/mysql.yml)
[![MariaDB](https://github.com/ebean-orm/ebean/actions/workflows/mariadb-10.6.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/mariadb-10.6.yml)
[![SqlServer](https://github.com/ebean-orm/ebean/actions/workflows/sqlserver-2017-latest.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/sqlserver-2017-latest.yml)
[![MariaDB](https://github.com/ebean-orm/ebean/actions/workflows/mariadb.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/mariadb.yml)
[![SqlServer](https://github.com/ebean-orm/ebean/actions/workflows/sqlserver.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/sqlserver.yml)
[![Yugabyte](https://github.com/ebean-orm/ebean/actions/workflows/yugabyte.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/yugabyte.yml)
# Sponsors
<table>
@@ -49,6 +51,3 @@ Goto [https://ebean.io/docs/](https://ebean.io/docs/)
[Maven central - all related projects](http://search.maven.org/#search%7Cga%7C1%7Cebean "maven central all related projects")
## Other versions
* [![Maven Central : ebean-agent](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean-agent/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean-agent) - ebean-agent
* [![Maven Central : ebean-maven-plugin](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean-maven-plugin/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean-maven-plugin) - ebean-maven-plugin
+3 -3
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.14.0</version>
<version>12.15.1</version>
</parent>
<name>ebean api</name>
@@ -49,7 +49,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-annotation</artifactId>
<version>7.3</version>
<version>7.6</version>
</dependency>
<dependency>
@@ -85,7 +85,7 @@
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.199</version>
<version>${h2database.version}</version>
<optional>true</optional>
</dependency>
@@ -1,6 +1,7 @@
package io.ebean;
import java.net.URL;
import java.nio.file.Path;
import java.util.Map;
/**
@@ -23,10 +24,10 @@ public interface ScriptRunner {
/**
* Run a script given the resource path (that should start with "/").
*/
void run(String path);
void run(String resourcePath);
/**
* Run a script given the resource path (that should start with "/") and place holders.
* Run a script given the resource path (that should start with "/") and place-holders.
*
* <pre>{@code
*
@@ -38,7 +39,7 @@ public interface ScriptRunner {
*
* }</pre>
*/
void run(String path, Map<String, String> placeholderMap);
void run(String resourcePath, Map<String, String> placeholderMap);
/**
* Run a DDL or SQL script given the resource.
@@ -46,10 +47,20 @@ public interface ScriptRunner {
void run(URL resource);
/**
* Run a DDL or SQL script given the resource and place holders.
* Run a DDL or SQL script given the resource and place-holders.
*/
void run(URL resource, Map<String, String> placeholderMap);
/**
* Run a DDL or SQL script given the file.
*/
void run(Path file);
/**
* Run a DDL or SQL script given the file and place-holders.
*/
void run(Path file, Map<String, String> placeholderMap);
/**
* Run the raw provided DDL or SQL script.
*
@@ -98,4 +98,14 @@ public class Version<T> {
public Map<String, ValuePair> getDiff() {
return diff;
}
@Override
public String toString() {
return "Version{" +
"bean=" + bean +
", start=" + start +
", end=" + end +
", diff=" + diff +
'}';
}
}
@@ -360,7 +360,7 @@ public final class EntityBeanIntercept implements Serializable {
* Return true if the entity should be updated.
*/
public boolean isUpdate() {
return forceUpdate || state == STATE_LOADED;
return forceUpdate || state == STATE_LOADED || state == STATE_REFERENCE;
}
/**
@@ -371,6 +371,33 @@ public class DatabaseConfig {
*/
private String uuidStateFile;
/**
* The node id (=mac address) for Version 1 UUIDs. There are several options:
* <ul>
* <li><code>null</code> (default) The generator tries to get the hardwarwe MAC
* address. If this fails, it will fall back to 'generate' mode.</li>
* <li><code>"generate"</code> Hardware detection is skipped. It generates a
* random identifier and tries to persist this to the state file. This nodeId
* will be reused on next start. If persisting to the state file will fail also,
* it will fall back to 'random' mode.<br>
* This mode is good, if the MAC address is not reliable, e.g. if you run
* multiple ebean instances on the same machine.</li>
* <li><code>"random"</code> In this mode, a random node id is generated on each
* start. No stateFile is used. it will generate a new nodeId on each
* application start.<br>
* This mode is good, if you have no write access to save the state file.</li>
* <li><code>"xx-xx-xx-xx-xx-xx"</code> When an explicit nodeId is specified,
* this one is used.</li>
* </ul>
* Note: It is possible that multiple servers are sharing the same state file as
* long as they are in the <b>same</b> JVM/ClassLoader scope. In this case it is
* recommended to use the same uuidNodeId configuration.
*
* If you have multiple servers in different JVMs, do <b>not</b> share the state
* files!
*/
private String uuidNodeId;
/**
* The clock used for setting the timestamps (e.g. @UpdatedTimestamp) on objects.
*/
@@ -2019,6 +2046,20 @@ public class DatabaseConfig {
public void setUuidStateFile(String uuidStateFile) {
this.uuidStateFile = uuidStateFile;
}
/**
* Returns the V1-UUID-NodeId
*/
public String getUuidNodeId() {
return uuidNodeId;
}
/**
* Sets the V1-UUID-NodeId.
*/
public void setUuidNodeId(String uuidNodeId) {
this.uuidNodeId = uuidNodeId;
}
/**
* Return true if LocalTime should be persisted with nanos precision.
@@ -2888,6 +2929,7 @@ public class DatabaseConfig {
uuidVersion = p.getEnum(UuidVersion.class, "uuidVersion", uuidVersion);
uuidStateFile = p.get("uuidStateFile", uuidStateFile);
uuidNodeId = p.get("uuidNodeId", uuidNodeId);
localTimeWithNanos = p.getBoolean("localTimeWithNanos", localTimeWithNanos);
jodaLocalTimeMode = p.get("jodaLocalTimeMode", jodaLocalTimeMode);
@@ -66,6 +66,8 @@ public class PlatformConfig {
private boolean caseSensitiveCollation = true;
private boolean useMigrationStoredProcedures = false;
/**
* Modify the default mapping of standard types such as default precision for DECIMAL etc.
*/
@@ -90,6 +92,7 @@ public class PlatformConfig {
this.geometrySRID = platformConfig.geometrySRID;
this.dbUuid = platformConfig.dbUuid;
this.caseSensitiveCollation = platformConfig.caseSensitiveCollation;
this.useMigrationStoredProcedures = platformConfig.useMigrationStoredProcedures;
this.allQuotedIdentifiers = platformConfig.allQuotedIdentifiers;
this.databaseInetAddressVarchar = platformConfig.databaseInetAddressVarchar;
this.customDbTypeMappings = platformConfig.customDbTypeMappings;
@@ -142,6 +145,20 @@ public class PlatformConfig {
this.caseSensitiveCollation = caseSensitiveCollation;
}
/**
* Return true if force use of helper stored procedures for migrations.
*/
public boolean isUseMigrationStoredProcedures() {
return useMigrationStoredProcedures;
}
/**
* Set true to force use of helper stored procedures for migrations.
*/
public void setUseMigrationStoredProcedures(boolean useMigrationStoredProcedures) {
this.useMigrationStoredProcedures = useMigrationStoredProcedures;
}
/**
* Return true if Postgres FOR UPDATE should use the NO KEY option.
*/
@@ -317,6 +334,7 @@ public class PlatformConfig {
databaseBooleanFalse = p.get("databaseBooleanFalse", databaseBooleanFalse);
databaseInetAddressVarchar = p.getBoolean("databaseInetAddressVarchar", databaseInetAddressVarchar);
caseSensitiveCollation = p.getBoolean("caseSensitiveCollation", caseSensitiveCollation);
useMigrationStoredProcedures = p.getBoolean("useMigrationStoredProcedures", useMigrationStoredProcedures);
DbUuid dbUuid = p.getEnum(DbUuid.class, "dbuuid", null);
if (dbUuid != null) {
@@ -7,13 +7,10 @@ public class BasicSqlAnsiLimiter implements BasicSqlLimiter {
@Override
public String limit(String dbSql, int firstRow, int maxRows) {
StringBuilder sb = new StringBuilder(50 + dbSql.length());
sb.append(dbSql);
if (firstRow > 0) {
sb.append(" ").append("offset");
sb.append(" ").append(firstRow).append(" rows");
sb.append(" offset ").append(firstRow).append(" rows");
}
if (maxRows > 0) {
sb.append(" fetch next ").append(maxRows).append(" rows only");
@@ -15,6 +15,7 @@ import javax.persistence.PersistenceException;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
@@ -53,6 +54,17 @@ public class DatabasePlatform {
protected boolean supportsSavepointId = true;
protected boolean useMigrationStoredProcedures = false;
/**
* Can we use native java time API objects in
* {@link ResultSet#getObject(int, Class)} and
* {@link PreparedStatement#setObject(int, Object)}.
*
* Not all drivers (DB2 e.g.) will support this.
*/
protected boolean supportsNativeJavaTime = true;
/**
* The behaviour used when ending a read only transaction at read committed isolation level.
*/
@@ -202,6 +214,8 @@ public class DatabasePlatform {
*/
protected PersistBatch persistBatchOnCascade = PersistBatch.ALL;
protected int maxInBinding;
/**
* The maximum length of table names - used specifically when derived
* default table names for intersection tables.
@@ -237,6 +251,7 @@ public class DatabasePlatform {
public void configure(PlatformConfig config) {
this.sequenceBatchSize = config.getDatabaseSequenceBatchSize();
this.caseSensitiveCollation = config.isCaseSensitiveCollation();
this.useMigrationStoredProcedures = config.isUseMigrationStoredProcedures();
configureIdType(config.getIdType());
configure(config, config.isAllQuotedIdentifiers());
}
@@ -343,6 +358,13 @@ public class DatabasePlatform {
return supportsSavepointId;
}
/**
* Return true if migrations should use stored procedures.
*/
public boolean isUseMigrationStoredProcedures() {
return useMigrationStoredProcedures;
}
/**
* Return true if the platform supports LIMIT with sql update.
*/
@@ -350,6 +372,13 @@ public class DatabasePlatform {
return inlineSqlUpdateLimit;
}
/**
* Return the maximum number of bind values this database platform allows or zero for no limit.
*/
public int getMaxInBinding() {
return maxInBinding;
}
/**
* Return the maximum table name length.
* <p>
@@ -573,11 +602,8 @@ public class DatabasePlatform {
this.supportsResultSetConcurrencyModeUpdatable = supportsResultSetConcurrencyModeUpdatable;
}
/**
* Normally not needed - overridden in CockroachPlatform.
*/
public boolean isDdlAutoCommit() {
return false;
public void setUseMigrationStoredProcedures(final boolean useMigrationStoredProcedures) {
this.useMigrationStoredProcedures = useMigrationStoredProcedures;
}
/**
@@ -813,4 +839,8 @@ public class DatabasePlatform {
protected void escapeLikeCharacter(char ch, StringBuilder sb) {
sb.append(likeEscapeChar).append(ch);
}
public boolean supportsNativeJavaTime() {
return supportsNativeJavaTime;
}
}
@@ -31,14 +31,39 @@ public class SqlCodeTranslator implements SqlExceptionTranslator {
this.map = Collections.emptyMap();
}
@Override
public PersistenceException translate(String message, SQLException e) {
private DataErrorType getErrorType(SQLException e) {
DataErrorType errorType = map.get(e.getSQLState());
if (errorType == null) {
// fall back to error code
errorType = map.get(String.valueOf(e.getErrorCode()));
}
return errorType;
}
@Override
public PersistenceException translate(String message, SQLException e) {
DataErrorType errorType = getErrorType(e);
// for DB2 we must inspect the sql exception chain to determine which
// persistence error occurred in a batch execution. We also concatenate
// the error messages to improve error analysis.
SQLException chain = e.getNextException();
if (chain != null) {
StringBuilder sb = new StringBuilder(message);
int i = 1;
while (chain != null && i < 100000) { // prevents from endless loop
sb.append("\n\t#").append(i++).append(": ").append(chain.getMessage());
if (errorType == null) {
errorType = getErrorType(chain);
if (errorType != null) {
sb.append(" (causing error)"); // mark the line, where we found a matching error code
}
}
chain = chain.getNextException();
}
message = sb.toString();
}
if (errorType != null) {
switch (errorType) {
case AcquireLock:
@@ -11,18 +11,7 @@ public class CockroachPlatform extends PostgresPlatform {
public CockroachPlatform() {
super();
this.platform = Platform.COCKROACH;
// no like escape clause supported
this.likeSpecialCharacters = new char[]{'%', '_'};
this.likeClauseRaw = "like ?";
this.likeClauseEscaped = "like ?";
}
/**
* Needs a commit after create index such that alter table add foreign key ... succeeds.
*/
@Override
public boolean isDdlAutoCommit() {
return true;
this.historySupport = null; // not yet implemented in DDL
}
}
@@ -1,7 +1,6 @@
package io.ebean.config.dbplatform.db2;
import io.ebean.BackgroundExecutor;
import io.ebean.annotation.PersistBatch;
import io.ebean.annotation.Platform;
import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebean.config.dbplatform.DbPlatformType;
@@ -15,21 +14,19 @@ import java.sql.Types;
/**
* DB2 specific platform.
*/
public class DB2Platform extends DatabasePlatform {
public abstract class BaseDB2Platform extends DatabasePlatform {
public DB2Platform() {
public BaseDB2Platform() {
super();
this.platform = Platform.DB2;
// Note: DB2 (at least LUW supports length up to 128)
// TOOD: Check if we need to introduce a new platform (DB2_LUW_11 ?)
this.maxTableNameLength = 18;
this.maxConstraintNameLength = 18;
this.supportsNativeJavaTime = false;
this.truncateTable = "truncate table %s reuse storage ignore delete triggers immediate";
this.likeClauseRaw = "like ?";
this.sqlLimiter = new Db2SqlLimiter();
this.dbIdentity.setSupportsGetGeneratedKeys(true);
this.dbIdentity.setSupportsSequence(true);
this.idInExpandedForm = true; // Db2 does not support (a,b) in ((?,?),(?,?))
this.exceptionTranslator =
new SqlErrorCodes()
.addAcquireLock("40001","57033") // key -911/-913
@@ -45,7 +42,6 @@ public class DB2Platform extends DatabasePlatform {
dbTypeMap.put(DbType.BIGINT, new DbPlatformType("bigint", false));
dbTypeMap.put(DbType.REAL, new DbPlatformType("real"));
dbTypeMap.put(DbType.DECIMAL, new DbPlatformType("decimal", 16, 3));
persistBatchOnCascade = PersistBatch.NONE;
}
/**
@@ -0,0 +1,39 @@
package io.ebean.config.dbplatform.db2;
import io.ebean.annotation.Platform;
import io.ebean.config.dbplatform.DbPlatformType;
import io.ebean.config.dbplatform.DbType;
import io.ebean.config.dbplatform.SqlErrorCodes;
import java.sql.Types;
/**
* DB2 specific platform for i Series.
*
* @author Cédric Sougné
*/
public class DB2ForIPlatform extends BaseDB2Platform {
public DB2ForIPlatform() {
super();
this.platform = Platform.DB2FORI;
// Note: IBM i from 7.1 allow up to to 128
// TODO: Check if we need to introduce older platform (DB2ForI_6 ? but older
// documentation is not anymore published on ibm.com),
this.maxTableNameLength = 128;
this.maxConstraintNameLength = 128;
this.dbIdentity.setSupportsIdentity(true);
this.exceptionTranslator = new SqlErrorCodes().addAcquireLock("57033") // key -913
.addDuplicateKey("23505") // -803
// .addDataIntegrity("-407","-530","-531","-532","-543","-544","-545","-603","-667")
// we need SQLState, not code:
// https://www.ibm.com/support/knowledgecenter/en/SSEPEK_10.0.0/codes/src/tpc/db2z_n.html
.addDataIntegrity("23502", "23503", "23504", "23507", "23511", "23512", "23513", "42917", "23515")
.build();
booleanDbType = Types.SMALLINT;
dbTypeMap.put(DbType.BOOLEAN, new DbPlatformType("smallint default 0"));
}
}
@@ -0,0 +1,22 @@
package io.ebean.config.dbplatform.db2;
import io.ebean.annotation.PersistBatch;
import io.ebean.annotation.Platform;
/**
* DB2 specific platform for older DB2 versions. This platform is here for
* compatibility reasons. It uses a length limit of 18 chars for table and
* constraint names. Newer DB2 versions will support up to 128. It is strongly
* recommended to migrate to db2luw/DB2ForI or db2zos platform.
*/
public class DB2LegacyPlatform extends BaseDB2Platform {
public DB2LegacyPlatform() {
super();
this.platform = Platform.DB2;
// Note: DB2 (at least LUW supports length up to 128)
// TOOD: Check if we need to introduce a new platform (DB2_LUW_11 ?)
this.maxTableNameLength = 18;
this.maxConstraintNameLength = 18;
this.persistBatchOnCascade = PersistBatch.NONE;
}
}
@@ -0,0 +1,17 @@
package io.ebean.config.dbplatform.db2;
import io.ebean.annotation.Platform;
/**
* DB2 platform for Linux/Unix/Windows.
* @author Roland Praml, FOCONIS AG
*
*/
public class DB2LuwPlatform extends BaseDB2Platform {
public DB2LuwPlatform() {
super();
this.platform = Platform.DB2LUW;
this.maxTableNameLength = 128;
this.maxConstraintNameLength = 128;
}
}
@@ -19,7 +19,7 @@ public class DB2SequenceIdGenerator extends SequenceBatchIdGenerator {
public DB2SequenceIdGenerator(BackgroundExecutor be, DataSource ds, String seqName, int batchSize) {
super(be, ds, seqName, batchSize);
this.baseSql = "values nextval for " + seqName;
this.unionBaseSql = " union " + baseSql;
this.unionBaseSql = ", nextval for " + seqName;
}
@Override
@@ -0,0 +1,18 @@
package io.ebean.config.dbplatform.db2;
import io.ebean.annotation.Platform;
/**
* DB2 platform for z/OS.
* Note: This platform is currently not tested!
* @author Roland Praml, FOCONIS AG
*
*/
public class DB2ZosPlatform extends BaseDB2Platform {
public DB2ZosPlatform() {
super();
this.platform = Platform.DB2ZOS;
this.maxTableNameLength = 128;
this.maxConstraintNameLength = 128;
}
}
@@ -15,10 +15,13 @@ public class Db2SqlLimiter implements SqlLimiter {
sb.append("distinct ");
}
sb.append(request.getDbSql());
int firstRow = request.getFirstRow();
if (firstRow > 0) {
sb.append(" offset ").append(firstRow).append(" rows");
}
int maxRows = request.getMaxRows();
if (maxRows > 0) {
sb.append(" ").append(NEW_LINE).append("FETCH FIRST ").append(maxRows).append(" ROWS ONLY");
sb.append(" fetch next ").append(maxRows).append(" rows only");
}
String sql = request.getDbPlatform().completeSql(sb.toString(), request.getOrmQuery());
@@ -5,6 +5,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.*;
import java.time.LocalDateTime;
import java.util.Arrays;
/**
@@ -76,7 +77,7 @@ public class H2HistoryTrigger implements Trigger {
public void fire(Connection connection, Object[] oldRow, Object[] newRow) throws SQLException {
if (oldRow != null) {
// a delete or update event
Timestamp now = new Timestamp(System.currentTimeMillis());
LocalDateTime now = LocalDateTime.now();
oldRow[effectEndPosition] = now;
if (newRow != null) {
// update event. Set the effective start timestamp to now.
@@ -39,6 +39,7 @@ public class H2Platform extends DatabasePlatform {
this.dbIdentity.setSupportsIdentity(true);
dbTypeMap.put(DbType.UUID, new DbPlatformType("uuid", false));
dbTypeMap.put(DbType.INTEGER, new DbPlatformType("integer", false));
}
/**
@@ -18,13 +18,12 @@ public class H2SequenceIdGenerator extends SequenceBatchIdGenerator {
*/
public H2SequenceIdGenerator(BackgroundExecutor be, DataSource ds, String seqName, int batchSize) {
super(be, ds, seqName, batchSize);
this.baseSql = "select " + seqName + ".nextval";
this.baseSql = "select nextval('" + seqName + "')";
this.unionBaseSql = " union " + baseSql;
}
@Override
public String getSql(int batchSize) {
StringBuilder sb = new StringBuilder();
sb.append(baseSql);
for (int i = 1; i < batchSize; i++) {
@@ -92,4 +92,8 @@ public class HanaPlatform extends DatabasePlatform {
}
}
@Override
public boolean isUseMigrationStoredProcedures() {
return true;
}
}
@@ -11,6 +11,7 @@ public class Oracle11Platform extends OraclePlatform {
public Oracle11Platform() {
super();
this.platform = Platform.ORACLE11;
this.columnAliasPrefix = "c";
this.sqlLimiter = new OracleRownumSqlLimiter();
this.basicSqlLimiter = new OracleRownumBasicLimiter();
dbIdentity.setIdType(IdType.SEQUENCE);
@@ -0,0 +1,13 @@
package io.ebean.config.dbplatform.oracle;
/**
* Oracle 12 platform using column alias.
*/
public class Oracle12Platform extends OraclePlatform {
public Oracle12Platform() {
super();
//this.platform = Platform.ORACLE12;
this.columnAliasPrefix = "c";
}
}
@@ -22,8 +22,8 @@ public class OraclePlatform extends DatabasePlatform {
public OraclePlatform() {
super();
this.platform = Platform.ORACLE;
this.columnAliasPrefix = "c";
this.supportsDeleteTableAlias = true;
this.maxInBinding = 1000;
this.maxTableNameLength = 30;
this.maxConstraintNameLength = 30;
this.dbEncrypt = new OracleDbEncrypt();
@@ -35,11 +35,9 @@ public class OraclePlatform extends DatabasePlatform {
dbIdentity.setSupportsSequence(true);
dbIdentity.setSupportsIdentity(true);
dbIdentity.setSupportsGetGeneratedKeys(true);
this.dbDefaultValue.setFalse("0");
this.dbDefaultValue.setTrue("1");
this.dbDefaultValue.setNow("current_timestamp");
this.treatEmptyStringsAsNull = true;
this.likeClauseRaw = "like ?";
@@ -56,7 +54,6 @@ public class OraclePlatform extends DatabasePlatform {
booleanDbType = Types.INTEGER;
dbTypeMap.put(DbType.BOOLEAN, new DbPlatformType("number(1)"));
dbTypeMap.put(DbType.INTEGER, new DbPlatformType("number", 10));
dbTypeMap.put(DbType.BIGINT, new DbPlatformType("number", 19));
dbTypeMap.put(DbType.REAL, new DbPlatformType("number", 19, 4));
@@ -65,12 +62,10 @@ public class OraclePlatform extends DatabasePlatform {
dbTypeMap.put(DbType.TINYINT, new DbPlatformType("number", 3));
dbTypeMap.put(DbType.DECIMAL, new DbPlatformType("number", 16, 3));
dbTypeMap.put(DbType.VARCHAR, new DbPlatformType("varchar2", 255));
dbTypeMap.put(DbType.LONGVARBINARY, new DbPlatformType("blob"));
dbTypeMap.put(DbType.LONGVARCHAR, new DbPlatformType("clob"));
dbTypeMap.put(DbType.VARBINARY, new DbPlatformType("raw", 255));
dbTypeMap.put(DbType.BINARY, new DbPlatformType("raw", 255));
dbTypeMap.put(DbType.TIME, new DbPlatformType("timestamp"));
}
@@ -27,6 +27,7 @@ abstract class SqlServerBasePlatform extends DatabasePlatform {
// SQL Server unless we are using sequences
this.dbEncrypt = new SqlServerDbEncrypt();
this.persistBatchOnCascade = PersistBatch.NONE;
this.maxInBinding = 2000;
this.idInExpandedForm = true;
this.selectCountWithAlias = true;
this.selectCountWithColumnAlias = true;
@@ -119,4 +120,9 @@ abstract class SqlServerBasePlatform extends DatabasePlatform {
// for update are hints on from clause of base table
return sql;
}
@Override
public boolean isUseMigrationStoredProcedures() {
return true;
}
}
@@ -0,0 +1,12 @@
package io.ebean.config.dbplatform.yugabyte;
import io.ebean.annotation.Platform;
import io.ebean.config.dbplatform.postgres.PostgresPlatform;
public class YugabytePlaform extends PostgresPlatform {
public YugabytePlaform() {
super();
this.platform = Platform.YUGABYTE;
}
}
@@ -18,7 +18,7 @@ import java.util.Locale;
* try {
* File f = new File("src/test/resources/test1.csv");
*
* FileReader reader = new FileReader(f);
* FileReader reader = new FileReader(f, encoding);
*
* CsvReader<Customer> csvReader = DB.createCsvReader(Customer.class);
*
@@ -0,0 +1,48 @@
package io.ebean.util;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
/**
* Utilities for IO. It uses UTF-8 as encoding when reading/writing and uses
* buffered IO for better performance.
*/
public class IOUtils {
/**
* Read from stream as UTF-8.
*/
public static BufferedReader newReader(InputStream is) {
return new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
}
/**
* Read from file as UTF-8.
*/
public static BufferedReader newReader(File file) throws FileNotFoundException {
return newReader(new FileInputStream(file));
}
/**
* Write to stream as UTF-8
*/
public static BufferedWriter newWriter(OutputStream os) {
return new BufferedWriter(new OutputStreamWriter(os, StandardCharsets.UTF_8));
}
/**
* Write to file as UTF-8
*/
public static BufferedWriter newWriter(File file) throws FileNotFoundException {
return newWriter(new FileOutputStream(file));
}
}
@@ -2,7 +2,6 @@ package io.ebean.util;
import static org.assertj.core.api.Assertions.assertThat;
import java.io.File;
import java.util.Set;
import org.junit.jupiter.api.Test;
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.14.0</version>
<version>12.15.1</version>
</parent>
<!-- <parent>-->
<!-- <groupId>org.avaje</groupId>-->
@@ -14,7 +14,7 @@
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-parent-12.14.0</tag>
<tag>ebean-parent-12.15.1</tag>
</scm>
<name>ebean autotune</name>
@@ -26,7 +26,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.14.0</version>
<version>12.15.1</version>
<scope>provided</scope>
</dependency>
@@ -34,7 +34,7 @@
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.2</version>
<version>2.3.6</version>
<scope>provided</scope>
</dependency>
@@ -63,7 +63,7 @@
<extensions>true</extensions>
<configuration>
<tiles>
<tile>io.ebean.tile:enhancement:12.11.3</tile>
<tile>io.ebean.tile:enhancement:12.15.0</tile>
<tile>io.avaje.tile:moditech-module:1.0</tile>
</tiles>
</configuration>
+15 -15
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.14.0</version>
<version>12.15.1</version>
</parent>
<name>ebean bom</name>
@@ -71,88 +71,88 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean</artifactId>
<version>12.14.0</version>
<version>12.15.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>12.14.0</version>
<version>12.15.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.14.0</version>
<version>12.15.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>12.14.0</version>
<version>12.15.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>12.14.0</version>
<version>12.15.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-api</artifactId>
<version>12.14.0</version>
<version>12.15.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-xml</artifactId>
<version>12.14.0</version>
<version>12.15.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-autotune</artifactId>
<version>12.14.0</version>
<version>12.15.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>12.14.0</version>
<version>12.15.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>12.14.0</version>
<version>12.15.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>kotlin-querybean-generator</artifactId>
<version>12.14.0</version>
<version>12.15.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>12.14.0</version>
<version>12.15.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgis</artifactId>
<version>12.14.0</version>
<version>12.15.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-redis</artifactId>
<version>12.14.0</version>
<version>12.15.1</version>
</dependency>
</dependencies>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.14.0</version>
<version>12.15.1</version>
</parent>
<artifactId>ebean-core-type</artifactId>
@@ -16,7 +16,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>12.14.0</version>
<version>12.15.1</version>
</dependency>
<dependency>
@@ -47,6 +47,8 @@ public interface DataReader {
Object getObject() throws SQLException;
<T> T getObject(Class<T> cls) throws SQLException;
InputStream getBinaryStream() throws SQLException;
/**
+7 -7
View File
@@ -3,7 +3,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.14.0</version>
<version>12.15.1</version>
</parent>
<artifactId>ebean-core</artifactId>
@@ -15,7 +15,7 @@
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-parent-12.14.0</tag>
<tag>ebean-parent-12.15.1</tag>
</scm>
<dependencies>
@@ -41,19 +41,19 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>12.14.0</version>
<version>12.15.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>12.14.0</version>
<version>12.15.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-api</artifactId>
<version>12.14.0</version>
<version>12.15.1</version>
</dependency>
<dependency>
@@ -78,7 +78,7 @@
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.199</version>
<version>${h2database.version}</version>
<scope>provided</scope>
</dependency>
@@ -136,7 +136,7 @@
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.24</version>
<version>42.3.3</version>
<optional>true</optional>
</dependency>
@@ -167,6 +167,7 @@ public final class BindParams implements Serializable {
*/
@SuppressWarnings("rawtypes")
public void setParameter(int position, Object value) {
assert value != null : "use setNullParameter";
Param p = getParam(position);
if (value instanceof Collection) {
// use of postgres ANY with positioned parameter
@@ -218,6 +219,7 @@ public final class BindParams implements Serializable {
* Set a named In parameter that is not null.
*/
public Param setParameter(String name, Object value) {
assert value != null : "use setNullParameter";
Param p = getParam(name);
p.setInValue(value);
return p;
@@ -3,8 +3,6 @@ package io.ebeaninternal.api;
import io.ebean.*;
import io.ebean.bean.BeanCollectionLoader;
import io.ebean.bean.CallOrigin;
import io.ebean.config.DatabaseConfig;
import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebean.event.readaudit.ReadAuditLogger;
import io.ebean.event.readaudit.ReadAuditPrepare;
import io.ebean.meta.MetricVisitor;
@@ -1,6 +1,5 @@
package io.ebeaninternal.api;
import io.ebean.meta.QueryPlanRequest;
import io.ebeaninternal.server.type.bindcapture.BindCapture;
/**
@@ -5,7 +5,6 @@ import com.fasterxml.jackson.core.JsonGenerator;
import io.ebean.event.changelog.BeanChange;
import io.ebean.event.changelog.ChangeSet;
import io.ebean.event.changelog.ChangeType;
import io.ebean.text.json.JsonContext;
import java.io.IOException;
import java.io.Writer;
@@ -15,8 +15,6 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.concurrent.locks.ReentrantLock;
import javax.persistence.PersistenceException;
/**
* Wraps the objects involved in executing a SQL / Relational Query.
*/
@@ -5,7 +5,6 @@ import io.avaje.classpath.scanner.ClassPathScannerFactory;
import io.ebean.config.DatabaseConfig;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ServiceLoader;
@@ -3,20 +3,20 @@ package io.ebeaninternal.server.core;
import io.ebean.ScriptRunner;
import io.ebean.ddlrunner.DdlRunner;
import io.ebean.ddlrunner.ScriptTransform;
import io.ebean.util.IOUtils;
import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.util.UrlHelper;
import javax.persistence.PersistenceException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.io.Reader;
import java.io.*;
import java.net.URL;
import java.nio.file.Path;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Map;
import static java.util.Objects.requireNonNull;
final class DScriptRunner implements ScriptRunner {
private static final String NEWLINE = "\n";
@@ -30,8 +30,8 @@ final class DScriptRunner implements ScriptRunner {
}
@Override
public void run(String path) {
run(path, null);
public void run(String resourcePath) {
run(resourcePath, null);
}
@Override
@@ -49,26 +49,42 @@ final class DScriptRunner implements ScriptRunner {
run(resource, null, placeholderMap);
}
@Override
public void run(Path file) {
run(file, null);
}
@Override
public void run(Path file, Map<String, String> placeholderMap) {
requireNonNull(file);
String scriptName = file.toFile().getName();
String content = fileContent(file);
runScript(content, scriptName, placeholderMap, false);
}
private void run(URL resource, String scriptName, Map<String, String> placeholderMap) {
if (resource == null) {
throw new IllegalArgumentException("resource is null?");
}
requireNonNull(resource);
if (scriptName == null) {
scriptName = resource.getFile();
}
String content = content(resource);
runScript(content, scriptName, placeholderMap, false);
}
private String content(URL resource) {
if (resource == null) {
throw new IllegalArgumentException("resource is null?");
private String fileContent(Path file) {
try (InputStream inputStream = new FileInputStream(file.toFile());
Reader reader = IOUtils.newReader(inputStream)) {
return readContent(reader);
} catch (IOException e) {
throw new PersistenceException("Failed to read script content", e);
}
}
try (InputStream inputStream = UrlHelper.openNoCache(resource)) {
return readContent(new InputStreamReader(inputStream));
private String content(URL resource) {
requireNonNull(resource);
try (InputStream inputStream = UrlHelper.openNoCache(resource);
Reader reader = IOUtils.newReader(inputStream)) {
return readContent(reader);
} catch (IOException e) {
throw new PersistenceException("Failed to read script content", e);
}
@@ -84,10 +100,9 @@ final class DScriptRunner implements ScriptRunner {
*/
private void runScript(String content, String scriptName, Map<String, String> placeholderMap, boolean useAutoCommit) {
try {
if (placeholderMap != null) {
if (placeholderMap != null && !placeholderMap.isEmpty()) {
content = ScriptTransform.build(null, placeholderMap).transform(content);
}
try (Connection connection = obtainConnection()) {
DdlRunner runner = new DdlRunner(useAutoCommit, scriptName, platformName);
runner.runAll(content, connection);
@@ -109,7 +124,6 @@ final class DScriptRunner implements ScriptRunner {
}
private String readContent(Reader reader) throws IOException {
StringBuilder buf = new StringBuilder();
try (LineNumberReader lineReader = new LineNumberReader(reader)) {
String line;
@@ -4,7 +4,10 @@ import io.ebean.config.DatabaseConfig;
import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebean.config.dbplatform.clickhouse.ClickHousePlatform;
import io.ebean.config.dbplatform.cockroach.CockroachPlatform;
import io.ebean.config.dbplatform.db2.DB2Platform;
import io.ebean.config.dbplatform.db2.DB2ForIPlatform;
import io.ebean.config.dbplatform.db2.DB2LegacyPlatform;
import io.ebean.config.dbplatform.db2.DB2LuwPlatform;
import io.ebean.config.dbplatform.db2.DB2ZosPlatform;
import io.ebean.config.dbplatform.h2.H2Platform;
import io.ebean.config.dbplatform.hana.HanaPlatform;
import io.ebean.config.dbplatform.hsqldb.HsqldbPlatform;
@@ -13,6 +16,7 @@ import io.ebean.config.dbplatform.mysql.MySql55Platform;
import io.ebean.config.dbplatform.mysql.MySqlPlatform;
import io.ebean.config.dbplatform.nuodb.NuoDbPlatform;
import io.ebean.config.dbplatform.oracle.Oracle11Platform;
import io.ebean.config.dbplatform.oracle.Oracle12Platform;
import io.ebean.config.dbplatform.oracle.OraclePlatform;
import io.ebean.config.dbplatform.postgres.Postgres9Platform;
import io.ebean.config.dbplatform.postgres.PostgresPlatform;
@@ -20,16 +24,14 @@ import io.ebean.config.dbplatform.sqlanywhere.SqlAnywherePlatform;
import io.ebean.config.dbplatform.sqlite.SQLitePlatform;
import io.ebean.config.dbplatform.sqlserver.SqlServer16Platform;
import io.ebean.config.dbplatform.sqlserver.SqlServer17Platform;
import io.ebean.config.dbplatform.yugabyte.YugabytePlaform;
import io.ebeaninternal.api.CoreLog;
import io.ebeaninternal.api.DbOffline;
import javax.persistence.PersistenceException;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.*;
import java.util.Locale;
/**
* Create a DatabasePlatform from the configuration.
@@ -87,6 +89,9 @@ public class DatabasePlatformFactory {
if (dbName.equals("oracle11") || dbName.equals("oracle10") || dbName.equals("oracle9")) {
return new Oracle11Platform();
}
if (dbName.equals("oracle12")) {
return new Oracle12Platform();
}
if (dbName.equals("oracle")) {
return new OraclePlatform();
}
@@ -103,7 +108,19 @@ public class DatabasePlatformFactory {
return new SqlAnywherePlatform();
}
if (dbName.equals("db2")) {
return new DB2Platform();
throw new IllegalArgumentException("Please choose the more specific db2luw/db2zos/db2fori platform. Refer to issue #2514 for details");
}
if (dbName.equals("db2legacy")) {
return new DB2LegacyPlatform();
}
if (dbName.equals("db2zos")) {
return new DB2ZosPlatform();
}
if (dbName.equals("db2fori")) {
return new DB2ForIPlatform();
}
if (dbName.equals("db2luw")) {
return new DB2LuwPlatform();
}
if (dbName.equals("clickhouse")) {
return new ClickHousePlatform();
@@ -149,7 +166,8 @@ public class DatabasePlatformFactory {
} else if (dbProductName.contains("hsql database engine")) {
return new HsqldbPlatform();
} else if (dbProductName.contains("postgres")) {
return readPostgres(connection, majorVersion);
String productVersion = metaData.getDatabaseProductVersion().toLowerCase(Locale.ENGLISH);
return readPostgres(connection, majorVersion, productVersion);
} else if (dbProductName.contains("mariadb")) {
return new MariaDbPlatform();
} else if (dbProductName.contains("mysql")) {
@@ -159,7 +177,7 @@ public class DatabasePlatformFactory {
} else if (dbProductName.contains("sqlite")) {
return new SQLitePlatform();
} else if (dbProductName.contains("db2")) {
return new DB2Platform();
throw new IllegalArgumentException("For DB2 please explicitly choose either db2legacy/db2luw/db2zos/db2fori platform. Refer to issue #2514 for details");
} else if (dbProductName.contains("sql anywhere")) {
return new SqlAnywherePlatform();
} else if (dbProductName.contains("hdb")) {
@@ -173,7 +191,13 @@ public class DatabasePlatformFactory {
}
private DatabasePlatform oracleVersion(int majorVersion) {
return majorVersion < 12 ? new Oracle11Platform() : new OraclePlatform();
if (majorVersion < 12) {
return new Oracle11Platform();
}
if (majorVersion < 13) {
return new Oracle12Platform();
}
return new OraclePlatform();
}
private DatabasePlatform mysqlVersion(int majorVersion, int minorVersion) {
@@ -186,11 +210,14 @@ public class DatabasePlatformFactory {
/**
* Use a select version() query as it could be Postgres or CockroachDB.
*/
private static DatabasePlatform readPostgres(Connection connection, int majorVersion) {
private static DatabasePlatform readPostgres(Connection connection, int majorVersion, String productVersion) {
if (productVersion.contains("-yb-")) {
return new YugabytePlaform();
}
try (PreparedStatement statement = connection.prepareStatement("select version() as \"version\"")) {
try (ResultSet resultSet = statement.executeQuery()) {
if (resultSet.next()) {
String productVersion = resultSet.getString("version").toLowerCase();
productVersion = resultSet.getString("version").toLowerCase();
if (productVersion.contains("cockroach")) {
return new CockroachPlatform();
}
@@ -613,6 +613,10 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
try (Connection connection = dataSource().getConnection()) {
for (String table : tables) {
executeSql(connection, databasePlatform.truncateStatement(table));
if (databasePlatform.getPlatform().base() == Platform.DB2) {
// DB2 requires commit after each truncate statement
connection.commit();
}
}
connection.commit();
} catch (SQLException e) {
@@ -99,7 +99,6 @@ final class InitDataSource {
if (config.getDatabasePlatformName() == null) {
throw new PersistenceException("You MUST specify a DatabasePlatformName on DatabaseConfig when offline");
}
return null;
}
attachAlert(dsConfig);
@@ -280,7 +280,7 @@ public final class InternalConfiguration {
private MultiValueBind createMultiValueBind(Platform platform) {
// only Postgres at this stage
if (platform.base() == Platform.POSTGRES) {
if (platform.base() == Platform.POSTGRES || platform.base() == Platform.YUGABYTE || platform.base() == Platform.COCKROACH) {
return new PostgresMultiValueBind();
}
return new MultiValueBind();
@@ -40,6 +40,9 @@ public final class PersistDeferredRelationship {
// bind the set clause for the importedId
int pos = importedId.bind(1, sqlUpdate, assocBean);
if (pos == -1) {
return; // could not bind: TODO: should we log/throw an error?
}
// bind the where clause for the bean
Object[] idValues = beanDescriptor.idBinder().getIdValues(bean);
for (int j = 0; j < idValues.length; j++) {
@@ -86,6 +86,8 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
private final ConcurrentHashMap<String, ElPropertyDeploy> elDeployCache = new ConcurrentHashMap<>();
private final ConcurrentHashMap<String, ElComparator<T>> comparatorCache = new ConcurrentHashMap<>();
private final ConcurrentHashMap<String, STreeProperty> dynamicProperty = new ConcurrentHashMap<>();
private final ConcurrentHashMap<String, Map<String,String>> pathMaps = new ConcurrentHashMap<>();
private final Map<String, SpiRawSql> namedRawSql;
private final Map<String, String> namedQuery;
private final boolean multiValueSupported;
@@ -2775,6 +2777,22 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
return draftableElement;
}
@Override
public Map<String, String> pathMap(String prefix) {
return pathMaps.computeIfAbsent(prefix, s -> {
HashMap<String, String> m = new HashMap<>();
for (STreePropertyAssocMany many : propsMany()) {
String name = many.name();
m.put(name, prefix + "." + name);
}
for (STreePropertyAssocOne one : propsOne()) {
String name = one.name();
m.put(name, prefix + "." + name);
}
return m.isEmpty() ? Collections.emptyMap() : m;
});
}
@Override
public boolean isEmbeddedPath(String propertyPath) {
ElPropertyDeploy elProp = elPropertyDeploy(propertyPath);
@@ -992,6 +992,9 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
*/
public String renderDbType(DbPlatformType dbType, boolean strict) {
if (dbColumnDefn != null) {
if (dbColumnDefn.endsWith(";")) {
return dbColumnDefn + dbType.renderType(dbLength, dbScale, strict);
}
return dbColumnDefn;
}
return dbType.renderType(dbLength, dbScale, strict);
@@ -1161,6 +1164,26 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
return lob;
}
/**
* Returns true if this <code>isLob()</code> or the type will effectively map to a lob.
*/
@Override
public boolean isDbLob() {
if (lob) {
return true;
}
switch (dbType) {
case DbPlatformType.JSON:
case DbPlatformType.JSONB:
return dbLength == 0; // must be analog to DbPlatformTypeMapping.lookup
case DbPlatformType.JSONBlob:
case DbPlatformType.JSONClob:
return true;
default:
return false;
}
}
public static boolean isLobType(int type) {
switch (type) {
case Types.CLOB:
@@ -226,7 +226,7 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> implements ST
*/
@Override
public void addBeanToCollectionWithCreate(EntityBean parentBean, EntityBean detailBean, boolean withCheck) {
BeanCollection<?> bc = (BeanCollection<?>) super.getValue(parentBean);
BeanCollection<?> bc = beanCollection(parentBean);
if (bc == null) {
bc = help.createEmpty(parentBean);
setValue(parentBean, bc);
@@ -234,6 +234,15 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> implements ST
help.add(bc, detailBean, withCheck);
}
private BeanCollection<?> beanCollection(EntityBean parentBean) {
try {
return (BeanCollection<?>) super.getValue(parentBean);
} catch (ClassCastException e) {
// fetching element collection, ok for now
return null;
}
}
/**
* Return true if this is considered 'empty' from a save perspective.
*/
@@ -62,4 +62,9 @@ class DynamicPropertyAggregationFormula extends DynamicPropertyBase {
ctx.appendParseSelect(parsedFormula, alias);
}
@Override
public boolean isDbLob() {
return false;
}
}
@@ -85,6 +85,9 @@ public final class ImportedIdEmbedded implements ImportedId {
for (ImportedIdSimple anImported : imported) {
if (anImported.owner.isUpdateable()) {
Object scalarValue = anImported.foreignProperty.getValue(embedded);
if (scalarValue == null) {
return -1; // could not bind
}
update.setParameter(pos++, scalarValue);
}
}
@@ -151,6 +151,9 @@ public final class ImportedIdSimple implements ImportedId, Comparable<ImportedId
@Override
public int bind(int position, SqlUpdate update, EntityBean bean) {
Object value = getIdValue(bean);
if (value == null) {
return -1; // could not bind
}
update.setParameter(position, value);
return ++position;
}
@@ -775,7 +775,7 @@ public class DeployBeanDescriptor<T> {
this.identityMode.setIdType(IdType.EXTERNAL);
switch (config.getUuidVersion()) {
case VERSION1:
this.idGenerator = UuidV1IdGenerator.getInstance(config.getUuidStateFile());
this.idGenerator = UuidV1IdGenerator.getInstance(config.getUuidStateFile(), config.getUuidNodeId());
break;
case VERSION1RND:
this.idGenerator = UuidV1RndIdGenerator.INSTANCE;
@@ -1,14 +1,9 @@
package io.ebeaninternal.server.deploy.parse;
import io.ebean.annotation.Aggregation;
import io.ebean.annotation.Avg;
import io.ebean.annotation.DbMigration;
import io.ebean.annotation.Index;
import io.ebean.annotation.Indices;
import io.ebean.annotation.Max;
import io.ebean.annotation.Min;
import io.ebean.annotation.Platform;
import io.ebean.annotation.Sum;
import io.ebean.config.NamingConvention;
import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebean.util.AnnotationUtil;
@@ -20,7 +15,6 @@ import javax.persistence.JoinColumns;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.Set;
@@ -6,6 +6,7 @@ import io.ebeaninternal.server.deploy.InheritInfo;
import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorType;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Inheritance;
import java.util.LinkedHashMap;
@@ -105,8 +106,11 @@ public final class DeployInherit {
if (da != null) {
// lowercase the discriminator column for RawSql and JSON
info.setColumnName(da.name().toLowerCase());
info.setColumnType(da.discriminatorType());
info.setColumnLength(da.length());
DiscriminatorType discriminatorType = da.discriminatorType();
info.setColumnType(discriminatorType);
if (discriminatorType == DiscriminatorType.STRING) {
info.setColumnLength(da.length());
}
info.setColumnDefn(da.columnDefinition());
}
if (!info.isAbstract()) {
@@ -0,0 +1,13 @@
package io.ebeaninternal.server.expression.platform;
/**
* DB2 handling of platform specific expressions. ARRAY expressions not supported.
*/
final class Db2DbExpression extends BasicDbExpression {
@Override
public String concat(String property0, String separator, String property1, String suffix) {
return concatOperator(property0, separator, property1, suffix);
}
}
@@ -10,23 +10,22 @@ public final class DbExpressionHandlerFactory {
* Create and return the appropriate platform specific handing of expressions.
*/
public static DbExpressionHandler from(DatabasePlatform databasePlatform) {
Platform platform = databasePlatform.getPlatform();
Platform platform = databasePlatform.getPlatform().base();
switch (platform) {
case H2:
return new H2DbExpression();
case POSTGRES:
case POSTGRES9:
case YUGABYTE:
case COCKROACH:
return new PostgresDbExpression();
case MARIADB:
return new MariaDbExpression();
case MYSQL55:
case MYSQL:
return new MySqlDbExpression();
case ORACLE:
case ORACLE11:
return new OracleDbExpression();
case SQLSERVER16:
case SQLSERVER17:
case DB2:
return new Db2DbExpression();
case SQLSERVER:
return new SqlServerDbExpression();
case HANA:
@@ -10,6 +10,7 @@ final class H2DbExpression extends BasicDbExpression {
@Override
public void bitwise(SpiExpressionRequest request, String propName, BitwiseOp operator, long flags, String compare, long match) {
bitwiseFunction(request, propName, operator, compare);
String funcName = functionName(operator);
request.append(funcName).append("(").append(propName).append(", cast(? as long)) ").append(compare).append(" cast(? as long)");
}
}
@@ -12,7 +12,8 @@ import java.util.concurrent.ConcurrentHashMap;
* It extends the UuidV1RndIdGenerator so that it can generate rfc4122 compliant Type 1 UUIDs.
*
* This generator produces real Type 1 UUIDs (best for sqlserver) - You should use this generator only,
* if you can guarantee, that mac addess is uniqe.
* if you can guarantee, that mac addess is uniqe or specify 'ebean.uuidNodeId' in your config file.
*
*/
public class UuidV1IdGenerator extends UuidV1RndIdGenerator {
@@ -25,38 +26,36 @@ public class UuidV1IdGenerator extends UuidV1RndIdGenerator {
/**
* Returns an instance for given file.
*/
public static UuidV1IdGenerator getInstance(String file) {
return INSTANCES.computeIfAbsent(new File(file), UuidV1IdGenerator::new);
public static UuidV1IdGenerator getInstance(String file, String nodeId) {
return getInstance(new File(file), nodeId);
}
/**
* Returns an instance for given file.
*/
public static UuidV1IdGenerator getInstance(File file) {
return INSTANCES.computeIfAbsent(file, UuidV1IdGenerator::new);
public static UuidV1IdGenerator getInstance(File file, String nodeId) {
return INSTANCES.computeIfAbsent(file, f ->new UuidV1IdGenerator(f, nodeId == null ? null : nodeId.toLowerCase()));
}
/**
* Returns an alternative node id - set with the 'ebean.uuid.nodeId' system property.
*/
private static byte[] getAlternativeNodeId() {
private static byte[] parseAlternativeNodeId(String altNodeId) {
String[] components = altNodeId.split("-");
if (components.length != 6) {
throw new IllegalArgumentException(altNodeId + " is invalid. Expected format: xx-xx-xx-xx-xx-xx");
}
try {
String altNodeId = System.getProperty("ebean.uuid.nodeId");
if (altNodeId != null) {
String[] components = altNodeId.split("-");
if (components.length != 5) {
throw new IllegalArgumentException("Invalid nodeId string: " + altNodeId);
}
byte[] nodeId = new byte[6];
for (int i=0; i<5; i++) {
nodeId[i] = Byte.decode("0x"+components[i]).byteValue();
}
return nodeId;
byte[] nodeId = new byte[6];
for (int i = 0; i < 6; i++) {
// do not use Byte.parseByte
// https://bugs.java.com/bugdatabase/view_bug.do?bug_id=6259307
nodeId[i] = (byte) Integer.parseInt(components[i], 16);
}
} catch (SecurityException se) {
// ignore
return nodeId;
} catch (IllegalArgumentException iae) {
throw new IllegalArgumentException(altNodeId + " is invalid.", iae);
}
return null;
}
/**
@@ -108,43 +107,85 @@ public class UuidV1IdGenerator extends UuidV1RndIdGenerator {
* Creates a new instance of UuidGenerator. Note that there should not be more
* than one instance per stateFile.
*/
private UuidV1IdGenerator(final File stateFile) {
private UuidV1IdGenerator(final File stateFile, String altNodeId) {
super();
this.stateFile = stateFile;
try {
// See, if there is an alternative MAC address set.
nodeId = getAlternativeNodeId();
if (nodeId != null) {
log.info("Using alternative MAC {} to generate Type 1 UUIDs", getNodeIdentifier());
if (altNodeId == null) {
// using hardware mode
tryHardwareId();
} else if (altNodeId.equals("generate")) {
tryGenerateMode();
} else if (altNodeId.equals("random")) {
useRandomMode();
} else {
nodeId = getHardwareId();
log.info("Using MAC {} to generate Type 1 UUIDs", getNodeIdentifier());
// See, if there is an alternative MAC address set.
nodeId = parseAlternativeNodeId(altNodeId);
restoreState();
log.info("Explicitly using ID {} to generate Type 1 UUIDs", getNodeIdentifier());
}
if (nodeId == null) {
canSaveState = false;
// RFC 4.5 use random portion for node
nodeId = super.getNodeIdBytes();
log.error("Have to fall back to random node identifier {} (Reason: No suitable network interface found)", getNodeIdentifier());
UUID uuid = nextId(null);
long ts = timeStamp.get();
ts -= UUID_EPOCH_OFFSET;
ts /= MILLIS_TO_UUID;
} else {
boolean flag = restoreState();
UUID uuid = nextId(null);
long ts = timeStamp.get();
ts -= UUID_EPOCH_OFFSET;
ts /= MILLIS_TO_UUID;
saveState();
log.debug("RestoreState: {}, ClockSeq {}, Timestamp {}, uuid {}, stateFile: {})", flag, clockSeq.get(),
new Date(ts), uuid, stateFile);
}
saveState();
log.debug("Saved state: clockSeq {}, timestamp {}, uuid {}, stateFile: {})", clockSeq.get(), new Date(ts), uuid, stateFile);
} catch (IOException e) {
canSaveState = false;
log.error("There was a problem while detecting the nodeId. Falling back to random mode. Try using to specify 'ebean.uuidNodeId' property", e);
useRandomMode();
}
}
/**
* Tries to initialize the generator by retrieving the MAC address from
* hardware. If there is no suitable network interface found, it will fall back
* to "generate" mode.
*
* @throws IOException if state file is not readable or tryGenerateMode also
* fails.
*/
private void tryHardwareId() throws IOException {
try {
nodeId = getHardwareId();
} catch (IOException e) {
log.error("Error while reading MAC address. Fall back to 'generate' mode", e);
tryGenerateMode();
}
if (nodeId != null) {
restoreState();
log.info("Using MAC {} to generate Type 1 UUIDs", getNodeIdentifier());
return;
}
log.warn("No suitable network interface found. Fall back to 'generate' mode");
tryGenerateMode();
}
/**
* Tries the "generate" mode. A nodeId is generated once and saved to the state
* file
*/
private void tryGenerateMode() throws IOException {
if (restoreState()) {
log.info("Using recently generated nodeId {} to generate Type 1 UUIDs", getNodeIdentifier());
} else {
// RFC 4.5 use random portion for node
nodeId = super.getNodeIdBytes();
log.error("Have to fall back to random node identifier {} (Reason: {} )", getNodeIdentifier(), e.getMessage());
log.info("Using a newly generated nodeId {} to generate Type 1 UUIDs", getNodeIdentifier());
}
}
/**
* Random mode. A nodeId is generated every start up. no state file is
* maintained. This should always work.
*/
private void useRandomMode() {
canSaveState = false;
nodeId = super.getNodeIdBytes();
log.info("Explicitly using a new random ID {} to generate Type 1 UUIDs", getNodeIdentifier());
}
/**
* Returns the Node-identifier (=MAC address) as string
*/
@@ -164,22 +205,38 @@ public class UuidV1IdGenerator extends UuidV1RndIdGenerator {
*/
private boolean restoreState() throws IOException {
Properties prop = new Properties();
if (stateFile.exists()) {
try (InputStream is = new FileInputStream(stateFile)) {
prop.load(is);
}
if (!stateFile.exists()) {
log.debug("State file '{}' does not exist", stateFile);
return false;
}
if (getNodeIdentifier().equals(prop.getProperty("nodeId"))) {
try {
Integer seq = Integer.valueOf(prop.getProperty("clockSeq")) & 0x3FFF;
Long ts = Long.valueOf(prop.getProperty("timeStamp"));
clockSeq.set(seq);
timeStamp.set(ts);
log.debug("Restored state from '{}'", stateFile);
return true;
} catch (NumberFormatException nfe) {
// nop
try (InputStream is = new FileInputStream(stateFile)) {
prop.load(is);
}
String propNodeId = prop.getProperty("nodeId");
if (propNodeId == null || propNodeId.isEmpty()) {
log.warn("State file '{}' is incomplete", stateFile);
return false; // we cannot restore
}
try {
if (nodeId == null) {
nodeId = parseAlternativeNodeId(propNodeId);
} else if (!getNodeIdentifier().equals(propNodeId)) {
log.warn(
"The nodeId in the state file '{}' has changed from {} to {}. "
+ "This can happen when MAC address changes or when two containers share the same state file",
stateFile, propNodeId, getNodeIdentifier());
return false;
}
Integer seq = Integer.valueOf(prop.getProperty("clockSeq")) & 0x3FFF;
Long ts = Long.valueOf(prop.getProperty("timeStamp"));
clockSeq.set(seq);
timeStamp.set(ts);
log.debug("State successfully restored: {}", prop);
return true;
} catch (IllegalArgumentException nfe) {
log.error("State file '{}' is corrupt", stateFile, nfe);
}
return false;
}
@@ -21,18 +21,12 @@ import java.util.List;
*/
public final class BatchedPstmt implements SpiProfileTransactionEvent {
/**
* The underlying statement.
*/
private static final DB2GetKeys DB2_HACK = new DB2GetKeys();
private PreparedStatement pstmt;
/**
* True if an insert that uses generated keys.
*/
private final boolean isGenKeys;
/**
* The list of BatchPostExecute used to perform post processing.
* The list of BatchPostExecute used to perform post-processing.
*/
private final List<BatchPostExecute> list = new ArrayList<>();
private final String sql;
@@ -170,12 +164,14 @@ public final class BatchedPstmt implements SpiProfileTransactionEvent {
}
private void getGeneratedKeys() throws SQLException {
if (DB2_HACK.getGeneratedKeys(pstmt, list)) {
return;
}
int index = 0;
try (ResultSet rset = pstmt.getGeneratedKeys()) {
while (rset.next()) {
Object idValue = rset.getObject(1);
list.get(index).setGeneratedKey(idValue);
index++;
list.get(index++).setGeneratedKey(idValue);
}
}
}
@@ -0,0 +1,55 @@
package io.ebeaninternal.server.persist;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
/**
* Horrible DB2 hack.
*/
final class DB2GetKeys {
private static Class<? extends PreparedStatement> DB2_PREPARED_STATEMENT;
private static Method GET_DB_GENERATED_KEYS;
static {
try {
DB2_PREPARED_STATEMENT = (Class<? extends PreparedStatement>) Class.forName("com.ibm.db2.jcc.DB2PreparedStatement");
GET_DB_GENERATED_KEYS = DB2_PREPARED_STATEMENT.getDeclaredMethod("getDBGeneratedKeys");
} catch (ClassNotFoundException | NoSuchMethodException | SecurityException cnf) {
// NOP
}
}
static boolean getGeneratedKeys(PreparedStatement pstmt, List<BatchPostExecute> list) throws SQLException {
if (DB2_PREPARED_STATEMENT != null) {
PreparedStatement db2Stmt = null;
if (DB2_PREPARED_STATEMENT.isInstance(pstmt)) {
db2Stmt = pstmt;
} else if (pstmt.isWrapperFor(DB2_PREPARED_STATEMENT)) {
db2Stmt = pstmt.unwrap(DB2_PREPARED_STATEMENT);
}
if (db2Stmt != null) {
// WTF: https://stackoverflow.com/questions/41725492/how-to-get-auto-generated-keys-of-batch-insert-statement
ResultSet[] result;
try {
result = (ResultSet[]) GET_DB_GENERATED_KEYS.invoke(db2Stmt);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
throw new SQLException("Could not get generated keys for DB2", e);
}
int index = 0;
for (ResultSet resultSet : result) {
while (resultSet.next()) {
Object idValue = resultSet.getObject(1);
list.get(index++).setGeneratedKey(idValue);
}
}
return true;
}
}
return false;
}
}
@@ -41,15 +41,15 @@ public final class DefaultPersister implements Persister {
* Actually does the persisting work.
*/
private final PersistExecute persistExecute;
private final SpiEbeanServer server;
private final BeanDescriptorManager beanDescriptorManager;
private final int maxInBinding;
public DefaultPersister(SpiEbeanServer server, Binder binder, BeanDescriptorManager descMgr) {
this.server = server;
this.beanDescriptorManager = descMgr;
this.persistExecute = new DefaultPersistExecute(binder, server.config().getPersistBatchSize());
this.maxInBinding = server.databasePlatform().getMaxInBinding();
}
@Override
@@ -81,8 +81,7 @@ public final class DefaultPersister implements Persister {
int rc = request.executeOrQueue();
request.commitTransIfRequired();
return rc;
} catch (RuntimeException e) {
} catch (Throwable e) {
request.rollbackTransIfRequired();
throw e;
} finally {
@@ -383,8 +382,7 @@ public final class DefaultPersister implements Persister {
req.resetDepth();
req.commitTransIfRequired();
req.flushBatchOnCascade();
} catch (RuntimeException ex) {
} catch (Throwable ex) {
req.rollbackTransIfRequired();
throw ex;
} finally {
@@ -420,8 +418,7 @@ public final class DefaultPersister implements Persister {
req.resetDepth();
req.commitTransIfRequired();
req.flushBatchOnCascade();
} catch (RuntimeException ex) {
} catch (Throwable ex) {
req.rollbackTransIfRequired();
throw ex;
} finally {
@@ -559,7 +556,7 @@ public final class DefaultPersister implements Persister {
req.flushBatchOnCascade();
return rows;
} catch (RuntimeException ex) {
} catch (Throwable ex) {
req.rollbackTransIfRequired();
throw ex;
} finally {
@@ -649,6 +646,20 @@ public final class DefaultPersister implements Persister {
* Delete by Id or a List of Id's.
*/
private int delete(BeanDescriptor<?> descriptor, Object id, List<Object> idList, Transaction transaction, DeleteMode deleteMode) {
int rows = 0;
if (maxInBinding > 0) {
// SqlServer has a 2100 parameter limit, so delete max 2000 ids at once
// this gives space up to 100 more query parameters.
while (idList != null && idList.size() > maxInBinding) {
rows += deleteBatch(descriptor, id, idList.subList(0, maxInBinding), transaction, deleteMode);
idList = idList.subList(maxInBinding, idList.size());
}
}
rows += deleteBatch(descriptor, id, idList, transaction, deleteMode);
return rows;
}
private int deleteBatch(BeanDescriptor<?> descriptor, Object id, List<Object> idList, Transaction transaction, DeleteMode deleteMode) {
SpiTransaction t = (SpiTransaction) transaction;
if (t.isPersistCascade()) {
BeanPropertyAssocOne<?>[] propImportDelete = descriptor.propertiesOneImportedDelete();
@@ -13,11 +13,8 @@ import io.ebeaninternal.server.persist.dmlbind.BindableList;
import java.sql.SQLException;
import static io.ebean.annotation.Platform.MARIADB;
import static io.ebean.annotation.Platform.MYSQL;
/**
* Meta data for insert handler. The meta data is for a particular bean type. It
* Metadata for insert handler. The metadata is for a particular bean type. It
* is considered immutable and is thread safe.
*/
final class InsertMeta {
@@ -153,31 +150,25 @@ final class InsertMeta {
private String genSql(boolean nullId, String table, boolean draftTable) {
GenerateDmlRequest request = new GenerateDmlRequest();
request.setInsertSetMode();
request.append("insert into ").append(table);
if (nullId && noColumnsForInsert(draftTable)) {
return request.append(defaultValues()).toString();
}
request.append(" (");
if (!nullId) {
id.dmlAppend(request);
}
if (shadowFKey != null) {
shadowFKey.dmlAppend(request);
}
if (discriminator != null) {
discriminator.dmlAppend(request);
}
if (draftTable) {
all.dmlAppend(request);
} else {
allExcludeDraftOnly.dmlAppend(request);
}
request.append(") values (");
request.append(request.getInsertBindBuffer());
request.append(")");
@@ -185,7 +176,16 @@ final class InsertMeta {
}
private String defaultValues() {
return platform.base() == MYSQL || platform.base() == MARIADB ? " values (default)" : " default values";
switch (platform.base()) {
case MYSQL:
case MARIADB:
case ORACLE:
return " values (default)";
case DB2:
return " (" + id.getIdentityColumn() + ") values (default)";
default:
return " default values";
}
}
/**
@@ -193,7 +193,7 @@ public final class CQuery<T> implements DbReadContext, CancelableQuery, SpiProfi
// set the generated sql back to the query
// so its available to the user...
query.setGeneratedSql(queryPlan.getSql());
SqlTree sqlTree = queryPlan.getSqlTree();
SqlTreePlan sqlTree = queryPlan.getSqlTree();
this.rootNode = sqlTree.getRootNode();
this.manyProperty = sqlTree.getManyProperty();
this.sql = queryPlan.getSql();
@@ -581,20 +581,17 @@ public final class CQuery<T> implements DbReadContext, CancelableQuery, SpiProfi
@Override
public void registerBeanInherit(BeanPropertyAssocOne<?> property, EntityBeanIntercept ebi) {
String path = getPath(property.name());
request.loadContext().register(path, ebi, property);
request.loadContext().register(path(property.name()), ebi, property);
}
@Override
public void register(String path, EntityBeanIntercept ebi) {
path = getPath(path);
request.loadContext().register(path, ebi);
request.loadContext().register(path(path), ebi);
}
@Override
public void register(BeanPropertyAssocMany<?> many, BeanCollection<?> bc) {
String path = getPath(many.name());
request.loadContext().register(path, many, bc);
request.loadContext().register(path(many.name()), many, bc);
}
/**
@@ -663,18 +660,14 @@ public final class CQuery<T> implements DbReadContext, CancelableQuery, SpiProfi
return autoTuneProfiling && query.isUsageProfiling();
}
private String getPath(String propertyName) {
private String path(String propertyName) {
if (currentPrefix == null) {
return propertyName;
} else if (propertyName == null) {
return currentPrefix;
}
String path = currentPathMap.get(propertyName);
if (path != null) {
return path;
} else {
return currentPrefix + "." + propertyName;
}
return path != null ? path : currentPrefix + "." + propertyName;
}
@Override
@@ -110,7 +110,7 @@ final class CQueryBuilder {
sql = buildUpdateSql(request, rootTableAlias, predicates, sqlTree);
}
// cache the query plan
queryPlan = new CQueryPlan(request, sql, sqlTree, predicates.getLogWhereSql());
queryPlan = new CQueryPlan(request, sql, sqlTree.plan(), predicates.getLogWhereSql());
request.putQueryPlan(queryPlan);
return new CQueryUpdate(request, predicates, queryPlan);
}
@@ -197,7 +197,7 @@ final class CQueryBuilder {
SqlTree sqlTree = createSqlTree(request, predicates);
SqlLimitResponse s = buildSql(null, request, predicates, sqlTree);
queryPlan = new CQueryPlan(request, s.getSql(), sqlTree, predicates.getLogWhereSql());
queryPlan = new CQueryPlan(request, s.getSql(), sqlTree.plan(), predicates.getLogWhereSql());
request.putQueryPlan(queryPlan);
return new CQueryFetchSingleAttribute(request, predicates, queryPlan, query.isCountDistinct());
}
@@ -288,7 +288,7 @@ final class CQueryBuilder {
}
}
// cache the query plan
queryPlan = new CQueryPlan(request, sql, sqlTree, predicates.getLogWhereSql());
queryPlan = new CQueryPlan(request, sql, sqlTree.plan(), predicates.getLogWhereSql());
request.putQueryPlan(queryPlan);
return new CQueryRowCount(queryPlan, request, predicates);
}
@@ -343,7 +343,7 @@ final class CQueryBuilder {
if (rawSql) {
queryPlan = new CQueryPlanRawSql(request, res, sqlTree, predicates.getLogWhereSql());
} else {
queryPlan = new CQueryPlan(request, res, sqlTree, false, predicates.getLogWhereSql());
queryPlan = new CQueryPlan(request, res, sqlTree.plan(), false, predicates.getLogWhereSql());
}
BeanDescriptor<T> desc = request.descriptor();
if (desc.isReadAuditing()) {
@@ -568,8 +568,16 @@ final class CQueryBuilder {
if (countSingleAttribute) {
sb.append("r1.attribute_, count(*) from (select ");
if (distinct) {
sb.append("distinct t0.");
sb.append(request.descriptor().idProperty().dbColumn()).append(", ");
sb.append("distinct ");
BeanProperty idProp = request.descriptor().idProperty();
if (idProp.isEmbedded()) {
BeanProperty[] props = ((BeanPropertyAssocOne<?>) idProp).properties();
for (BeanProperty prop : props) {
sb.append("t0.").append(prop.dbColumn()).append(", ");
}
} else {
sb.append("t0.").append(idProp.dbColumn()).append(", ");
}
}
sb.append(select.getSelectSql()).append(" as attribute_");
} else {
@@ -749,7 +757,11 @@ final class CQueryBuilder {
}
boolean isPlatformDistinctOn() {
return dbPlatform.isPlatform(Platform.POSTGRES);
return dbPlatform.isPlatform(Platform.POSTGRES) || dbPlatform.isPlatform(Platform.YUGABYTE) || dbPlatform.isPlatform(Platform.COCKROACH);
}
boolean isPlatformDistinctNoLobs() {
return dbPlatform.isPlatform(Platform.DB2); // CHECKME: Also oracle?
}
/**
@@ -3,7 +3,6 @@ package io.ebeaninternal.server.query;
import io.ebean.QueryIterator;
import io.ebeaninternal.server.core.OrmQueryRequest;
import javax.persistence.PersistenceException;
import java.sql.SQLException;
/**
@@ -3,7 +3,6 @@ package io.ebeaninternal.server.query;
import io.ebean.QueryIterator;
import io.ebeaninternal.server.core.OrmQueryRequest;
import javax.persistence.PersistenceException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.NoSuchElementException;
@@ -55,7 +55,7 @@ public class CQueryPlan implements SpiQueryPlan {
private final String sql;
private final String hash;
private final String logWhereSql;
private final SqlTree sqlTree;
private final SqlTreePlan sqlTree;
/**
* Encrypted properties required additional binding.
@@ -76,7 +76,7 @@ public class CQueryPlan implements SpiQueryPlan {
/**
* Create a query plan based on a OrmQueryRequest.
*/
CQueryPlan(OrmQueryRequest<?> request, SqlLimitResponse sqlRes, SqlTree sqlTree, boolean rawSql, String logWhereSql) {
CQueryPlan(OrmQueryRequest<?> request, SqlLimitResponse sqlRes, SqlTreePlan sqlTree, boolean rawSql, String logWhereSql) {
this.server = request.server();
this.dataTimeZone = server.dataTimeZone();
this.beanType = request.descriptor().type();
@@ -101,7 +101,7 @@ public class CQueryPlan implements SpiQueryPlan {
/**
* Create a query plan for a raw sql query.
*/
CQueryPlan(OrmQueryRequest<?> request, String sql, SqlTree sqlTree, String logWhereSql) {
CQueryPlan(OrmQueryRequest<?> request, String sql, SqlTreePlan sqlTree, String logWhereSql) {
this.server = request.server();
this.dataTimeZone = server.dataTimeZone();
this.beanType = request.descriptor().type();
@@ -249,7 +249,7 @@ public class CQueryPlan implements SpiQueryPlan {
return rawSql ? planKey.getPartialKey() + "_" + hash : planKey.getPartialKey();
}
final SqlTree getSqlTree() {
final SqlTreePlan getSqlTree() {
return sqlTree;
}
@@ -17,7 +17,7 @@ final class CQueryPlanRawSql extends CQueryPlan {
private final int[] rsetIndexPositions;
CQueryPlanRawSql(OrmQueryRequest<?> request, SqlLimitResponse sqlRes, SqlTree sqlTree, String logWhereSql) {
super(request, sqlRes, sqlTree, true, logWhereSql);
super(request, sqlRes, sqlTree.plan(), true, logWhereSql);
this.rsetIndexPositions = createIndexPositions(request, sqlTree);
}
@@ -28,6 +28,11 @@ public interface STreeProperty extends ScalarDataReader<Object> {
* Return true if the property is the Id.
*/
boolean isId();
/**
* Returns true, if this is a lob property from db-perspective.
*/
boolean isDbLob();
/**
* Return true if the property is an embedded type.
@@ -7,6 +7,8 @@ import io.ebeaninternal.server.deploy.DbReadContext;
import io.ebeaninternal.server.deploy.InheritInfo;
import io.ebeaninternal.server.deploy.id.IdBinder;
import java.util.Map;
/**
* Bean type interface for Sql query tree.
*/
@@ -136,4 +138,8 @@ public interface STreeType {
*/
void markAsDeleted(EntityBean bean);
/**
* Return the "path map" to toMany or toOne properties using the given prefix.
*/
Map<String, String> pathMap(String prefix);
}
@@ -56,6 +56,10 @@ final class SqlTree {
this.noJoins = !includeJoins;
}
SqlTreePlan plan() {
return new SqlTreePlan(rootNode.createLoad(), manyProperty, encryptedProps, dependentTables());
}
/**
* Return true if the query mandates SQL Distinct due to ToMany inclusion.
*/
@@ -123,10 +127,6 @@ final class SqlTree {
return inheritanceWhereSql;
}
SqlTreeRoot getRootNode() {
return (SqlTreeRoot)rootNode;
}
/**
* Return the property that is associated with the many. There can only be one
* per SqlSelect. This can be null.
@@ -135,10 +135,6 @@ final class SqlTree {
return manyProperty;
}
STreeProperty[] getEncryptedProps() {
return encryptedProps;
}
/**
* Return true if the query has a many join.
*/
@@ -153,7 +149,7 @@ final class SqlTree {
/**
* Return the tables that are joined in this query.
*/
Set<String> dependentTables() {
private Set<String> dependentTables() {
Set<String> tables = new LinkedHashSet<>();
rootNode.dependentTables(tables);
return tables;
@@ -53,6 +53,7 @@ public final class SqlTreeBuilder {
private final SpiQuery.TemporalMode temporalMode;
private SqlTreeNode rootNode;
private boolean sqlDistinct;
private final boolean distinctNoLobs;
/**
* Construct for RawSql query.
@@ -65,6 +66,7 @@ public final class SqlTreeBuilder {
this.query = null;
this.subQuery = false;
this.distinctOnPlatform = false;
this.distinctNoLobs = false;
this.queryDetail = queryDetail;
this.predicates = predicates;
this.temporalMode = SpiQuery.TemporalMode.CURRENT;
@@ -97,6 +99,7 @@ public final class SqlTreeBuilder {
this.predicates = predicates;
this.alias = new SqlTreeAlias(request.baseTableAlias(), temporalMode);
this.distinctOnPlatform = builder.isPlatformDistinctOn();
this.distinctNoLobs = builder.isPlatformDistinctNoLobs();
String fromForUpdate = builder.fromForUpdate(query);
CQueryHistorySupport historySupport = builder.getHistorySupport(query);
CQueryDraftSupport draftSupport = builder.getDraftSupport(query);
@@ -266,6 +269,9 @@ public final class SqlTreeBuilder {
if (joinList != null) {
joinList.add(selectNode);
}
if (sqlDistinct && distinctNoLobs) {
selectNode.unselectLobs();
}
return selectNode;
}
@@ -0,0 +1,28 @@
package io.ebeaninternal.server.query;
import io.ebean.bean.EntityBean;
import io.ebean.core.type.ScalarDataReader;
import io.ebeaninternal.server.deploy.DbReadContext;
import java.sql.SQLException;
/**
* Tree node that loads an entity bean type.
*/
interface SqlTreeLoad {
/**
* Load the appropriate information from the SqlSelectReader.
* <p>
* At a high level this actually controls the reading of the data from the
* jdbc resultSet and putting it into the bean etc.
* </p>
*/
EntityBean load(DbReadContext ctx, EntityBean localBean, EntityBean contextBean) throws SQLException;
/**
* Return the reader for the single attribute query.
*/
ScalarDataReader<?> getSingleAttributeReader();
}
@@ -0,0 +1,373 @@
package io.ebeaninternal.server.query;
import io.ebean.bean.BeanCollection;
import io.ebean.bean.EntityBean;
import io.ebean.bean.EntityBeanIntercept;
import io.ebean.bean.PersistenceContext;
import io.ebean.core.type.ScalarDataReader;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.api.SpiQuery.Mode;
import io.ebeaninternal.server.deploy.DbReadContext;
import io.ebeaninternal.server.deploy.InheritInfo;
import io.ebeaninternal.server.deploy.id.IdBinder;
import java.sql.SQLException;
import java.util.Map;
/**
* Normal bean included in the query.
*/
class SqlTreeLoadBean implements SqlTreeLoad {
final STreeType desc;
final IdBinder idBinder;
final SqlTreeLoad[] children;
private final boolean partialObject;
private final STreeProperty[] properties;
private final STreePropertyAssoc nodeBeanProp;
final boolean readId;
private final boolean readIdNormal;
private final boolean disableLazyLoad;
private final InheritInfo inheritInfo;
final String prefix;
private final Map<String, String> pathMap;
final STreePropertyAssocMany lazyLoadParent;
private final SpiQuery.TemporalMode temporalMode;
private final boolean temporalVersions;
final IdBinder lazyLoadParentIdBinder;
SqlTreeLoadBean(SqlTreeNodeBean node) {
this.lazyLoadParent = node.lazyLoadParent;
this.lazyLoadParentIdBinder = node.lazyLoadParentIdBinder;
this.prefix = node.prefix;
this.desc = node.desc;
this.inheritInfo = desc.inheritInfo();
this.idBinder = desc.idBinder();
this.temporalMode = node.temporalMode;
this.temporalVersions = node.temporalVersions;
this.nodeBeanProp = node.nodeBeanProp;
this.readId = node.readId;
this.readIdNormal = readId && !temporalVersions;
this.disableLazyLoad = node.disableLazyLoad;
this.partialObject = node.partialObject;
this.properties = node.properties;
this.pathMap = node.pathMap;
this.children = node.createLoadChildren();
}
boolean isRoot() {
return false;
}
@Override
public final ScalarDataReader<?> getSingleAttributeReader() {
if (properties == null || properties.length == 0) {
// if we have no property ask first children (in a distinct select with join)
if (children.length == 0) {
// expected to be a findIds query
return desc.idBinder().getBeanProperty();
}
return children[0].getSingleAttributeReader();
}
if (properties[0] instanceof STreePropertyAssocOne) {
STreePropertyAssocOne assocOne = (STreePropertyAssocOne)properties[0];
if (assocOne.isAssocId()) {
return assocOne.idReader();
}
}
return properties[0];
}
/**
* Load that takes into account inheritance.
*/
private final class LoadInherit extends Load {
private LoadInherit(DbReadContext ctx, EntityBean parentBean) {
super(ctx, parentBean);
}
@Override
void initBeanType() throws SQLException {
InheritInfo localInfo = readId ? inheritInfo.readType(ctx) : desc.inheritInfo();
if (localInfo == null) {
// the bean must be null
localIdBinder = idBinder;
localDesc = desc;
} else {
localBean = localInfo.createEntityBean();
localType = localInfo.getType();
localIdBinder = localInfo.getIdBinder();
localDesc = localInfo.desc();
}
}
@Override
void loadProperties() {
// take account of inheritance
for (STreeProperty property : properties) {
localDesc.inheritanceLoad(sqlBeanLoad, property, ctx);
}
}
}
/**
* Load a bean instance.
*/
class Load {
final DbReadContext ctx;
final EntityBean parentBean;
Object lazyLoadParentId;
Class<?> localType;
STreeType localDesc;
IdBinder localIdBinder;
EntityBean localBean;
Mode queryMode;
PersistenceContext persistenceContext;
Object id;
EntityBean contextBean;
SqlBeanLoad sqlBeanLoad;
boolean lazyLoadMany;
private Load(DbReadContext ctx, EntityBean parentBean) {
this.ctx = ctx;
this.parentBean = parentBean;
}
private void initLazyParent() throws SQLException {
if (lazyLoadParentIdBinder != null) {
lazyLoadParentId = lazyLoadParentIdBinder.read(ctx);
}
}
void initBeanType() throws SQLException {
localDesc = desc;
localBean = desc.createEntityBean();
localIdBinder = idBinder;
}
private void initPersistenceContext() {
queryMode = ctx.getQueryMode();
persistenceContext = (!readIdNormal) ? null : ctx.getPersistenceContext();
}
private void readId() throws SQLException {
if (readId) {
id = localIdBinder.readSet(ctx, localBean);
if (id == null) {
readIdNullBean();
} else if (!temporalVersions) {
readIdBean();
}
}
}
private void readIdBean() {
// check the PersistenceContext to see if the bean already exists
contextBean = (EntityBean) localDesc.contextPutIfAbsent(persistenceContext, id, localBean);
if (contextBean == null) {
// bean just added to the persistenceContext
contextBean = localBean;
} else {
// bean already exists in persistenceContext
if (queryMode.isLoadContextBean()) {
// if explicitly set loadContextBean to true, then reload
localBean = contextBean;
} else if (!contextBean._ebean_getIntercept().isFullyLoadedBean()) {
// reload if contextBean is partial object
localBean = contextBean;
// and switch to lazyLoad query mode in order not to overwrite
// existing properties in SqlBeanLoad::load
queryMode = Mode.LAZYLOAD_BEAN;
} else {
// ignore the DB data...
localBean = null;
}
}
}
private void readIdNullBean() {
// bean must be null...
localBean = null;
// ... but there may exist as reference bean in parent which has to be marked as deleted.
if (parentBean != null && nodeBeanProp instanceof STreePropertyAssocOne) {
contextBean = ((STreePropertyAssocOne)nodeBeanProp).getValueAsEntityBean(parentBean);
if (contextBean != null) {
desc.markAsDeleted(contextBean);
}
}
}
private void initSqlLoadBean() {
ctx.setCurrentPrefix(prefix, pathMap);
ctx.propagateState(localBean);
sqlBeanLoad = new SqlBeanLoad(ctx, localType, localBean, queryMode);
}
void loadProperties() {
for (STreeProperty property : properties) {
property.load(sqlBeanLoad);
}
}
private void loadChildren() throws SQLException {
if (localBean == null && queryMode == Mode.LAZYLOAD_MANY) {
// batch lazy load many into existing contextBean
localBean = contextBean;
lazyLoadMany = true;
}
for (SqlTreeLoad child : children) {
child.load(ctx, localBean, contextBean);
}
}
private boolean isLazyLoadManyRoot() {
return queryMode == Mode.LAZYLOAD_MANY && isRoot();
}
private EntityBean getContextBean() {
return contextBean;
}
private void postLoad() {
if (!lazyLoadMany && localBean != null) {
ctx.setCurrentPrefix(prefix, pathMap);
if (readIdNormal) {
createListProxies();
}
if (temporalMode == SpiQuery.TemporalMode.DRAFT) {
localDesc.setDraft(localBean);
}
localDesc.postLoad(localBean);
EntityBeanIntercept ebi = localBean._ebean_getIntercept();
ebi.setPersistenceContext(persistenceContext);
if (Mode.LAZYLOAD_BEAN == queryMode) {
// Lazy Load does not reset the dirty state
ebi.setLoadedLazy();
} else if (readId) {
// normal bean loading
ebi.setLoaded();
}
if (disableLazyLoad) {
// bean does not have an Id or is SqlSelect based
ebi.setDisableLazyLoad(true);
} else if (partialObject) {
if (readId) {
// register for lazy loading
ctx.register(null, ebi);
}
} else {
ebi.setFullyLoadedBean(true);
}
if (ctx.isAutoTuneProfiling() && !disableLazyLoad) {
// collect autoTune profiling for this bean...
ctx.profileBean(ebi, prefix);
}
}
}
/**
* Create lazy loading proxies for the Many's except for the one that is
* included in the actual query.
*/
private void createListProxies() {
STreePropertyAssocMany fetchedMany = ctx.getManyProperty();
boolean forceNewReference = queryMode == Mode.REFRESH_BEAN;
for (STreePropertyAssocMany many : localDesc.propsMany()) {
if (many != fetchedMany) {
// create a proxy for the many (deferred fetching)
BeanCollection<?> ref = many.createReference(localBean, forceNewReference);
if (ref != null) {
if (disableLazyLoad) {
ref.setDisableLazyLoad(true);
}
if (!ref.isRegisteredWithLoadContext()) {
ctx.register(many.asMany(), ref);
}
}
}
}
}
private void setBeanToParent() {
if (parentBean != null) {
// set this back to the parentBean
nodeBeanProp.setValue(parentBean, contextBean);
}
}
private EntityBean complete() {
if (!readIdNormal) {
// a bean with no Id (never found in context)
if (lazyLoadParentId != null) {
ctx.setLazyLoadedChildBean(localBean, lazyLoadParentId);
}
return localBean;
} else {
if (lazyLoadParentId != null) {
ctx.setLazyLoadedChildBean(contextBean, lazyLoadParentId);
}
return contextBean;
}
}
private void initialise() throws SQLException {
initLazyParent();
initBeanType();
initPersistenceContext();
readId();
initSqlLoadBean();
loadProperties();
loadChildren();
}
/**
* Perform the load returning the loaded bean.
*/
final EntityBean perform() throws SQLException {
initialise();
if (isLazyLoadManyRoot()) {
return getContextBean();
}
postLoad();
setBeanToParent();
return complete();
}
/**
* Return true if this bean was already in the context. If already in the
* context we need to check if it is already contained in the collection.
*/
final boolean isContextBean() {
return localBean == null;
}
}
/**
* read the properties from the resultSet.
*/
@Override
public EntityBean load(DbReadContext ctx, EntityBean parentBean, EntityBean contextParent) throws SQLException {
return createLoad(ctx, parentBean).perform();
}
/**
* Create the loader with or without inheritance.
*/
final Load createLoad(DbReadContext ctx, EntityBean parentBean) {
return (inheritInfo != null) ? new LoadInherit(ctx, parentBean) : new Load(ctx, parentBean);
}
@Override
public String toString() {
return "SqlTreeLoadBean: " + desc;
}
}
@@ -0,0 +1,30 @@
package io.ebeaninternal.server.query;
import io.ebean.bean.EntityBean;
import io.ebeaninternal.server.deploy.DbReadContext;
import java.sql.SQLException;
final class SqlTreeLoadManyRoot extends SqlTreeLoadBean {
private final STreePropertyAssocMany manyProp;
SqlTreeLoadManyRoot(SqlTreeNodeManyRoot node) {
super(node);
this.manyProp = node.manyProp;
}
@Override
public EntityBean load(DbReadContext cquery, EntityBean parentBean, EntityBean contextParent) throws SQLException {
// pass in null for parentBean because added to a collection rather than set to the parentBean
Load load = createLoad(cquery, null);
EntityBean detailBean = load.perform();
if (contextParent != null) {
// Add to the collection and initialise collection if needed
// A null detailBean may initialise an empty collection
// Check for bean existing in collection based on load.isContextBean()
manyProp.addBeanToCollectionWithCreate(contextParent, detailBean, load.isContextBean());
}
return detailBean;
}
}
@@ -0,0 +1,43 @@
package io.ebeaninternal.server.query;
import io.ebean.Version;
import io.ebean.bean.EntityBean;
import io.ebeaninternal.server.deploy.DbReadContext;
import java.sql.SQLException;
import java.sql.Timestamp;
/**
* Represents the root node of the Sql Tree.
*/
final class SqlTreeLoadRoot extends SqlTreeLoadBean implements SqlTreeRoot {
SqlTreeLoadRoot(SqlTreeNodeBean node) {
super(node);
}
@Override
protected boolean isRoot() {
return true;
}
@Override
public EntityBean load(DbReadContext ctx) throws SQLException {
return load(ctx, null, null);
}
/**
* Read the version bean.
*/
@Override
@SuppressWarnings("unchecked")
public <T> Version<T> loadVersion(DbReadContext ctx) throws SQLException {
// read the sys period lower and upper bounds
// these are always the first 2 columns in the resultSet
Timestamp start = ctx.getDataReader().getTimestamp();
Timestamp end = ctx.getDataReader().getTimestamp();
T bean = (T) load(ctx, null, null);
return new Version<>(bean, start, end);
}
}
@@ -1,13 +1,8 @@
package io.ebeaninternal.server.query;
import io.ebean.Version;
import io.ebean.bean.EntityBean;
import io.ebean.core.type.ScalarDataReader;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.server.deploy.DbReadContext;
import io.ebeaninternal.server.deploy.DbSqlContext;
import java.sql.SQLException;
import java.util.List;
import java.util.Set;
@@ -64,25 +59,11 @@ interface SqlTreeNode {
*/
void addSoftDeletePredicate(SpiQuery<?> query);
/**
* Load the appropriate information from the SqlSelectReader.
* <p>
* At a high level this actually controls the reading of the data from the
* jdbc resultSet and putting it into the bean etc.
* </p>
*/
EntityBean load(DbReadContext ctx, EntityBean localBean, EntityBean contextBean) throws SQLException;
/**
* Return true if the query has a many join.
*/
boolean hasMany();
/**
* Return the reader for the single attribute query.
*/
ScalarDataReader<?> getSingleAttributeReader();
/**
* Return true if the query is known to only have a single property selected.
*/
@@ -92,4 +73,15 @@ interface SqlTreeNode {
* Add dependent tables to the given set.
*/
void dependentTables(Set<String> tables);
/**
* Create the loader for this node.
*/
SqlTreeLoad createLoad();
/**
* Unselect lobs (for distinct queries on DB2 and Oracle).
*/
default void unselectLobs() {
};
}
@@ -1,68 +1,57 @@
package io.ebeaninternal.server.query;
import io.ebean.bean.BeanCollection;
import io.ebean.bean.EntityBean;
import io.ebean.bean.EntityBeanIntercept;
import io.ebean.bean.PersistenceContext;
import io.ebean.core.type.ScalarDataReader;
import io.ebean.util.SplitName;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.api.SpiQuery.Mode;
import io.ebeaninternal.server.deploy.DbReadContext;
import io.ebeaninternal.server.deploy.DbSqlContext;
import io.ebeaninternal.server.deploy.InheritInfo;
import io.ebeaninternal.server.deploy.TableJoin;
import io.ebeaninternal.server.deploy.id.IdBinder;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
/**
* Normal bean included in the query.
*/
class SqlTreeNodeBean implements SqlTreeNode {
private static final SqlTreeNode[] NO_CHILDREN = new SqlTreeNode[0];
private static final SqlTreeLoad[] NO_LOAD_CHILDREN = new SqlTreeLoad[0];
final STreeType desc;
final IdBinder idBinder;
/**
* The children which will be other SelectBean or SelectProxyBean.
*/
final SqlTreeNode[] children;
final List<SqlTreeNode> children;
/**
* Set to true if this is a partial object fetch.
*/
private final boolean partialObject;
private final STreeProperty[] properties;
boolean partialObject;
STreeProperty[] properties;
/**
* Extra where clause added by Where annotation on associated many.
*/
private final String extraWhere;
private final STreePropertyAssoc nodeBeanProp;
final String extraWhere;
final STreePropertyAssoc nodeBeanProp;
/**
* False if report bean and has no id property.
*/
final boolean readId;
private final boolean readIdNormal;
private final boolean disableLazyLoad;
private final InheritInfo inheritInfo;
final boolean readIdNormal;
final boolean disableLazyLoad;
final InheritInfo inheritInfo;
final String prefix;
private final Map<String, String> pathMap;
final Map<String, String> pathMap;
final STreePropertyAssocMany lazyLoadParent;
private final SpiQuery.TemporalMode temporalMode;
private final boolean temporalVersions;
private final IdBinder lazyLoadParentIdBinder;
final SpiQuery.TemporalMode temporalMode;
final boolean temporalVersions;
final IdBinder lazyLoadParentIdBinder;
String baseTableAlias;
/**
* Table alias set if this bean node includes a join to a intersection
* table and that table has history support.
*/
private boolean intersectionAsOfTableAlias;
private final boolean aggregation;
boolean intersectionAsOfTableAlias;
final boolean aggregation;
/**
* Construct for leaf node.
@@ -104,53 +93,40 @@ class SqlTreeNodeBean implements SqlTreeNode {
this.disableLazyLoad = disableLazyLoad || !readIdNormal || desc.isRawSqlBased();
this.partialObject = props.isPartialObject();
this.properties = props.getProps();
this.children = myChildren == null ? NO_CHILDREN : myChildren.toArray(new SqlTreeNode[0]);
pathMap = createPathMap(prefix, desc);
this.children = myChildren == null ? Collections.emptyList() : myChildren;
this.pathMap = createPathMap(prefix, desc);
}
boolean isRoot() {
return false;
@Override
public SqlTreeLoad createLoad() {
return new SqlTreeLoadBean(this);
}
protected SqlTreeLoad[] createLoadChildren() {
if (children.isEmpty()) {
return NO_LOAD_CHILDREN;
}
List<SqlTreeLoad> loadChildren = new ArrayList<>(children.size());
for (SqlTreeNode child : children) {
SqlTreeLoad load = child.createLoad();
if (load != null) {
loadChildren.add(load);
}
}
return loadChildren.toArray(new SqlTreeLoad[0]);
}
@Override
public final boolean isSingleProperty() {
return properties != null && properties.length == 1 && children.length == 0;
}
@Override
public final ScalarDataReader<?> getSingleAttributeReader() {
if (properties == null || properties.length == 0) {
// if we have no property ask first children (in a distinct select with join)
if (children.length == 0) {
// expected to be a findIds query
return desc.idBinder().getBeanProperty();
}
return children[0].getSingleAttributeReader();
}
if (properties[0] instanceof STreePropertyAssocOne) {
STreePropertyAssocOne assocOne = (STreePropertyAssocOne)properties[0];
if (assocOne.isAssocId()) {
return assocOne.idReader();
}
}
return properties[0];
return properties != null && properties.length == 1 && children.isEmpty();
}
private Map<String, String> createPathMap(String prefix, STreeType desc) {
HashMap<String, String> m = new HashMap<>();
for (STreePropertyAssocMany many : desc.propsMany()) {
String name = many.name();
m.put(name, getPath(prefix, name));
}
return m;
return prefix == null ? Collections.emptyMap() : desc.pathMap(prefix);
}
private String getPath(String prefix, String propertyName) {
if (prefix == null) {
return propertyName;
} else {
return prefix + "." + propertyName;
}
private String path(String prefix, String propertyName) {
return prefix == null ? propertyName : prefix + "." + propertyName;
}
@Override
@@ -158,7 +134,7 @@ class SqlTreeNodeBean implements SqlTreeNode {
if (readId) {
if (inheritInfo != null) {
// discriminator column always proceeds id column
selectChain.add(getPath(prefix, inheritInfo.getDiscriminatorColumn()));
selectChain.add(path(prefix, inheritInfo.getDiscriminatorColumn()));
}
idBinder.buildRawSqlSelectChain(prefix, selectChain);
}
@@ -173,293 +149,6 @@ class SqlTreeNodeBean implements SqlTreeNode {
}
}
/**
* Load that takes into account inheritance.
*/
private final class LoadInherit extends Load {
private LoadInherit(DbReadContext ctx, EntityBean parentBean) {
super(ctx, parentBean);
}
@Override
void initBeanType() throws SQLException {
InheritInfo localInfo = readId ? inheritInfo.readType(ctx) : desc.inheritInfo();
if (localInfo == null) {
// the bean must be null
localIdBinder = idBinder;
localDesc = desc;
} else {
localBean = localInfo.createEntityBean();
localType = localInfo.getType();
localIdBinder = localInfo.getIdBinder();
localDesc = localInfo.desc();
}
}
@Override
void loadProperties() {
// take account of inheritance
for (STreeProperty property : properties) {
localDesc.inheritanceLoad(sqlBeanLoad, property, ctx);
}
}
}
/**
* Load a bean instance.
*/
class Load {
final DbReadContext ctx;
final EntityBean parentBean;
Object lazyLoadParentId;
Class<?> localType;
STreeType localDesc;
IdBinder localIdBinder;
EntityBean localBean;
Mode queryMode;
PersistenceContext persistenceContext;
Object id;
EntityBean contextBean;
SqlBeanLoad sqlBeanLoad;
boolean lazyLoadMany;
private Load(DbReadContext ctx, EntityBean parentBean) {
this.ctx = ctx;
this.parentBean = parentBean;
}
private void initLazyParent() throws SQLException {
if (lazyLoadParentIdBinder != null) {
lazyLoadParentId = lazyLoadParentIdBinder.read(ctx);
}
}
void initBeanType() throws SQLException {
localDesc = desc;
localBean = desc.createEntityBean();
localIdBinder = idBinder;
}
private void initPersistenceContext() {
queryMode = ctx.getQueryMode();
persistenceContext = (!readIdNormal) ? null : ctx.getPersistenceContext();
}
private void readId() throws SQLException {
if (readId) {
id = localIdBinder.readSet(ctx, localBean);
if (id == null) {
readIdNullBean();
} else if (!temporalVersions) {
readIdBean();
}
}
}
private void readIdBean() {
// check the PersistenceContext to see if the bean already exists
contextBean = (EntityBean) localDesc.contextPutIfAbsent(persistenceContext, id, localBean);
if (contextBean == null) {
// bean just added to the persistenceContext
contextBean = localBean;
} else {
// bean already exists in persistenceContext
if (queryMode.isLoadContextBean()) {
// if explicitly set loadContextBean to true, then reload
localBean = contextBean;
} else if (!contextBean._ebean_getIntercept().isFullyLoadedBean()) {
// reload if contextBean is partial object
localBean = contextBean;
// and switch to lazyLoad query mode in order not to overwrite
// existing properties in SqlBeanLoad::load
queryMode = Mode.LAZYLOAD_BEAN;
} else {
// ignore the DB data...
localBean = null;
}
}
}
private void readIdNullBean() {
// bean must be null...
localBean = null;
// ... but there may exist as reference bean in parent which has to be marked as deleted.
if (parentBean != null && nodeBeanProp instanceof STreePropertyAssocOne) {
contextBean = ((STreePropertyAssocOne)nodeBeanProp).getValueAsEntityBean(parentBean);
if (contextBean != null) {
desc.markAsDeleted(contextBean);
}
}
}
private void initSqlLoadBean() {
ctx.setCurrentPrefix(prefix, pathMap);
ctx.propagateState(localBean);
sqlBeanLoad = new SqlBeanLoad(ctx, localType, localBean, queryMode);
}
void loadProperties() {
for (STreeProperty property : properties) {
property.load(sqlBeanLoad);
}
}
private void loadChildren() throws SQLException {
if (localBean == null && queryMode == Mode.LAZYLOAD_MANY) {
// batch lazy load many into existing contextBean
localBean = contextBean;
lazyLoadMany = true;
}
for (SqlTreeNode child : children) {
child.load(ctx, localBean, contextBean);
}
}
private boolean isLazyLoadManyRoot() {
return queryMode == Mode.LAZYLOAD_MANY && isRoot();
}
private EntityBean getContextBean() {
return contextBean;
}
private void postLoad() {
if (!lazyLoadMany && localBean != null) {
ctx.setCurrentPrefix(prefix, pathMap);
if (readIdNormal) {
createListProxies();
}
if (temporalMode == SpiQuery.TemporalMode.DRAFT) {
localDesc.setDraft(localBean);
}
localDesc.postLoad(localBean);
EntityBeanIntercept ebi = localBean._ebean_getIntercept();
ebi.setPersistenceContext(persistenceContext);
if (Mode.LAZYLOAD_BEAN == queryMode) {
// Lazy Load does not reset the dirty state
ebi.setLoadedLazy();
} else if (readId) {
// normal bean loading
ebi.setLoaded();
}
if (disableLazyLoad) {
// bean does not have an Id or is SqlSelect based
ebi.setDisableLazyLoad(true);
} else if (partialObject) {
if (readId) {
// register for lazy loading
ctx.register(null, ebi);
}
} else {
ebi.setFullyLoadedBean(true);
}
if (ctx.isAutoTuneProfiling() && !disableLazyLoad) {
// collect autoTune profiling for this bean...
ctx.profileBean(ebi, prefix);
}
}
}
/**
* Create lazy loading proxies for the Many's except for the one that is
* included in the actual query.
*/
private void createListProxies() {
STreePropertyAssocMany fetchedMany = ctx.getManyProperty();
boolean forceNewReference = queryMode == Mode.REFRESH_BEAN;
for (STreePropertyAssocMany many : localDesc.propsMany()) {
if (many != fetchedMany) {
// create a proxy for the many (deferred fetching)
BeanCollection<?> ref = many.createReference(localBean, forceNewReference);
if (ref != null) {
if (disableLazyLoad) {
ref.setDisableLazyLoad(true);
}
if (!ref.isRegisteredWithLoadContext()) {
ctx.register(many.asMany(), ref);
}
}
}
}
}
private void setBeanToParent() {
if (parentBean != null) {
// set this back to the parentBean
nodeBeanProp.setValue(parentBean, contextBean);
}
}
private EntityBean complete() {
if (!readIdNormal) {
// a bean with no Id (never found in context)
if (lazyLoadParentId != null) {
ctx.setLazyLoadedChildBean(localBean, lazyLoadParentId);
}
return localBean;
} else {
if (lazyLoadParentId != null) {
ctx.setLazyLoadedChildBean(contextBean, lazyLoadParentId);
}
return contextBean;
}
}
private void initialise() throws SQLException {
initLazyParent();
initBeanType();
initPersistenceContext();
readId();
initSqlLoadBean();
loadProperties();
loadChildren();
}
/**
* Perform the load returning the loaded bean.
*/
final EntityBean perform() throws SQLException {
initialise();
if (isLazyLoadManyRoot()) {
return getContextBean();
}
postLoad();
setBeanToParent();
return complete();
}
/**
* Return true if this bean was already in the context. If already in the
* context we need to check if it is already contained in the collection.
*/
final boolean isContextBean() {
return localBean == null;
}
}
/**
* read the properties from the resultSet.
*/
@Override
public EntityBean load(DbReadContext ctx, EntityBean parentBean, EntityBean contextParent) throws SQLException {
return createLoad(ctx, parentBean).perform();
}
/**
* Create the loader with or without inheritance.
*/
final Load createLoad(DbReadContext ctx, EntityBean parentBean) {
return (inheritInfo != null) ? new LoadInherit(ctx, parentBean) : new Load(ctx, parentBean);
}
@Override
public final void appendGroupBy(DbSqlContext ctx, boolean subQuery) {
ctx.pushJoin(prefix);
@@ -700,4 +389,33 @@ class SqlTreeNodeBean implements SqlTreeNode {
}
return false;
}
@Override
public void unselectLobs() {
if (children != null) {
for (SqlTreeNode child : children) {
child.unselectLobs();
}
}
if (hasLob()) {
List<STreeProperty> lst = new ArrayList<>();
for (STreeProperty prop : properties) {
if (!prop.isDbLob()) {
lst.add(prop);
}
}
properties = lst.toArray(new STreeProperty[0]);
partialObject = true;
}
}
private boolean hasLob() {
for (STreeProperty prop : properties) {
if (prop.isDbLob()) {
return true;
}
}
return false;
}
}
@@ -1,11 +1,8 @@
package io.ebeaninternal.server.query;
import io.ebean.bean.EntityBean;
import io.ebean.core.type.ScalarType;
import io.ebean.util.SplitName;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.server.deploy.BeanPropertyAssocOne;
import io.ebeaninternal.server.deploy.DbReadContext;
import io.ebeaninternal.server.deploy.DbSqlContext;
import io.ebeaninternal.server.deploy.TableJoin;
@@ -38,6 +35,11 @@ final class SqlTreeNodeExtraJoin implements SqlTreeNode {
this.manyJoin = assocBeanProperty instanceof STreePropertyAssocMany;
}
@Override
public SqlTreeLoad createLoad() {
return null;
}
@Override
public boolean isSingleProperty() {
return false;
@@ -73,11 +75,6 @@ final class SqlTreeNodeExtraJoin implements SqlTreeNode {
// nothing to do here
}
@Override
public ScalarType<?> getSingleAttributeReader() {
throw new IllegalStateException("No expected");
}
/**
* Return true if the extra join is a many join.
* <p>
@@ -184,14 +181,6 @@ final class SqlTreeNodeExtraJoin implements SqlTreeNode {
public void appendWhere(DbSqlContext ctx) {
}
/**
* Does nothing.
*/
@Override
public EntityBean load(DbReadContext ctx, EntityBean localBean, EntityBean parentBean) {
return null;
}
@Override
public boolean hasMany() {
return manyJoin;
@@ -1,9 +1,6 @@
package io.ebeaninternal.server.query;
import io.ebean.bean.EntityBean;
import io.ebean.core.type.ScalarType;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.server.deploy.DbReadContext;
import io.ebeaninternal.server.deploy.DbSqlContext;
import java.util.List;
@@ -33,13 +30,13 @@ final class SqlTreeNodeFormulaWhereJoin implements SqlTreeNode {
}
@Override
public boolean isSingleProperty() {
return true;
public SqlTreeLoad createLoad() {
return null;
}
@Override
public ScalarType<?> getSingleAttributeReader() {
throw new IllegalStateException("No expected");
public boolean isSingleProperty() {
return true;
}
@Override
@@ -98,12 +95,6 @@ final class SqlTreeNodeFormulaWhereJoin implements SqlTreeNode {
// nothing to do here
}
@Override
public EntityBean load(DbReadContext ctx, EntityBean localBean, EntityBean parentBean) {
// nothing to do here
return null;
}
@Override
public boolean hasMany() {
return true;
@@ -1,16 +1,13 @@
package io.ebeaninternal.server.query;
import io.ebean.bean.EntityBean;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.server.deploy.DbReadContext;
import io.ebeaninternal.server.deploy.DbSqlContext;
import java.sql.SQLException;
import java.util.List;
final class SqlTreeNodeManyRoot extends SqlTreeNodeBean {
private final STreePropertyAssocMany manyProp;
final STreePropertyAssocMany manyProp;
SqlTreeNodeManyRoot(String prefix, STreePropertyAssocMany prop, SqlTreeProperties props, List<SqlTreeNode> myList,
boolean withId, SpiQuery.TemporalMode temporalMode, boolean disableLazyLoad) {
@@ -19,22 +16,13 @@ final class SqlTreeNodeManyRoot extends SqlTreeNodeBean {
}
@Override
public boolean hasMany() {
return true;
public SqlTreeLoad createLoad() {
return new SqlTreeLoadManyRoot(this);
}
@Override
public EntityBean load(DbReadContext cquery, EntityBean parentBean, EntityBean contextParent) throws SQLException {
// pass in null for parentBean because added to a collection rather than set to the parentBean
SqlTreeNodeBean.Load load = createLoad(cquery, null);
EntityBean detailBean = load.perform();
if (contextParent != null) {
// Add to the collection and initialise collection if needed
// A null detailBean may initialise an empty collection
// Check for bean existing in collection based on load.isContextBean()
manyProp.addBeanToCollectionWithCreate(contextParent, detailBean, load.isContextBean());
}
return detailBean;
public boolean hasMany() {
return true;
}
/**
@@ -1,10 +1,7 @@
package io.ebeaninternal.server.query;
import io.ebean.bean.EntityBean;
import io.ebean.core.type.ScalarType;
import io.ebean.util.SplitName;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.server.deploy.DbReadContext;
import io.ebeaninternal.server.deploy.DbSqlContext;
import io.ebeaninternal.server.deploy.TableJoin;
@@ -37,13 +34,13 @@ final class SqlTreeNodeManyWhereJoin implements SqlTreeNode {
}
@Override
public boolean isSingleProperty() {
return false;
public SqlTreeLoad createLoad() {
return null;
}
@Override
public ScalarType<?> getSingleAttributeReader() {
throw new IllegalStateException("No expected");
public boolean isSingleProperty() {
return false;
}
@Override
@@ -132,12 +129,6 @@ final class SqlTreeNodeManyWhereJoin implements SqlTreeNode {
// nothing to do here
}
@Override
public EntityBean load(DbReadContext ctx, EntityBean localBean, EntityBean parentBean) {
// nothing to do here
return null;
}
@Override
public boolean hasMany() {
return true;
@@ -1,21 +1,16 @@
package io.ebeaninternal.server.query;
import io.ebean.Version;
import io.ebean.bean.EntityBean;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.server.deploy.DbReadContext;
import io.ebeaninternal.server.deploy.DbSqlContext;
import io.ebeaninternal.server.deploy.TableJoin;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.List;
import java.util.Set;
/**
* Represents the root node of the Sql Tree.
*/
final class SqlTreeNodeRoot extends SqlTreeNodeBean implements SqlTreeRoot {
final class SqlTreeNodeRoot extends SqlTreeNodeBean {
private final TableJoin includeJoin;
private final boolean sqlDistinct;
@@ -34,27 +29,8 @@ final class SqlTreeNodeRoot extends SqlTreeNodeBean implements SqlTreeRoot {
}
@Override
protected boolean isRoot() {
return true;
}
@Override
public EntityBean load(DbReadContext ctx) throws SQLException {
return load(ctx, null, null);
}
/**
* Read the version bean.
*/
@Override
@SuppressWarnings("unchecked")
public <T> Version<T> loadVersion(DbReadContext ctx) throws SQLException {
// read the sys period lower and upper bounds
// these are always the first 2 columns in the resultSet
Timestamp start = ctx.getDataReader().getTimestamp();
Timestamp end = ctx.getDataReader().getTimestamp();
T bean = (T) load(ctx, null, null);
return new Version<>(bean, start, end);
public SqlTreeLoad createLoad() {
return new SqlTreeLoadRoot(this);
}
@Override
@@ -0,0 +1,41 @@
package io.ebeaninternal.server.query;
import java.util.Set;
final class SqlTreePlan {
private final SqlTreeLoad rootNode;
private final STreePropertyAssocMany manyProperty;
private final STreeProperty[] encryptedProps;
private final Set<String> dependentTables;
SqlTreePlan(SqlTreeLoad rootNode, STreePropertyAssocMany manyProperty, STreeProperty[] encryptedProps, Set<String> dependentTables) {
this.rootNode = rootNode;
this.manyProperty = manyProperty;
this.encryptedProps = encryptedProps;
this.dependentTables = dependentTables;
}
SqlTreeRoot getRootNode() {
return (SqlTreeRoot)rootNode;
}
/**
* Return the property that is associated with the many. There can only be one
* per SqlSelect. This can be null.
*/
STreePropertyAssocMany getManyProperty() {
return manyProperty;
}
STreeProperty[] getEncryptedProps() {
return encryptedProps;
}
/**
* Return the tables that are joined in this query.
*/
Set<String> dependentTables() {
return dependentTables;
}
}
@@ -4,6 +4,7 @@ import io.ebean.ProfileLocation;
import io.ebean.config.ProfilingConfig;
import io.ebean.plugin.Plugin;
import io.ebean.plugin.SpiServer;
import io.ebean.util.IOUtils;
import io.ebeaninternal.api.CoreLog;
import io.ebeaninternal.api.SpiProfileHandler;
import org.slf4j.Logger;
@@ -123,7 +124,7 @@ public final class DefaultProfileHandler implements SpiProfileHandler, Plugin {
try {
String now = DTF.format(LocalDateTime.now());
File file = new File(dir, "txprofile-" + now + ".tprofile");
out = new BufferedWriter(new FileWriter(file));
out = IOUtils.newWriter(file);
} catch (IOException e) {
log.error("Not expected", e);
}
@@ -15,7 +15,6 @@ import io.ebeaninternal.server.persist.BatchedSqlException;
import io.ebeaninternal.server.util.Str;
import io.ebeanservice.docstore.api.DocStoreTransaction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.persistence.PersistenceException;
import javax.persistence.RollbackException;
@@ -1,7 +1,9 @@
package io.ebeaninternal.server.type;
import io.ebean.core.type.ScalarType;
import io.ebeaninternal.server.core.BasicTypeConverter;
import java.math.BigDecimal;
import java.util.UUID;
/**
@@ -48,6 +50,8 @@ interface ArrayElementConverter<T> {
*/
ArrayElementConverter<Double> DOUBLE = new DoubleConverter();
ArrayElementConverter<BigDecimal> BIG_DECIMAL = new BigDecimalConverter();
class LongConverter implements ArrayElementConverter<Long> {
@Override
@@ -99,6 +103,23 @@ interface ArrayElementConverter<T> {
}
}
class BigDecimalConverter implements ArrayElementConverter<BigDecimal> {
@Override
public BigDecimal fromSerialized(Object rawValue) {
return fromDbArray(rawValue);
}
@Override
public BigDecimal fromDbArray(Object rawValue) {
if (rawValue instanceof BigDecimal) {
return (BigDecimal) rawValue;
} else {
return BasicTypeConverter.toBigDecimal(rawValue);
}
}
}
/**
* String converter (noop based).
*/

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