Compare commits

...
Author SHA1 Message Date
Rob Bygrave ef8d9c7eb0 [maven-release-plugin] prepare release ebean-parent-12.16.0 2022-03-16 22:49:16 +13:00
Rob Bygrave a464c763d0 Bump parent pom 2022-03-16 22:45:57 +13:00
Rob Bygrave d4d1e571d3 Fix test assert for multi-database 2022-03-16 22:37:54 +13:00
Rob Bygrave 92e85e32a2 #2598 - H2 + @Lob String fails with - Error[Value too long for column "CHARACTER VARYING": "... (1048577)" [22001-210]] 2022-03-16 22:13:52 +13:00
Rob Bygrave ff1b01e5ca Bump agent to 12.16.0 + test and provided dependencies 2022-03-16 22:13:07 +13:00
Rob Bygrave 327f25c568 No functional change - refactor tidy dealing with some internal warnings
protected not needed on final classes
2022-03-16 18:51:12 +13:00
Rob BygraveandGitHub 00a1324c52 Merge pull request #2596 from FOCONIS/ddl-refactor8
DDl-Refactor: Add DB2 Reorg support and history support
2022-03-16 18:47:58 +13:00
Rob Bygrave 75b9df942c No effective change - tidy TestWithCacheAndLazyLoad 2022-03-16 18:38:47 +13:00
Rob Bygrave 946b390037 Merge branch 'FOCONIS-lazyload-npe' 2022-03-16 18:37:48 +13:00
Rob Bygrave 3a1e1e23f5 Merge branch 'lazyload-npe' of https://github.com/FOCONIS/ebean into FOCONIS-lazyload-npe 2022-03-16 18:14:22 +13:00
Rob Bygrave d9ea465102 Support running tests against java 19 2022-03-16 18:02:07 +13:00
Rob Bygrave 3bc7f061eb Bump test dependencies for junit, assertj, mockito 2022-03-16 17:55:37 +13:00
Rob Bygrave 0bc07d38b2 Add Oracle GH workflow for JDK EA 18,19,loom,valhalla,metropolis,panama 2022-03-16 12:13:29 +13:00
Roland Praml 79f6d6d0f0 Ignored query plans for DB2 2022-03-15 17:18:34 +01:00
Roland Praml 782e41098d enabled history tests 2022-03-15 16:56:00 +01:00
Roland Praml 0225fddf6d FIX: AlterColumnTest 2022-03-15 16:31:43 +01:00
Roland Praml be3e08018e Reference Scripts 2022-03-15 15:59:50 +01:00
Roland Praml c9204eed3f DB2: HistorySupport added 2022-03-15 15:59:33 +01:00
Noemi Szemenyei edb6a0ebe2 performance boost list --> set
(cherry picked from commit 2478aded70)
2022-03-15 13:21:10 +01:00
Noemi Szemenyei 826b507b77 Suggested fix
(cherry picked from commit 52ca271a13)
2022-03-15 13:21:02 +01:00
Noemi Szemenyei 8ad8f47c6b Created failing test case
(cherry picked from commit 2b21588c90)
2022-03-15 13:20:16 +01:00
Rob BygraveandGitHub 5944777a13 Merge pull request #2594 from FOCONIS/ddl-refactor7
[DDL-Refactor] History table generation
2022-03-15 09:23:30 +13:00
Roland Praml 05a1b0d64e DB2: Migration is working now 2022-03-14 16:31:34 +01:00
Roland Praml 4d62958645 Updated DDL scripts to support notnull -> null transitions 2022-03-14 14:13:56 +01:00
Roland Praml 610a8b2df6 FIX: notNull -> null transition must be applied also to history 2022-03-14 14:13:10 +01:00
Roland Praml 5b8bb41598 Postgres: Drops history support during alter and restores it after that 2022-03-14 14:08:42 +01:00
Roland Praml 9e16d955ae Sqlserver: no effective code change 2022-03-14 14:06:25 +01:00
Roland Praml 197bb0509a Nuodb: no effective ddl change 2022-03-14 14:05:42 +01:00
Roland Praml 5536aeb829 Mysql: locks only one table at once 2022-03-14 14:04:59 +01:00
Roland Praml d629fb2dbd MariaDB uses '@@system_versioning_alter_history = 1' now. Removed obsolete "lock tables" statements 2022-03-14 14:01:21 +01:00
Roland Praml 10c01574d2 H2: No effective change Statements reordered 2022-03-14 13:12:24 +01:00
Roland Praml cfad20c8e1 Refactored Hisotry generation 2022-03-14 13:11:00 +01:00
Rob Bygrave 0ea375b4fc Merge branch 'FOCONIS-ddl-clickhouse' 2022-03-14 16:54:07 +13:00
Rob Bygrave 71fce1b4c5 #2575 Tidy up for [DDL-ClickHouse] fixes for ClickHouse platform 2022-03-14 16:53:51 +13:00
Rob Bygrave db60065389 Merge branch 'ddl-clickhouse' of https://github.com/FOCONIS/ebean into FOCONIS-ddl-clickhouse 2022-03-14 16:51:27 +13:00
Rob Bygrave d3a765a532 Tidy whitespace only, no effective change 2022-03-14 16:19:02 +13:00
Rob Bygrave fd4be0ca59 #2593 - Tidy SqlTreeBuilder to not add duplicate BeanProperties 2022-03-14 16:16:14 +13:00
Rob Bygrave 267a81b792 #25890 - Tidy only, no effective change for BackgroundExecutorWrapper 2022-03-14 15:46:21 +13:00
Rob Bygrave 1615beadd1 Merge branch 'master' of github.com:ebean-orm/ebean 2022-03-14 15:37:52 +13:00
Rob Bygrave a3e5c3de72 Merge branch 'FOCONIS-Bug-wrong-join-inheritance-dbforeignkey' 2022-03-14 15:37:38 +13:00
Rob Bygrave 267b1b7303 #2580 - Fix for Wrong join in query with @Inheritance
Effectively delays an extra join added via BeanPropertyAssocOne with inheritance, such that this only occurs if a SqlTreeNode child doesn't add the join.
2022-03-14 15:37:12 +13:00
Rob Bygrave c902caed24 Fix is to delay the extra join added via BeanPropertyAssocOne until after the children nodes have joined.
In this way the join is ONLY added if not already done so via a child node (SqlTreeNode).
2022-03-14 15:32:42 +13:00
Rob BygraveandGitHub 662666e1a4 Merge pull request #2590 from FOCONIS/background-executor-wrapper
Provide custom BackgroundExecutorWrapper to pass thread locals
2022-03-14 10:40:37 +13:00
Rob BygraveandGitHub 394f245e33 Merge pull request #2591 from FOCONIS/ddl-refactor6
[DDL-refactor] Sorted the statements, so that they are going to the correct buffers
2022-03-14 09:17:17 +13:00
Roland Praml 89da952b15 updated scripts 2022-03-11 15:35:15 +01:00
Roland Praml d927b8c2c2 [DDL-refactor] Sorted the statements, so that they are going to the correct buffers 2022-03-11 15:34:37 +01:00
Noemi Szemenyei 6867c4568c fix db.shutdown()
(cherry picked from commit 33d17d0f49)
2022-03-11 13:32:08 +01:00
Noemi Szemenyei e0e572a8b4 update
(cherry picked from commit dab8ed8a3b)
2022-03-11 13:31:58 +01:00
Noemi Szemenyei 3c7555de36 Provide custom BackgroundExecutorWrapper to pass thread locals
(cherry picked from commit 336accf447)
2022-03-11 13:31:50 +01:00
Rob BygraveandGitHub 75662aac5c Merge pull request #2589 from FOCONIS/ddl-refactor5
No effective DDL change - refactor whitespace and add buffer comments
2022-03-11 10:38:14 +13:00
Roland Praml e4ddcbd40a Reference scripts 2022-03-10 13:39:59 +01:00
Roland Praml a8f390c3b7 No effective DDL change - removed obsolete whitespaces 2022-03-10 13:31:12 +01:00
Roland Praml f1b196cf2e FIX: tests and pushed reference ddl scripts 2022-03-10 13:24:39 +01:00
Roland Praml 04675ea76b No effective DDL change, just added buffer comments in DDL 2022-03-10 13:24:01 +01:00
Rob Bygrave 8e44ad71e8 Merge branch 'Bug-wrong-join-inheritance-dbforeignkey' of https://github.com/FOCONIS/ebean into FOCONIS-Bug-wrong-join-inheritance-dbforeignkey 2022-03-10 16:24:14 +13:00
Rob Bygrave febd56c9c0 #2581 - SoftDelete on @OneToMany is ignored after refresh() (since 12.11.5) 2022-03-10 16:19:11 +13:00
Rob Bygrave 0d3649853a Bump provided optional Jackson dependency to 2.13.2 2022-03-10 15:33:33 +13:00
Rob Bygrave beed67567a #2588 - [postgis-jdbc] Bump postgis-jdbc dependency from 2.2.1 to 2.5.1 2022-03-10 15:33:00 +13:00
Rob BygraveandGitHub 0fe0803374 Merge pull request #2587 from FOCONIS/ddl-refactor4
[Ddl refactor] Alter Table changes are grouped by table name.
2022-03-10 13:00:44 +13:00
Roland Praml 5fd7aca3d9 Fixed test cases 2022-03-09 16:17:04 +01:00
Rob BygraveandGitHub 348fecddf7 Merge pull request #2586 from FOCONIS/ddl-refactor3
[Clickhouse] Refactored columnNotNull
2022-03-09 22:10:59 +13:00
Rob BygraveandGitHub b333449d84 Merge pull request #2584 from FOCONIS/hazelcast-unmodifiable-map
Small code change for Hazelcast 4.1.5
2022-03-09 16:10:39 +13:00
Rob BygraveandGitHub 87a97c2889 Merge pull request #2585 from FOCONIS/ddl-refactor2
Fix DDL Default handling & Prepared PlatformDdl to to have only one 'alterColumn' method
2022-03-09 16:07:30 +13:00
Roland Praml 790147e42d Reviewed DDL changes - all changes are plausible 2022-03-08 17:28:39 +01:00
Roland Praml 3a93abaa7f Only moves in DDL (checked with git -c color.diff.newMoved=black -c color.diff.oldMoved=black diff --color-moved=plain '*.sql') 2022-03-08 12:43:54 +01:00
Roland Praml 1049d951d9 Code changes to group alterTables by tableName 2022-03-08 12:39:44 +01:00
Roland Praml c3bdac5271 [Clickhouse] Refactored columnNotNull 2022-03-07 16:41:27 +01:00
Roland Praml 9bcba0b80d Sql-scripts 2022-03-07 15:40:45 +01:00
Roland Praml 1529a2f12b Prepared PlatformDdl to to have only one 'alterColumn' method (required for further refactoring) 2022-03-07 15:35:36 +01:00
Noemi Szemenyei b41b6da40e iterator.remove() is not needed 2022-03-04 08:20:44 +01:00
Rob BygraveandGitHub 4285cbaeb2 Merge pull request #2583 from ebean-orm/feature/2582-bg-executor
#2582 - Fix for regression, BackgroundExecutor is bounded (since 12.6.2)
2022-03-04 11:15:23 +13:00
Rob BygraveandGitHub 26fd7c5498 Merge pull request #2578 from ebean-orm/feature/bump-ddl-runner
Bump to ebean-ddl-runner 1.3
2022-03-04 11:14:35 +13:00
Rob BygraveandGitHub 6ec4e4b965 Merge branch 'master' into feature/bump-ddl-runner 2022-03-04 10:26:17 +13:00
Rob Bygrave e3a20a351d #2582 - Fix for regression, BackgroundExecutor is bounded (since 12.6.2)
The change for #2121 brought in a regression where the scheduledExecutorService was used for processing ALL submitted tasks (not just scheduled ones) and is a bounded executor service.  Previously non-scheduled tasks went to a "newCachedThreadPool" based executor service and with this change we are moving back to that (via restoring and using the DaemonExecutorService for those tasks).
2022-03-04 10:21:56 +13:00
Alexander Wagner 9b8f7be98f Bug: Wrong join in query with @Inheritance and @DbForeignKey
(cherry picked from commit 4bcadbb4da3f0defbcc58802e621442d948df38a)
2022-03-02 11:50:57 +01:00
Rob Bygrave 61f5442e3b #2579 - Bump to ebean-migration 12.16.0, support both basePlatform and platform for finding/running migrations
Fix ebean-migration-auto.version to 1.2
2022-03-02 12:30:32 +13:00
Rob Bygrave c5acd31da4 #2579 - Bump to ebean-migration 12.16.0, support both basePlatform and platform for finding/running migrations 2022-03-02 12:25:57 +13:00
Rob Bygrave 49fde7654e Bump to 12.16.0-SNAPSHOT 2022-03-02 12:17:38 +13:00
Rob Bygrave 05338531ed Bump versions after release 2022-03-01 23:01:09 +13:00
Rob Bygrave eb4d906814 [maven-release-plugin] prepare for next development iteration 2022-03-01 22:47:01 +13:00
Rob Bygrave 2a96a59deb [maven-release-plugin] prepare release ebean-parent-12.15.1 2022-03-01 22:46:55 +13:00
Rob Bygrave f571da5154 Bump to ebean-ddl-runner 1.3 2022-03-01 22:35:40 +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 b88e4a35f8 Ddl fixes for clickhouse platform 2022-02-25 12:10: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
488 changed files with 15941 additions and 7382 deletions
+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
+39
View File
@@ -0,0 +1,39 @@
name: JDK EA
on:
workflow_dispatch:
schedule:
- cron: '39 6 * * 1,3,5'
jobs:
build:
runs-on: ${{ matrix.os }}
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
java_version: [17,18,19,loom,valhalla,metropolis,panama]
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v2
- name: Set up Java
uses: oracle-actions/setup-java@v1
with:
website: jdk.java.net
release: ${{ matrix.java_version }}
- name: Maven cache
uses: actions/cache@v2
env:
cache-name: maven-cache
with:
path:
~/.m2
key: build-${{ env.cache-name }}
- name: Build with Maven
run: mvn package
+4 -6
View File
@@ -31,7 +31,7 @@ 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
@@ -39,13 +39,11 @@ jobs:
run: mvn clean test -Dprops.file=testconfig/ebean-mysql.properties
- name: mariadb
run: mvn clean test -Dprops.file=testconfig/ebean-mariadb.properties
- name: mariadb
run: mvn clean test -Dprops.file=testconfig/ebean-mariadb.properties
- name: sqlserver
run: mvn clean test -Dprops.file=testconfig/ebean-sqlserver17.properties
- name: yugabyte
run: mvn clean test -Dprops.file=testconfig/ebean-yugabyte.properties
# - name: sqlserver 2019
- 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
+1 -3
View File
@@ -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
+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.
+2
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.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>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.15.0</version>
<version>12.16.0</version>
</parent>
<name>ebean api</name>
@@ -106,7 +106,7 @@
<dependency>
<groupId>io.avaje</groupId>
<artifactId>junit</artifactId>
<version>1.0</version>
<version>1.1</version>
<scope>test</scope>
</dependency>
@@ -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;
}
/**
@@ -829,7 +829,7 @@ public final class EntityBeanIntercept implements Serializable {
/**
* Load the bean when it is a reference.
*/
protected void loadBean(int loadProperty) {
void loadBean(int loadProperty) {
lock.lock();
try {
if (beanLoader == null) {
@@ -886,7 +886,7 @@ public final class EntityBeanIntercept implements Serializable {
* Helper method to check if two objects are equal.
*/
@SuppressWarnings({"unchecked", "rawtypes"})
protected static boolean notEqual(Object obj1, Object obj2) {
static boolean notEqual(Object obj1, Object obj2) {
if (obj1 == null) {
return (obj2 != null);
}
@@ -0,0 +1,42 @@
package io.ebean.config;
import java.util.concurrent.Callable;
/**
* BackgroundExecutorWrapper that can be used to wrap tasks that are sent to background (i.e. another thread).
* It should copy all necessary thread-local variables. See {@link MdcBackgroundExecutorWrapper} for implementation details.
*
* @author Roland Praml, FOCONIS AG
*/
public interface BackgroundExecutorWrapper {
/**
* Wrap the task with MDC context if defined.
*/
<T> Callable<T> wrap(Callable<T> task);
/**
* Wrap the task with MDC context if defined.
*/
Runnable wrap(Runnable task);
/**
* Combines two wrappers by nesting them.
*/
default BackgroundExecutorWrapper with(BackgroundExecutorWrapper inner) {
return new BackgroundExecutorWrapper() {
@Override
public Runnable wrap(Runnable task) {
return BackgroundExecutorWrapper.this.wrap(inner.wrap(task));
}
@Override
public <T> Callable<T> wrap(Callable<T> task) {
return BackgroundExecutorWrapper.this.wrap(inner.wrap(task));
}
};
}
}
@@ -445,6 +445,7 @@ public class DatabaseConfig {
private int backgroundExecutorSchedulePoolSize = 1;
private int backgroundExecutorShutdownSecs = 30;
private BackgroundExecutorWrapper backgroundExecutorWrapper = new MdcBackgroundExecutorWrapper();
// defaults for the L2 bean caching
@@ -1463,6 +1464,20 @@ public class DatabaseConfig {
this.backgroundExecutorShutdownSecs = backgroundExecutorShutdownSecs;
}
/**
* Return the background executor wrapper.
*/
public BackgroundExecutorWrapper getBackgroundExecutorWrapper() {
return backgroundExecutorWrapper;
}
/**
* Sets the background executor wrapper. The wrapper is used when a task is sent to background and should copy the thread-locals.
*/
public void setBackgroundExecutorWrapper(BackgroundExecutorWrapper backgroundExecutorWrapper) {
this.backgroundExecutorWrapper = backgroundExecutorWrapper;
}
/**
* Return the L2 cache default max size.
*/
@@ -2884,6 +2899,7 @@ public class DatabaseConfig {
backgroundExecutorSchedulePoolSize = p.getInt("backgroundExecutorSchedulePoolSize", backgroundExecutorSchedulePoolSize);
backgroundExecutorShutdownSecs = p.getInt("backgroundExecutorShutdownSecs", backgroundExecutorShutdownSecs);
backgroundExecutorWrapper = p.createInstance(BackgroundExecutorWrapper.class, "backgroundExecutorWrapper", backgroundExecutorWrapper);
disableClasspathSearch = p.getBoolean("disableClasspathSearch", disableClasspathSearch);
currentUserProvider = p.createInstance(CurrentUserProvider.class, "currentUserProvider", currentUserProvider);
databasePlatform = p.createInstance(DatabasePlatform.class, "databasePlatform", databasePlatform);
@@ -0,0 +1,52 @@
package io.ebean.config;
import org.slf4j.MDC;
import java.util.Map;
import java.util.concurrent.Callable;
/**
* Propagates MDC context for tasks executed in the background.
*/
public final class MdcBackgroundExecutorWrapper implements BackgroundExecutorWrapper {
/**
* Wrap the task with MDC context if defined.
*/
@Override
public <T> Callable<T> wrap(Callable<T> task) {
final Map<String, String> map = MDC.getCopyOfContextMap();
if (map == null) {
return task;
} else {
return () -> {
MDC.setContextMap(map);
try {
return task.call();
} finally {
MDC.clear();
}
};
}
}
/**
* Wrap the task with MDC context if defined.
*/
@Override
public Runnable wrap(Runnable task) {
final Map<String, String> map = MDC.getCopyOfContextMap();
if (map == null) {
return task;
} else {
return () -> {
MDC.setContextMap(map);
try {
task.run();
} finally {
MDC.clear();
}
};
}
}
}
@@ -606,13 +606,6 @@ public class DatabasePlatform {
this.useMigrationStoredProcedures = useMigrationStoredProcedures;
}
/**
* Normally not needed - overridden in CockroachPlatform.
*/
public boolean isDdlAutoCommit() {
return false;
}
/**
* Return the DB identity/sequence features for this platform.
*
@@ -18,6 +18,8 @@ public class ClickHousePlatform extends DatabasePlatform {
//this.exceptionTranslator =
this.nativeUuidType = true;
this.dbDefaultValue.setNow("now()");
this.dbDefaultValue.setFalse("0");
this.dbDefaultValue.setTrue("1");
this.dbIdentity.setIdType(IdType.IDENTITY);
this.dbIdentity.setSupportsGetGeneratedKeys(false);
@@ -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;
@@ -37,6 +36,7 @@ public abstract class BaseDB2Platform extends DatabasePlatform {
.addDataIntegrity("23502","23503","23504","23511","23512","23511","42917","23515")
.build();
historySupport = new DB2HistorySupport();
booleanDbType = Types.BOOLEAN;
dbTypeMap.put(DbType.TINYINT, new DbPlatformType("smallint", false));
dbTypeMap.put(DbType.INTEGER, new DbPlatformType("integer", false));
@@ -0,0 +1,30 @@
package io.ebean.config.dbplatform.db2;
import io.ebean.config.dbplatform.DbStandardHistorySupport;
/**
* DB2 based history support.
*/
public class DB2HistorySupport extends DbStandardHistorySupport {
@Override
public String getAsOfViewSuffix(String asOfViewSuffix) {
return " for system_time as of ?";
}
@Override
public String getVersionsBetweenSuffix(String asOfViewSuffix) {
return " for system_time between ? and ?";
}
@Override
public String getSysPeriodLower(String tableAlias, String sysPeriod) {
return tableAlias + "." + sysPeriod + "_start";
}
@Override
public String getSysPeriodUpper(String tableAlias, String sysPeriod) {
return tableAlias + "." + sysPeriod + "_end";
}
}
@@ -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.
@@ -92,4 +92,8 @@ public class HanaPlatform extends DatabasePlatform {
}
}
@Override
public boolean isUseMigrationStoredProcedures() {
return true;
}
}
@@ -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;
+4 -4
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.15.0</version>
<version>12.16.0</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.15.0</tag>
<tag>ebean-parent-12.16.0</tag>
</scm>
<name>ebean autotune</name>
@@ -26,7 +26,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.15.0</version>
<version>12.16.0</version>
<scope>provided</scope>
</dependency>
@@ -48,7 +48,7 @@
<dependency>
<groupId>io.avaje</groupId>
<artifactId>junit</artifactId>
<version>1.0</version>
<version>1.1</version>
<scope>test</scope>
</dependency>
+15 -15
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.15.0</version>
<version>12.16.0</version>
</parent>
<name>ebean bom</name>
@@ -71,88 +71,88 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean</artifactId>
<version>12.15.0</version>
<version>12.16.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>12.15.0</version>
<version>12.16.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.15.0</version>
<version>12.16.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>12.15.0</version>
<version>12.16.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>12.15.0</version>
<version>12.16.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-api</artifactId>
<version>12.15.0</version>
<version>12.16.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-xml</artifactId>
<version>12.15.0</version>
<version>12.16.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-autotune</artifactId>
<version>12.15.0</version>
<version>12.16.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>12.15.0</version>
<version>12.16.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>12.15.0</version>
<version>12.16.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>kotlin-querybean-generator</artifactId>
<version>12.15.0</version>
<version>12.16.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>12.15.0</version>
<version>12.16.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgis</artifactId>
<version>12.15.0</version>
<version>12.16.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-redis</artifactId>
<version>12.15.0</version>
<version>12.16.0</version>
</dependency>
</dependencies>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.15.0</version>
<version>12.16.0</version>
</parent>
<artifactId>ebean-core-type</artifactId>
@@ -16,7 +16,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>12.15.0</version>
<version>12.16.0</version>
</dependency>
<dependency>
+9 -9
View File
@@ -3,7 +3,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.15.0</version>
<version>12.16.0</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.15.0</tag>
<tag>ebean-parent-12.16.0</tag>
</scm>
<dependencies>
@@ -23,7 +23,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-runner</artifactId>
<version>1.2</version>
<version>${ebean-ddl-runner.version}</version>
</dependency>
<dependency>
@@ -35,25 +35,25 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-migration-auto</artifactId>
<version>1.1</version>
<version>${ebean-migration-auto.version}</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>12.15.0</version>
<version>12.16.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>12.15.0</version>
<version>12.16.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-api</artifactId>
<version>12.15.0</version>
<version>12.16.0</version>
</dependency>
<dependency>
@@ -136,7 +136,7 @@
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.3.2</version>
<version>42.3.3</version>
<optional>true</optional>
</dependency>
@@ -152,7 +152,7 @@
<dependency>
<groupId>io.avaje</groupId>
<artifactId>junit</artifactId>
<version>1.0</version>
<version>1.1</version>
<scope>test</scope>
</dependency>
@@ -4,7 +4,7 @@ import io.ebean.bean.EntityBeanIntercept;
import io.ebean.bean.PersistenceContext;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import java.util.List;
import java.util.Set;
/**
* A buffer of beans for batch lazy loading and secondary query loading.
@@ -13,7 +13,7 @@ public interface LoadBeanBuffer {
int batchSize();
List<EntityBeanIntercept> batch();
Set<EntityBeanIntercept> batch();
BeanDescriptor<?> descriptor();
@@ -16,7 +16,7 @@ import java.util.Set;
*/
public final class LoadBeanRequest extends LoadRequest {
private final List<EntityBeanIntercept> batch;
private final Set<EntityBeanIntercept> batch;
private final LoadBeanBuffer loadBuffer;
private final String lazyLoadProperty;
private final boolean loadCache;
@@ -58,7 +58,7 @@ public final class LoadBeanRequest extends LoadRequest {
/**
* Return the batch of beans to actually load.
*/
public List<EntityBeanIntercept> batch() {
public Set<EntityBeanIntercept> batch() {
return batch;
}
@@ -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;
@@ -106,7 +106,9 @@ final class DScriptRunner implements ScriptRunner {
try (Connection connection = obtainConnection()) {
DdlRunner runner = new DdlRunner(useAutoCommit, scriptName, platformName);
runner.runAll(content, connection);
connection.commit();
if (!connection.getAutoCommit()) {
connection.commit();
}
runner.runNonTransactional(connection);
}
@@ -2,7 +2,6 @@ package io.ebeaninternal.server.core;
import io.ebean.CacheMode;
import io.ebean.ExpressionList;
import io.ebean.Transaction;
import io.ebean.bean.BeanCollection;
import io.ebean.bean.EntityBean;
import io.ebean.bean.EntityBeanIntercept;
@@ -17,6 +16,7 @@ import org.slf4j.Logger;
import javax.persistence.EntityNotFoundException;
import java.util.List;
import java.util.Set;
/**
* Helper to handle lazy loading and refreshing of beans.
@@ -39,14 +39,14 @@ final class DefaultBeanLoader {
}
void loadMany(BeanCollection<?> bc, boolean onlyIds) {
loadManyInternal(bc.getOwnerBean(), bc.getPropertyName(), null, false, onlyIds);
loadManyInternal(bc.getOwnerBean(), bc.getPropertyName(), false, onlyIds);
}
void refreshMany(EntityBean parentBean, String propertyName) {
loadManyInternal(parentBean, propertyName, null, true, false);
loadManyInternal(parentBean, propertyName, true, false);
}
private void loadManyInternal(EntityBean parentBean, String propertyName, Transaction t, boolean refresh, boolean onlyIds) {
private void loadManyInternal(EntityBean parentBean, String propertyName, boolean refresh, boolean onlyIds) {
EntityBeanIntercept ebi = parentBean._ebean_getIntercept();
PersistenceContext pc = ebi.getPersistenceContext();
BeanDescriptor<?> parentDesc = server.descriptor(parentBean.getClass());
@@ -105,7 +105,7 @@ final class DefaultBeanLoader {
query.setReadOnly(true);
}
server.findOne(query, t);
server.findOne(query, null);
if (beanCollection != null) {
if (beanCollection.checkEmptyLazyLoad()) {
if (log.isDebugEnabled()) {
@@ -121,7 +121,7 @@ final class DefaultBeanLoader {
* Load a batch of beans for +query or +lazy loading.
*/
void loadBean(LoadBeanRequest loadRequest) {
List<EntityBeanIntercept> batch = loadRequest.batch();
Set<EntityBeanIntercept> batch = loadRequest.batch();
if (batch.isEmpty()) {
throw new RuntimeException("Nothing in batch?");
}
@@ -199,7 +199,7 @@ final class DefaultBeanLoader {
query.setLazyLoadProperty(ebi.getLazyLoadProperty());
if (draft) {
query.asDraft();
} else {
} else if (mode == SpiQuery.Mode.LAZYLOAD_BEAN) {
query.setIncludeSoftDeletes();
}
if (embeddedOwnerIndex > -1) {
@@ -1,5 +1,6 @@
package io.ebeaninternal.server.core;
import io.ebean.config.BackgroundExecutorWrapper;
import io.ebean.config.ContainerConfig;
import io.ebean.config.DatabaseConfig;
import io.ebean.config.DatabaseConfigProvider;
@@ -67,7 +68,8 @@ public final class DefaultContainer implements SpiContainer {
String namePrefix = "ebean-" + config.getName();
int schedulePoolSize = config.getBackgroundExecutorSchedulePoolSize();
int shutdownSecs = config.getBackgroundExecutorShutdownSecs();
return new DefaultBackgroundExecutor(schedulePoolSize, shutdownSecs, namePrefix);
BackgroundExecutorWrapper wrapper = config.getBackgroundExecutorWrapper();
return new DefaultBackgroundExecutor(schedulePoolSize, shutdownSecs, namePrefix, wrapper);
}
/**
@@ -373,7 +373,9 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
migrationRunner.setDefaultDbSchema(dbSchema);
}
migrationRunner.setName(config.getName());
migrationRunner.setPlatform(config.getDatabasePlatform().getPlatform().base().name().toLowerCase());
Platform platform = config.getDatabasePlatform().getPlatform();
migrationRunner.setBasePlatform(platform.base().name().toLowerCase());
migrationRunner.setPlatform(platform.name().toLowerCase());
migrationRunner.loadProperties(config.getProperties());
migrationRunner.run(config.getDataSource());
}
@@ -280,7 +280,7 @@ public final class InternalConfiguration {
private MultiValueBind createMultiValueBind(Platform platform) {
// only Postgres at this stage
if (platform.base() == Platform.POSTGRES || platform.base() == Platform.YUGABYTE) {
if (platform.base() == Platform.POSTGRES || platform.base() == Platform.YUGABYTE || platform.base() == Platform.COCKROACH) {
return new PostgresMultiValueBind();
}
return new MultiValueBind();
@@ -3,6 +3,7 @@ package io.ebeaninternal.server.deploy;
import io.ebean.bean.EntityBean;
import io.ebean.bean.PersistenceContext;
import io.ebeaninternal.server.query.SqlJoinType;
import io.ebeaninternal.server.query.SqlTreeJoin;
import java.sql.SQLException;
@@ -60,11 +61,28 @@ final class AssocOneHelpRefInherit extends AssocOneHelp {
return ref;
}
@Override
void appendFrom(DbSqlContext ctx, SqlJoinType joinType) {
// add join to support the discriminator column
String relativePrefix = ctx.getRelativePrefix(property.name);
property.tableJoin.addJoin(joinType, relativePrefix, ctx);
ctx.addExtraJoin(new Extra(relativePrefix, joinType));
}
/**
* Extra join to support the discriminator column.
*/
final class Extra implements SqlTreeJoin {
final String relativePrefix;
final SqlJoinType joinType;
Extra(String relativePrefix, SqlJoinType joinType) {
this.relativePrefix = relativePrefix;
this.joinType = joinType;
}
@Override
public void addJoin(DbSqlContext ctx) {
// add join to support the discriminator column *IF* join is not already present
property.tableJoin.addJoin(joinType, relativePrefix, ctx);
}
}
/**
@@ -1310,8 +1310,8 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
* Hit the bean cache trying to load a list/batch of entities.
* Return the set of entities that were successfully loaded from L2 cache.
*/
public Set<EntityBeanIntercept> cacheBeanLoadAll(List<EntityBeanIntercept> list, PersistenceContext persistenceContext, int lazyLoadProperty, String propertyName) {
return cacheHelp.beanCacheLoadAll(list, persistenceContext, lazyLoadProperty, propertyName);
public Set<EntityBeanIntercept> cacheBeanLoadAll(Set<EntityBeanIntercept> batch, PersistenceContext persistenceContext, int lazyLoadProperty, String propertyName) {
return cacheHelp.beanCacheLoadAll(batch, persistenceContext, lazyLoadProperty, propertyName);
}
/**
@@ -693,9 +693,9 @@ final class BeanDescriptorCacheHelp<T> {
/**
* Load a batch of entities from L2 bean cache checking the lazy loaded property is loaded.
*/
Set<EntityBeanIntercept> beanCacheLoadAll(List<EntityBeanIntercept> list, PersistenceContext context, int lazyLoadProperty, String propertyName) {
Set<EntityBeanIntercept> beanCacheLoadAll(Set<EntityBeanIntercept> batch, PersistenceContext context, int lazyLoadProperty, String propertyName) {
Map<Object, EntityBeanIntercept> ebis = new HashMap<>();
for (EntityBeanIntercept ebi : list) {
for (EntityBeanIntercept ebi : batch) {
ebis.put(desc.cacheKeyForBean(ebi.getOwner()), ebi);
}
@@ -716,7 +716,6 @@ final class BeanDescriptorCacheHelp<T> {
if (beanLog.isTraceEnabled()) {
beanLog.trace(" load {}({}) - cache miss on property({})", cacheName, key, propertyName);
}
iterator.remove();
} else {
CachedBeanDataToBean.load(desc, ebi.getOwner(), cacheData, context);
loaded.add(ebi);
@@ -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);
@@ -1160,26 +1163,27 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
public boolean isLob() {
return lob;
}
/**
* Returns true if this <code>isLob()</code> or the type will effectively map to a 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;
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:
@@ -1,6 +1,7 @@
package io.ebeaninternal.server.deploy;
import io.ebeaninternal.server.query.SqlJoinType;
import io.ebeaninternal.server.query.SqlTreeJoin;
/**
* Used to provide context during sql construction.
@@ -133,4 +134,13 @@ public interface DbSqlContext {
*/
void appendFromForUpdate();
/**
* Delay adding an extra join to support inheritance discriminator in projection (IF required).
*/
void addExtraJoin(SqlTreeJoin treeJoin);
/**
* Add extra joins *IF* required to support inheritance discriminator in projection.
*/
void flushExtraJoins();
}
@@ -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;
@@ -0,0 +1,67 @@
package io.ebeaninternal.server.executor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.*;
import java.util.concurrent.locks.ReentrantLock;
/**
* A "CachedThreadPool" based on Daemon threads.
* <p>
* The Threads are created as needed and once idle live for 60 seconds.
*/
final class DaemonExecutorService {
private static final Logger logger = LoggerFactory.getLogger(DaemonExecutorService.class);
private final ReentrantLock lock = new ReentrantLock(false);
private final String namePrefix;
private final int shutdownWaitSeconds;
private final ExecutorService service;
DaemonExecutorService(int shutdownWaitSeconds, String namePrefix) {
this.service = Executors.newCachedThreadPool(new DaemonThreadFactory(namePrefix));
this.shutdownWaitSeconds = shutdownWaitSeconds;
this.namePrefix = namePrefix;
}
<T> Future<T> submit(Callable<T> task) {
return service.submit(task);
}
Future<?> submit(Runnable task) {
return service.submit(task);
}
/**
* Shutdown this thread pool nicely if possible.
* <p>
* This will wait a maximum of 20 seconds before terminating any threads still working.
*/
void shutdown() {
lock.lock();
try {
if (service.isShutdown()) {
logger.debug("DaemonExecutorService[{}] already shut down", namePrefix);
return;
}
try {
logger.debug("DaemonExecutorService[{}] shutting down...", namePrefix);
service.shutdown();
if (!service.awaitTermination(shutdownWaitSeconds, TimeUnit.SECONDS)) {
logger.info("DaemonExecutorService[{}] shut down timeout exceeded. Terminating running threads.", namePrefix);
service.shutdownNow();
}
} catch (Exception e) {
logger.error("Error during shutdown of DaemonThreadPool[" + namePrefix + "]", e);
e.printStackTrace();
}
} finally {
lock.unlock();
}
}
}
@@ -1,15 +1,13 @@
package io.ebeaninternal.server.executor;
import io.avaje.lang.NonNullApi;
import io.ebean.config.BackgroundExecutorWrapper;
import io.ebeaninternal.api.SpiBackgroundExecutor;
import org.slf4j.MDC;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The default implementation of the BackgroundExecutor.
@@ -17,56 +15,81 @@ import java.util.concurrent.TimeUnit;
@NonNullApi
public final class DefaultBackgroundExecutor implements SpiBackgroundExecutor {
private final ScheduledExecutorService executor;
private static final Logger log = LoggerFactory.getLogger("io.ebean.BackgroundExecutor");
private final ScheduledExecutorService schedulePool;
private final DaemonExecutorService pool;
private final BackgroundExecutorWrapper wrapper;
/**
* Construct the default implementation of BackgroundExecutor.
*/
public DefaultBackgroundExecutor(int schedulePoolSize, int shutdownWaitSeconds, String namePrefix) {
this.executor = new DaemonScheduleThreadPool(schedulePoolSize, shutdownWaitSeconds, namePrefix);
public DefaultBackgroundExecutor(int schedulePoolSize, int shutdownWaitSeconds, String namePrefix, BackgroundExecutorWrapper wrapper) {
this.schedulePool = new DaemonScheduleThreadPool(schedulePoolSize, shutdownWaitSeconds, namePrefix + "-periodic-");
this.pool = new DaemonExecutorService(shutdownWaitSeconds, namePrefix);
this.wrapper = wrapper;
log.debug("Created backgroundExecutor {} (schedulePoolSize={}, shutdownWaitSeconds={})", namePrefix, schedulePoolSize, shutdownWaitSeconds);
}
/**
* Wrap the task with MDC context if defined.
*/
<T> Callable<T> wrapMDC(Callable<T> task) {
final Map<String, String> map = MDC.getCopyOfContextMap();
if (map == null) {
<T> Callable<T> wrap(Callable<T> task) {
if (wrapper == null) {
return task;
} else {
return () -> {
MDC.setContextMap(map);
try {
return task.call();
} finally {
MDC.clear();
}
};
return wrapper.wrap(task);
}
}
/**
* Wrap the task with MDC context if defined.
*/
Runnable wrapMDC(Runnable task) {
final Map<String, String> map = MDC.getCopyOfContextMap();
if (map == null) {
Runnable wrap(Runnable task) {
if (wrapper == null) {
return task;
} else {
return () -> {
MDC.setContextMap(map);
try {
return wrapper.wrap(task);
}
}
/**
* Decorates a runnable by adding an exception handler and some timing metrics.
* This is used in methods that accepts a <code>Runnable</code> and return
* either <code>void</code> or <code>ScheduledFuture</code>, as there is
* normally no Future.get() call.
*
* Note: When submitting a <code>Callable</code>, you must check
* <code>Future.get()</code> for exceptions.
*/
private Runnable logExceptions(Runnable task) {
long queued = System.nanoTime();
log.trace("Queued {}", task);
return () -> {
try {
if (log.isTraceEnabled()) {
long start = System.nanoTime();
log.trace("Start {} (delay time {} us)", task, (start - queued) / 1000L);
task.run();
log.trace("Stop {} (exec time {} us)", task, (System.nanoTime() - start) / 1000L);
} else {
task.run();
} finally {
MDC.clear();
}
};
}
} catch (Throwable t) {
// log any exception here. Note they will not bubble up to the calling user
// unless Future.get() is checked. (Which is almost never done on scheduled
// background executions)
log.error("Error while executing the task {}", task, t);
throw t;
}
};
}
@Override
public <T> Future<T> submit(Callable<T> task) {
return executor.submit(wrapMDC(task));
// Note: No "logExceptions" as we expect Future.get() by the invoker
return pool.submit(wrap(task));
}
/**
@@ -74,47 +97,52 @@ public final class DefaultBackgroundExecutor implements SpiBackgroundExecutor {
*/
@Override
public Future<?> submit(Runnable task) {
return executor.submit(wrapMDC(task));
return pool.submit(wrap(task));
}
@Override
public void execute(Runnable task) {
submit(task);
submit(logExceptions(task));
}
@Override
public void executePeriodically(Runnable task, long delay, TimeUnit unit) {
executor.scheduleWithFixedDelay(wrapMDC(task), delay, delay, unit);
schedulePool.scheduleWithFixedDelay(wrap(logExceptions(task)), delay, delay, unit);
}
@Override
public void executePeriodically(Runnable task, long initialDelay, long delay, TimeUnit unit) {
executor.scheduleWithFixedDelay(wrapMDC(task), initialDelay, delay, unit);
schedulePool.scheduleWithFixedDelay(wrap(logExceptions(task)), initialDelay, delay, unit);
}
@Override
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, long initialDelay, long delay, TimeUnit unit) {
return executor.scheduleWithFixedDelay(wrapMDC(task), initialDelay, delay, unit);
return schedulePool.scheduleWithFixedDelay(wrap(logExceptions(task)), initialDelay, delay, unit);
}
@Override
public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, long initialDelay, long delay, TimeUnit unit) {
return executor.scheduleAtFixedRate(wrapMDC(task), initialDelay, delay, unit);
return schedulePool.scheduleAtFixedRate(wrap(logExceptions(task)), initialDelay, delay, unit);
}
@Override
public ScheduledFuture<?> schedule(Runnable task, long delay, TimeUnit unit) {
return executor.schedule(wrapMDC(task), delay, unit);
return schedulePool.schedule(wrap(logExceptions(task)), delay, unit);
}
@Override
public <V> ScheduledFuture<V> schedule(Callable<V> task, long delay, TimeUnit unit) {
return executor.schedule(wrapMDC(task), delay, unit);
// Note: No "logExceptions" as we expect Future.get() by the invoker
return schedulePool.schedule(wrap(task), delay, unit);
}
@Override
public void shutdown() {
executor.shutdown();
log.trace("BackgroundExecutor shutting down");
schedulePool.shutdown();
pool.shutdown();
log.debug("BackgroundExecutor stopped");
}
}
@@ -15,6 +15,7 @@ import io.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import io.ebeaninternal.server.querydefn.OrmQueryProperties;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.locks.Lock;
@@ -66,7 +67,7 @@ final class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext
}
}
protected void register(EntityBeanIntercept ebi) {
void register(EntityBeanIntercept ebi) {
if (currentBuffer.isFull()) {
currentBuffer = createBuffer(batchSize);
}
@@ -91,7 +92,7 @@ final class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext
try {
if (bufferList != null) {
for (LoadBuffer loadBuffer : bufferList) {
if (!loadBuffer.list.isEmpty()) {
if (!loadBuffer.batch.isEmpty()) {
parent.getEbeanServer().loadBean(new LoadBeanRequest(loadBuffer, parentRequest));
}
if (forEach) {
@@ -115,13 +116,13 @@ final class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext
private final ReentrantLock bufferLock = new ReentrantLock();
private final DLoadBeanContext context;
private final int batchSize;
private final List<EntityBeanIntercept> list;
private final Set<EntityBeanIntercept> batch;
private PersistenceContext persistenceContext;
LoadBuffer(DLoadBeanContext context, int batchSize) {
this.context = context;
this.batchSize = batchSize;
this.list = new ArrayList<>(batchSize);
this.batch = new HashSet<>(Math.max((int) (batchSize/.75f) + 1, 16));
}
@Override
@@ -139,7 +140,7 @@ final class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext
* Return true if the buffer is full.
*/
public boolean isFull() {
return batchSize == list.size();
return batchSize == batch.size();
}
/**
@@ -150,12 +151,12 @@ final class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext
// get persistenceContext from first loaded bean into the buffer
persistenceContext = ebi.getPersistenceContext();
}
list.add(ebi);
batch.add(ebi);
}
@Override
public List<EntityBeanIntercept> batch() {
return list;
public Set<EntityBeanIntercept> batch() {
return batch;
}
@Override
@@ -190,13 +191,13 @@ final class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext
// lazy load property was a Many
return;
}
if (list.isEmpty()) {
if (!batch.contains(ebi)) {
// re-add to the batch and lazy load from DB skipping l2 cache
list.add(ebi);
batch.add(ebi);
} else if (context.hitCache) {
Set<EntityBeanIntercept> hits = context.desc.cacheBeanLoadAll(list, persistenceContext, ebi.getLazyLoadPropertyIndex(), ebi.getLazyLoadProperty());
list.removeAll(hits);
if (list.isEmpty() || hits.contains(ebi)) {
Set<EntityBeanIntercept> hits = context.desc.cacheBeanLoadAll(batch, persistenceContext, ebi.getLazyLoadPropertyIndex(), ebi.getLazyLoadProperty());
batch.removeAll(hits);
if (batch.isEmpty() || hits.contains(ebi)) {
// successfully hit the L2 cache so don't invoke DB lazy loading
return;
}
@@ -204,7 +205,7 @@ final class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext
LoadBeanRequest req = new LoadBeanRequest(this, ebi, context.hitCache);
context.desc.ebeanServer().loadBean(req);
list.clear();
batch.clear();
}
}
@@ -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 {
@@ -757,7 +757,7 @@ final class CQueryBuilder {
}
boolean isPlatformDistinctOn() {
return dbPlatform.isPlatform(Platform.POSTGRES) || dbPlatform.isPlatform(Platform.YUGABYTE);
return dbPlatform.isPlatform(Platform.POSTGRES) || dbPlatform.isPlatform(Platform.YUGABYTE) || dbPlatform.isPlatform(Platform.COCKROACH);
}
boolean isPlatformDistinctNoLobs() {
@@ -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;
@@ -7,6 +7,7 @@ import io.ebeaninternal.server.util.ArrayStack;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
final class DefaultDbSqlContext implements DbSqlContext {
@@ -43,7 +44,9 @@ final class DefaultDbSqlContext implements DbSqlContext {
private String currentPrefix;
private ArrayList<BeanProperty> encryptedProps;
private List<BeanProperty> encryptedProps;
private List<SqlTreeJoin> extraJoins;
private final CQueryDraftSupport draftSupport;
@@ -70,6 +73,24 @@ final class DefaultDbSqlContext implements DbSqlContext {
return alias.isIncludeSoftDelete();
}
@Override
public void addExtraJoin(SqlTreeJoin treeJoin) {
if (extraJoins == null) {
extraJoins = new ArrayList<>();
}
extraJoins.add(treeJoin);
}
@Override
public void flushExtraJoins() {
if (extraJoins != null) {
for (SqlTreeJoin extra : extraJoins) {
extra.addJoin(this);
}
extraJoins = null;
}
}
@Override
public void appendFromForUpdate() {
if (fromForUpdate != null) {
@@ -13,30 +13,22 @@ import java.util.Set;
final class SqlTree {
private final SqlTreeNode rootNode;
/**
* Property if resultSet contains master and detail rows.
*/
private final STreePropertyAssocMany manyProperty;
private final String distinctOn;
private final String selectSql;
private final String fromSql;
private final String groupBy;
/**
* Encrypted Properties require additional binding.
*/
private final STreeProperty[] encryptedProps;
/**
* Where clause for inheritance.
*/
private final String inheritanceWhereSql;
private final boolean noJoins;
/**
@@ -44,7 +36,6 @@ final class SqlTree {
*/
SqlTree(SqlTreeNode rootNode, String distinctOn, String selectSql, String fromSql, String groupBy, String inheritanceWhereSql,
STreeProperty[] encryptedProps, STreePropertyAssocMany manyProperty, boolean includeJoins) {
this.rootNode = rootNode;
this.distinctOn = distinctOn;
this.selectSql = selectSql;
@@ -15,22 +15,14 @@ import java.util.TreeSet;
final class SqlTreeAlias {
private final SpiQuery.TemporalMode temporalMode;
private int counter;
private int manyWhereCounter;
private final TreeSet<String> joinProps = new TreeSet<>();
private HashSet<String> embeddedPropertyJoins;
private final TreeSet<String> manyWhereJoinProps = new TreeSet<>();
private final HashMap<String, String> aliasMap = new HashMap<>();
private final HashMap<String, String> manyWhereAliasMap = new HashMap<>();
private final String rootTableAlias;
private int counter;
private int manyWhereCounter;
SqlTreeAlias(String rootTableAlias, SpiQuery.TemporalMode temporalMode) {
this.rootTableAlias = rootTableAlias;
@@ -224,8 +224,7 @@ public final class SqlTreeBuilder {
* Recursively build the query tree depending on what leaves in the tree
* should be included.
*/
private SqlTreeNode buildSelectChain(String prefix, STreePropertyAssoc prop,
STreeType desc, List<SqlTreeNode> joinList) {
private SqlTreeNode buildSelectChain(String prefix, STreePropertyAssoc prop, STreeType desc, List<SqlTreeNode> joinList) {
List<SqlTreeNode> myJoinList = new ArrayList<>();
List<STreePropertyAssocOne> extraProps = new ArrayList<>();
for (STreePropertyAssocOne one : desc.propsOne()) {
@@ -256,7 +255,7 @@ public final class SqlTreeBuilder {
}
addManyWhereJoins(myJoinList);
}
extraProps.forEach(props::add);
extraProps.forEach(props::addExtra);
if (!rawSql && manyWhereJoins.isFormulaWithJoin(prefix)) {
for (String property : manyWhereJoins.getFormulaJoinProperties(prefix)) {
@@ -0,0 +1,15 @@
package io.ebeaninternal.server.query;
import io.ebeaninternal.server.deploy.DbSqlContext;
/**
* Extra Sql joins conditionally added if required (after children are joined).
*/
public interface SqlTreeJoin {
/**
* Add the extra join if required.
*/
void addJoin(DbSqlContext ctx);
}
@@ -279,18 +279,16 @@ class SqlTreeNodeBean implements SqlTreeNode {
ctx.pushTableAlias(prefix);
baseTableAlias = ctx.getTableAlias(prefix);
// join and return SqlJoinType to use for child joins
joinType = appendFromBaseTable(ctx, joinType);
for (STreeProperty property : properties) {
// usually nothing... except for 1-1 Exported
property.appendFrom(ctx, joinType, null);
}
for (SqlTreeNode child : children) {
child.appendFrom(ctx, joinType);
}
ctx.flushExtraJoins();
ctx.popTableAlias();
ctx.popJoin();
}
@@ -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;
@@ -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,6 +33,12 @@ public final class SqlTreeProperties {
propsList.addAll(Arrays.asList(props));
}
public void addExtra(STreePropertyAssocOne prop) {
if (!propsList.contains(prop)) {
add(prop);
}
}
public void add(STreeProperty prop) {
propsList.add(prop);
propNames.add(prop.name());
@@ -10,7 +10,6 @@ import io.ebeaninternal.api.SpiProfileHandler;
import org.slf4j.Logger;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
@@ -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;
@@ -202,7 +202,8 @@ public final class DefaultTypeManager implements TypeManager {
private boolean isPostgresCompatible(DatabasePlatform databasePlatform) {
return databasePlatform.isPlatform(Platform.POSTGRES)
|| databasePlatform.isPlatform(Platform.YUGABYTE);
|| databasePlatform.isPlatform(Platform.YUGABYTE)
|| databasePlatform.isPlatform(Platform.COCKROACH);
}
private boolean hstoreSupport() {
@@ -1,5 +1,6 @@
package io.ebeaninternal.server.type;
import io.ebean.core.type.DataBinder;
import io.ebean.core.type.DataReader;
import java.sql.SQLException;
@@ -18,6 +19,15 @@ class ScalarTypeClob extends ScalarTypeStringBase {
super(true, Types.CLOB);
}
@Override
public void bind(DataBinder binder, String value) throws SQLException {
if (value == null) {
binder.setNull(Types.VARCHAR);
} else {
binder.setClob(value);
}
}
@Override
public String read(DataReader reader) throws SQLException {
return reader.getStringFromStream();
@@ -1,6 +1,5 @@
package io.ebeaninternal.server.type;
import io.ebean.annotation.DbArray;
import io.ebean.core.type.ScalarType;
import io.ebeaninternal.server.deploy.meta.DeployBeanProperty;
@@ -0,0 +1,56 @@
package io.ebeaninternal.server.executor;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Future;
import static org.assertj.core.api.Assertions.assertThat;
class DaemonExecutorServiceTest {
private final int count = 10;
private final int waitMillis = 100;
@Test
void submit() throws Exception {
DaemonExecutorService des = new DaemonExecutorService(5, "junk");
long start = System.currentTimeMillis();
List<Future<?>> futures = new ArrayList<>();
for (int i = 0; i < count; i++) {
futures.add(des.submit(this::doStuff));
}
for (Future<?> f: futures) {
f.get();
}
long exeMillis = System.currentTimeMillis() - start;
assertThat(exeMillis).isLessThan(count * waitMillis);
des.shutdown();
}
@Test
void submit_via_DefaultBackgroundExecutor() throws Exception {
DefaultBackgroundExecutor des = new DefaultBackgroundExecutor(1, 5, "junk", null);
long start = System.currentTimeMillis();
List<Future<?>> futures = new ArrayList<>();
for (int i = 0; i < count; i++) {
futures.add(des.submit(this::doStuff));
}
for (Future<?> f: futures) {
f.get();
}
long exeMillis = System.currentTimeMillis() - start;
assertThat(exeMillis).isLessThan(count * waitMillis);
des.shutdown();
}
private void doStuff() {
try {
Thread.sleep(waitMillis);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.15.0</version>
<version>12.16.0</version>
</parent>
<name>ebean ddl generation</name>
@@ -16,7 +16,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-runner</artifactId>
<version>1.2</version>
<version>${ebean-ddl-runner.version}</version>
</dependency>
<dependency>
@@ -28,14 +28,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>12.15.0</version>
<version>12.16.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.15.0</version>
<version>12.16.0</version>
<scope>provided</scope>
</dependency>
@@ -51,7 +51,7 @@
<dependency>
<groupId>io.avaje</groupId>
<artifactId>junit</artifactId>
<version>1.0</version>
<version>1.1</version>
<scope>test</scope>
</dependency>
@@ -44,7 +44,6 @@ public class DdlGenerator implements SpiDdlGenerator {
private final boolean extraDdl;
private final boolean createOnly;
private final boolean jaxbPresent;
private final boolean ddlAutoCommit;
private final String dbSchema;
private final ScriptTransform scriptTransform;
private final Platform platform;
@@ -70,11 +69,9 @@ public class DdlGenerator implements SpiDdlGenerator {
if (!config.getTenantMode().isDdlEnabled() && config.isDdlRun()) {
log.warn("DDL can't be run on startup with TenantMode " + config.getTenantMode());
this.runDdl = false;
this.ddlAutoCommit = false;
this.useMigrationStoredProcedures = false;
} else {
this.runDdl = config.isDdlRun();
this.ddlAutoCommit = databasePlatform.isDdlAutoCommit();
this.useMigrationStoredProcedures = config.getDatabasePlatform().isUseMigrationStoredProcedures();
}
this.scriptTransform = createScriptTransform(config);
@@ -166,11 +163,11 @@ public class DdlGenerator implements SpiDdlGenerator {
DdlRunner runner = createDdlRunner(expectErrors, scriptName);
try {
if (expectErrors || ddlAutoCommit) {
if (expectErrors) {
connection.setAutoCommit(true);
}
runner.runAll(scriptTransform.transform(content), connection);
if (expectErrors || ddlAutoCommit) {
if (expectErrors) {
connection.setAutoCommit(false);
}
connection.commit();
@@ -305,21 +302,13 @@ public class DdlGenerator implements SpiDdlGenerator {
}
protected String generateDropAllDdl() {
try {
dropAllContent = currentModel().getDropAllDdl();
return dropAllContent;
} catch (IOException e) {
throw new RuntimeException(e);
}
dropAllContent = currentModel().getDropAllDdl();
return dropAllContent;
}
protected String generateCreateAllDdl() {
try {
createAllContent = currentModel().getCreateDdl();
return createAllContent;
} catch (IOException e) {
throw new RuntimeException(e);
}
createAllContent = currentModel().getCreateDdl();
return createAllContent;
}
protected String getDropFileName() {
@@ -8,7 +8,6 @@ import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.StringJoiner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -16,7 +15,6 @@ import org.slf4j.LoggerFactory;
import io.ebean.DB;
import io.ebean.Database;
import io.ebean.annotation.Platform;
import io.ebean.config.ClassLoadConfig;
import io.ebean.config.DatabaseConfig;
import io.ebean.config.DbConstraintNaming;
import io.ebean.config.PlatformConfig;
@@ -43,9 +41,9 @@ 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.ebean.dbmigration.DbMigration;
import io.ebean.util.IOUtils;
import io.ebean.util.StringHelper;
import io.ebeaninternal.api.DbOffline;
import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlOptions;
@@ -584,9 +582,9 @@ public class DefaultDbMigration implements DbMigration {
// writer needs the current model to provide table/column details for
// history ddl generation (triggers, history tables etc)
DdlOptions options = new DdlOptions(addForeignKeySkipCheck);
DdlWrite write = new DdlWrite(new MConfiguration(), request.current, options);
PlatformDdlWriter writer = createDdlWriter(databasePlatform);
writer.processMigration(dbMigration, write, request.migrationDir, fullVersion);
DdlWrite writer = new DdlWrite(new MConfiguration(), request.current, options);
PlatformDdlWriter platformWriter = createDdlWriter(databasePlatform);
platformWriter.processMigration(dbMigration, writer, request.migrationDir, fullVersion);
}
return fullVersion;
}
@@ -653,10 +651,10 @@ public class DefaultDbMigration implements DbMigration {
private void writeExtraPlatformDdl(String fullVersion, CurrentModel currentModel, Migration dbMigration, File writePath) throws IOException {
DdlOptions options = new DdlOptions(addForeignKeySkipCheck);
for (Pair pair : platforms) {
DdlWrite platformBuffer = new DdlWrite(new MConfiguration(), currentModel.read(), options);
DdlWrite writer = new DdlWrite(new MConfiguration(), currentModel.read(), options);
PlatformDdlWriter platformWriter = createDdlWriter(pair.platform);
File subPath = platformWriter.subPath(writePath, pair.prefix);
platformWriter.processMigration(dbMigration, platformBuffer, subPath, fullVersion);
platformWriter.processMigration(dbMigration, writer, subPath, fullVersion);
}
}
@@ -815,6 +813,8 @@ public class DefaultDbMigration implements DbMigration {
return new Postgres9Platform();
case POSTGRES:
return new PostgresPlatform();
case YUGABYTE:
return new YugabytePlaform();
case MARIADB:
return new MariaDbPlatform();
case MYSQL55:
@@ -7,6 +7,8 @@ package io.ebeaninternal.dbmigration;
*/
public class UnknownResourcePathException extends RuntimeException {
private static final long serialVersionUID = 8533769929372106003L;
public UnknownResourcePathException(String msg) {
super(msg);
}
@@ -17,7 +17,6 @@ import io.ebeaninternal.dbmigration.migration.DropHistoryTable;
import io.ebeaninternal.dbmigration.migration.DropIndex;
import io.ebeaninternal.dbmigration.migration.DropTable;
import java.io.IOException;
import java.util.List;
/**
@@ -36,7 +35,7 @@ public class BaseDdlHandler implements DdlHandler {
}
@Override
public void generate(DdlWrite writer, ChangeSet changeSet) throws IOException {
public void generate(DdlWrite writer, ChangeSet changeSet) {
List<Object> changeSetChildren = changeSet.getChangeSetChildren();
for (Object change : changeSetChildren) {
@@ -76,72 +75,72 @@ public class BaseDdlHandler implements DdlHandler {
}
@Override
public void generateProlog(DdlWrite write) throws IOException {
tableDdl.generateProlog(write);
public void generateProlog(DdlWrite writer) {
tableDdl.generateProlog(writer);
}
@Override
public void generateEpilog(DdlWrite write) throws IOException {
tableDdl.generateEpilog(write);
public void generateEpilog(DdlWrite writer) {
tableDdl.generateEpilog(writer);
}
@Override
public void generate(DdlWrite writer, CreateTable createTable) throws IOException {
public void generate(DdlWrite writer, CreateTable createTable) {
tableDdl.generate(writer, createTable);
}
@Override
public void generate(DdlWrite writer, DropTable dropTable) throws IOException {
public void generate(DdlWrite writer, DropTable dropTable) {
tableDdl.generate(writer, dropTable);
}
@Override
public void generate(DdlWrite writer, AddTableComment addTableComment) throws IOException {
public void generate(DdlWrite writer, AddTableComment addTableComment) {
tableDdl.generate(writer, addTableComment);
}
@Override
public void generate(DdlWrite writer, AddColumn addColumn) throws IOException {
public void generate(DdlWrite writer, AddColumn addColumn) {
tableDdl.generate(writer, addColumn);
}
@Override
public void generate(DdlWrite writer, DropColumn dropColumn) throws IOException {
public void generate(DdlWrite writer, DropColumn dropColumn) {
tableDdl.generate(writer, dropColumn);
}
@Override
public void generate(DdlWrite writer, AlterColumn alterColumn) throws IOException {
public void generate(DdlWrite writer, AlterColumn alterColumn) {
tableDdl.generate(writer, alterColumn);
}
@Override
public void generate(DdlWrite writer, AddHistoryTable addHistoryTable) throws IOException {
public void generate(DdlWrite writer, AddHistoryTable addHistoryTable) {
tableDdl.generate(writer, addHistoryTable);
}
@Override
public void generate(DdlWrite writer, DropHistoryTable dropHistoryTable) throws IOException {
public void generate(DdlWrite writer, DropHistoryTable dropHistoryTable) {
tableDdl.generate(writer, dropHistoryTable);
}
@Override
public void generate(DdlWrite writer, CreateIndex createIndex) throws IOException {
public void generate(DdlWrite writer, CreateIndex createIndex) {
tableDdl.generate(writer, createIndex);
}
@Override
public void generate(DdlWrite writer, DropIndex dropIndex) throws IOException {
public void generate(DdlWrite writer, DropIndex dropIndex) {
tableDdl.generate(writer, dropIndex);
}
@Override
public void generate(DdlWrite writer, AddUniqueConstraint constraint) throws IOException {
public void generate(DdlWrite writer, AddUniqueConstraint constraint) {
tableDdl.generate(writer, constraint);
}
@Override
public void generate(DdlWrite writer, AlterForeignKey alterForeignKey) throws IOException {
public void generate(DdlWrite writer, AlterForeignKey alterForeignKey) {
tableDdl.generate(writer, alterForeignKey);
}
}
@@ -4,8 +4,6 @@ import io.ebeaninternal.dbmigration.migration.AddColumn;
import io.ebeaninternal.dbmigration.migration.AlterColumn;
import io.ebeaninternal.dbmigration.migration.DropColumn;
import java.io.IOException;
/**
* Write DDL for AddColumn , DropColumn or AlterColumn.
*/
@@ -14,15 +12,15 @@ public interface ColumnDdl {
/**
* Write the add column change.
*/
void generate(DdlWrite writer, AddColumn addColumn) throws IOException;
void generate(DdlWrite writer, AddColumn addColumn);
/**
* Write the drop column change.
*/
void generate(DdlWrite writer, DropColumn dropColumn) throws IOException;
void generate(DdlWrite writer, DropColumn dropColumn);
/**
* Write the alter column changes.
*/
void generate(DdlWrite writer, AlterColumn alterColumn) throws IOException;
void generate(DdlWrite writer, AlterColumn alterColumn);
}
@@ -0,0 +1,45 @@
package io.ebeaninternal.dbmigration.ddlgeneration;
import java.io.IOException;
/**
* Object that represents an Alter Table statements. Table alters are grouped together by tableName in DDL and can be extended by
* a ddl-specific handler (e.g. doing a reorg for DB2 or implement special grouping for Hana). There is one instance per table.
*
* @author TODO Roland Praml, FOCONIS AG
*/
public interface DdlAlterTable {
/**
* Writes the alter table statements to <code>target</code>
*/
void write(Appendable target) throws IOException;
/**
* Adds an alter table command for given column. When you invoke<br>
* <code>alterTable(writer, "my_table").add("alter column","my_column).append("type integer")</code> the resulting DDL (in
* standard implementation) would be<br>
* <code>alter table my_table alter column my_column type integer</code>
*
* @return a DdlBuffer, which can be used for further appends. Note you MUST NOT call <code>.endOfStatement()</code> on this
* buffer.
*/
DdlBuffer append(String operation, String columnName);
/**
* Adds a raw command. This is mainly used for executing user stored procedures.
*/
DdlBuffer raw(String string);
/**
* Flag that detects if history DDL (switching on) is handled for this table.
*/
boolean isHistoryHandled();
/**
* Sets the history handled flag for this table.
*/
void setHistoryHandled();
}
@@ -1,19 +1,10 @@
package io.ebeaninternal.dbmigration.ddlgeneration;
import io.ebeaninternal.dbmigration.model.MConfiguration;
import java.io.IOException;
/**
* Buffer to append generated DDL to.
*/
public interface DdlBuffer {
/**
* Return the configuration (default tablespaces etc).
*/
MConfiguration getConfiguration();
/**
* Return true if the buffer is empty.
*/
@@ -22,37 +13,37 @@ public interface DdlBuffer {
/**
* Append a statement allowing for null or empty statements.
*/
DdlBuffer appendStatement(String content) throws IOException;
DdlBuffer appendStatement(String content);
/**
* Append DDL content to the buffer.
*/
DdlBuffer append(String content) throws IOException;
DdlBuffer append(String content);
/**
* Append DDL content to the buffer with space padding.
*/
DdlBuffer append(String type, int space) throws IOException;
DdlBuffer append(String type, int space);
/**
* Append a value that is potentially null or empty and proceed it with a space if so.
*/
DdlBuffer appendWithSpace(String foreignKeyRestrict) throws IOException;
DdlBuffer appendWithSpace(String foreignKeyRestrict);
/**
* Append new line character to the buffer.
*/
DdlBuffer newLine() throws IOException;
DdlBuffer newLine();
/**
* Append the end of statement content.
*/
DdlBuffer endOfStatement() throws IOException;
DdlBuffer endOfStatement();
/**
* End of a change - add some whitespace.
*/
DdlBuffer end() throws IOException;
DdlBuffer end();
/**
* Return the buffer content.
@@ -14,40 +14,38 @@ import io.ebeaninternal.dbmigration.migration.DropHistoryTable;
import io.ebeaninternal.dbmigration.migration.DropIndex;
import io.ebeaninternal.dbmigration.migration.DropTable;
import java.io.IOException;
/**
* DDL generation interface.
*/
public interface DdlHandler {
void generate(DdlWrite writer, ChangeSet changeSet) throws IOException;
void generate(DdlWrite writer, ChangeSet changeSet);
void generate(DdlWrite writer, CreateTable createTable) throws IOException;
void generate(DdlWrite writer, CreateTable createTable);
void generate(DdlWrite writer, DropTable dropTable) throws IOException;
void generate(DdlWrite writer, DropTable dropTable);
void generate(DdlWrite writer, AddTableComment addTableComment) throws IOException;
void generate(DdlWrite writer, AddTableComment addTableComment);
void generate(DdlWrite writer, AddColumn addColumn) throws IOException;
void generate(DdlWrite writer, AddColumn addColumn);
void generate(DdlWrite writer, DropColumn dropColumn) throws IOException;
void generate(DdlWrite writer, DropColumn dropColumn);
void generate(DdlWrite writer, AlterColumn alterColumn) throws IOException;
void generate(DdlWrite writer, AlterColumn alterColumn);
void generate(DdlWrite writer, AddHistoryTable addHistoryTable) throws IOException;
void generate(DdlWrite writer, AddHistoryTable addHistoryTable);
void generate(DdlWrite writer, DropHistoryTable dropHistoryTable) throws IOException;
void generate(DdlWrite writer, DropHistoryTable dropHistoryTable);
void generate(DdlWrite writer, CreateIndex createIndex) throws IOException;
void generate(DdlWrite writer, CreateIndex createIndex);
void generate(DdlWrite writer, DropIndex dropIndex) throws IOException;
void generate(DdlWrite writer, DropIndex dropIndex);
void generate(DdlWrite writer, AddUniqueConstraint constraint) throws IOException;
void generate(DdlWrite writer, AddUniqueConstraint constraint);
void generate(DdlWrite writer, AlterForeignKey alterForeignKey) throws IOException;
void generate(DdlWrite writer, AlterForeignKey alterForeignKey);
void generateProlog(DdlWrite write) throws IOException;
void generateProlog(DdlWrite writer);
void generateEpilog(DdlWrite write) throws IOException;
void generateEpilog(DdlWrite writer);
}
@@ -1,30 +1,46 @@
package io.ebeaninternal.dbmigration.ddlgeneration;
import java.io.IOException;
import java.util.Map;
import java.util.TreeMap;
import java.util.function.Function;
import io.ebeaninternal.dbmigration.ddlgeneration.platform.BaseDdlBuffer;
import io.ebeaninternal.dbmigration.model.MConfiguration;
import io.ebeaninternal.dbmigration.model.MTable;
import io.ebeaninternal.dbmigration.model.ModelContainer;
/**
* Write context holding the buffers for both apply and rollback DDL.
* Write context holding the buffers for both apply and rollback DDL. Description of the apply buffers:
* <ul>
* <li><b>applyDropDependencies:</b> Contains drops for foreign keys, indices, constraint or drop history table</li>
* <li><b>apply:</b> Contains &#64;DbMigraion.before, create table, create sequence or disable system versioning statements</li>
* <li><b>applyAlterTables:</b> Contains table alters (only that change the table data structure, there may be table alters like
* constraints etc. in postAlter)</li>
* <li><b>applyPostAlter:</b> Contains check constraints, unique constraints (which CAN be an index), column and table comments,
* &#64;DbMigraion.after, drop tables, drop sequences or enable system versioning statement</li>
* <li><b>applyForeignKeys: Contains foreign keys and indices.</b>
* <li><b>applyHistoryView:</b> The views for trigger based history support</li>
* <li><b>applyHistoryTrigger:</b> The triggers for trigger based history support</li>
* </ul>
*/
public class DdlWrite {
private final ModelContainer currentModel;
private final DdlBuffer applyDropDependencies;
private final DdlBuffer applyDropDependencies = new BaseDdlBuffer();
private final DdlBuffer apply;
private final DdlBuffer apply = new BaseDdlBuffer();
private final DdlBuffer applyForeignKeys;
private final Map<String, DdlAlterTable> applyAlterTables = new TreeMap<>();
private final DdlBuffer applyHistoryView;
private final DdlBuffer applyPostAlter = new BaseDdlBuffer();
private final DdlBuffer applyHistoryTrigger;
private final DdlBuffer applyForeignKeys = new BaseDdlBuffer();
private final DdlBuffer dropAllForeignKeys;
private final DdlBuffer dropAllForeignKeys = new BaseDdlBuffer();
private final DdlBuffer dropAll;
private final DdlBuffer dropAll = new BaseDdlBuffer();
private final DdlOptions options;
@@ -40,13 +56,6 @@ public class DdlWrite {
*/
public DdlWrite(MConfiguration configuration, ModelContainer currentModel, DdlOptions options) {
this.currentModel = currentModel;
this.applyDropDependencies = new BaseDdlBuffer(configuration);
this.apply = new BaseDdlBuffer(configuration);
this.applyForeignKeys = new BaseDdlBuffer(configuration);
this.applyHistoryView = new BaseDdlBuffer(configuration);
this.applyHistoryTrigger = new BaseDdlBuffer(configuration);
this.dropAllForeignKeys = new BaseDdlBuffer(configuration);
this.dropAll = new BaseDdlBuffer(configuration);
this.options = options;
}
@@ -73,12 +82,19 @@ public class DdlWrite {
*/
public boolean isApplyEmpty() {
return apply.getBuffer().isEmpty()
&& applyAlterTables.isEmpty()
&& applyPostAlter.getBuffer().isEmpty()
&& applyForeignKeys.getBuffer().isEmpty()
&& applyHistoryView.getBuffer().isEmpty()
&& applyHistoryTrigger.getBuffer().isEmpty()
&& applyDropDependencies.getBuffer().isEmpty();
}
/**
* Return the buffer that POST ALTER is written to.
*/
public DdlBuffer applyPostAlter() {
return applyPostAlter;
}
/**
* Return the buffer that APPLY DDL is written to.
*/
@@ -93,6 +109,20 @@ public class DdlWrite {
return applyDropDependencies;
}
/**
* Creates or returns the DdlAlterTable statement for <code>tablename</code>.
*
* Note: All alters on a particular table are sorted in natural order in the ddl script. This allows optimizing the alters by
* merging them or doing a reorg table after altering is done.
*
* @param tableName the table name
* @param factory the factory to construct a new object
* @return
*/
public DdlAlterTable applyAlterTable(String tableName, Function<String, DdlAlterTable> factory) {
return applyAlterTables.computeIfAbsent(tableName, factory);
}
/**
* Return the buffer that APPLY DDL is written to for foreign keys and their associated indexes.
* <p>
@@ -103,20 +133,6 @@ public class DdlWrite {
return applyForeignKeys;
}
/**
* Return the buffer that apply history-view DDL is written to.
*/
public DdlBuffer applyHistoryView() {
return applyHistoryView;
}
/**
* Return the buffer that apply history-trigger DDL is written to.
*/
public DdlBuffer applyHistoryTrigger() {
return applyHistoryTrigger;
}
/**
* Return the buffer used for the 'drop all DDL' for dropping foreign keys and associated indexes.
*/
@@ -131,4 +147,61 @@ public class DdlWrite {
return dropAll;
}
/**
* Writes the apply ddl to the target.
*/
public void writeApply(Appendable target) throws IOException {
if (!applyDropDependencies.isEmpty()) {
target.append("-- drop dependencies\n");
target.append(applyDropDependencies.getBuffer());
}
if (!apply.isEmpty()) {
target.append("-- apply changes\n");
target.append(apply.getBuffer());
}
if (!applyAlterTables.isEmpty()) {
target.append("-- apply alter tables\n");
for (DdlAlterTable alterTable : applyAlterTables.values()) {
alterTable.write(target);
}
}
if (!applyPostAlter.isEmpty()) {
target.append("-- apply post alter\n");
target.append(applyPostAlter.getBuffer());
}
if (!applyForeignKeys.isEmpty()) {
target.append("-- foreign keys and indices\n");
target.append(applyForeignKeys.getBuffer());
}
}
/**
* Writes the drop all ddl to the target.
*/
public void writeDropAll(Appendable target) throws IOException {
if (!dropAllForeignKeys.isEmpty()) {
target.append("-- drop all foreign keys\n");
target.append(dropAllForeignKeys.getBuffer());
}
if (!dropAll.isEmpty()) {
target.append("-- drop all\n");
target.append(dropAll.getBuffer());
}
}
/**
* Returns all create statements. Mainly used for unit-tests
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
try {
writeDropAll(sb);
writeApply(sb);
} catch (IOException e) {
// can not happen
}
return sb.toString();
}
}
@@ -13,8 +13,6 @@ import io.ebeaninternal.dbmigration.migration.DropHistoryTable;
import io.ebeaninternal.dbmigration.migration.DropIndex;
import io.ebeaninternal.dbmigration.migration.DropTable;
import java.io.IOException;
/**
* Write table DDL.
*/
@@ -23,70 +21,70 @@ public interface TableDdl {
/**
* Generate the create table change.
*/
void generate(DdlWrite writer, CreateTable createTable) throws IOException;
void generate(DdlWrite writer, CreateTable createTable);
/**
* Write the drop column change.
*/
void generate(DdlWrite writer, DropTable dropTable) throws IOException;
void generate(DdlWrite writer, DropTable dropTable);
/**
* Write the add column change.
*/
void generate(DdlWrite writer, AddColumn addColumn) throws IOException;
void generate(DdlWrite writer, AddColumn addColumn);
/**
* Write the alter column changes.
*/
void generate(DdlWrite writer, AlterColumn alterColumn) throws IOException;
void generate(DdlWrite writer, AlterColumn alterColumn);
/**
* Write the drop column change.
*/
void generate(DdlWrite writer, DropColumn dropColumn) throws IOException;
void generate(DdlWrite writer, DropColumn dropColumn);
/**
* Write the AddTableComment change.
*/
void generate(DdlWrite writer, AddTableComment addTableComment) throws IOException;
void generate(DdlWrite writer, AddTableComment addTableComment);
/**
* Write the AddHistoryTable change.
*/
void generate(DdlWrite writer, AddHistoryTable addHistoryTable) throws IOException;
void generate(DdlWrite writer, AddHistoryTable addHistoryTable);
/**
* Write the DropHistoryTable change.
*/
void generate(DdlWrite writer, DropHistoryTable dropHistoryTable) throws IOException;
void generate(DdlWrite writer, DropHistoryTable dropHistoryTable);
/**
* Generate the create index change.
*/
void generate(DdlWrite writer, CreateIndex createIndex) throws IOException;
void generate(DdlWrite writer, CreateIndex createIndex);
/**
* Write the drop index change.
*/
void generate(DdlWrite writer, DropIndex dropIndex) throws IOException;
void generate(DdlWrite writer, DropIndex dropIndex);
/**
* Write add unique constraint.
*/
void generate(DdlWrite writer, AddUniqueConstraint constraint) throws IOException;
void generate(DdlWrite writer, AddUniqueConstraint constraint);
/**
* Writes alter foreign key statements.
*/
void generate(DdlWrite writer, AlterForeignKey alterForeignKey) throws IOException;
void generate(DdlWrite writer, AlterForeignKey alterForeignKey);
/**
* Generate any extra DDL such as stored procedures or TableValueParameters.
*/
void generateProlog(DdlWrite write) throws IOException;
void generateProlog(DdlWrite writer);
/**
* Generate any extra DDL such as regeneration of history triggers.
*/
void generateEpilog(DdlWrite write) throws IOException;
void generateEpilog(DdlWrite writer);
}
@@ -1,14 +1,20 @@
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
import io.ebean.config.DatabaseConfig;
import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebean.config.dbplatform.DbPlatformType;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlAlterTable;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlHandler;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite;
import io.ebeaninternal.dbmigration.migration.AlterColumn;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -18,16 +24,13 @@ public abstract class AbstractHanaDdl extends PlatformDdl {
public AbstractHanaDdl(DatabasePlatform platform) {
super(platform);
this.addColumn = "add (";
this.addColumnSuffix = ")";
this.alterColumn = "alter (";
this.alterColumnSuffix = ")";
this.columnDropDefault = " default null";
this.columnSetDefault = " default";
this.columnSetNotnull = " not null";
this.addColumn = "add";
this.alterColumn = "alter";
this.columnDropDefault = "default null";
this.columnSetDefault = "default";
this.columnSetNotnull = "not null";
this.columnSetNull = " null";
this.dropColumn = "drop (";
this.dropColumnSuffix = ")";
this.dropColumn = "drop";
this.dropConstraintIfExists = "drop constraint ";
this.dropIndexIfExists = "drop index ";
this.dropSequenceIfExists = "drop sequence ";
@@ -39,7 +42,7 @@ public abstract class AbstractHanaDdl extends PlatformDdl {
}
@Override
public String alterColumnBaseAttributes(AlterColumn alter) {
public void alterColumn(DdlWrite writer, AlterColumn alter) {
String tableName = alter.getTableName();
String columnName = alter.getColumnName();
String currentType = alter.getCurrentType();
@@ -52,51 +55,21 @@ public abstract class AbstractHanaDdl extends PlatformDdl {
: (alter.getDefaultValue() != null ? alter.getDefaultValue() : alter.getCurrentDefaultValue());
String defaultValueClause = (defaultValue == null || defaultValue.isEmpty()) ? "" : " default " + defaultValue;
try {
DdlBuffer buffer = new BaseDdlBuffer(null);
if (!isConvertible(currentType, type)) {
// add an intermediate conversion if possible
if (isNumberType(currentType)) {
// numbers can always be converted to decimal
buffer.append("alter table ").append(tableName).append(" ").append(alterColumn).append(" ").append(columnName)
.append(" decimal ").append(defaultValueClause).append(notnullClause).append(alterColumnSuffix)
.endOfStatement();
if (!isConvertible(currentType, type)) {
// add an intermediate conversion if possible
if (isNumberType(currentType)) {
// numbers can always be converted to decimal
alterTable(writer, tableName).append(alterColumn, columnName).append("decimal").append(notnullClause);
} else if (isStringType(currentType)) {
// strings can always be converted to nclob
buffer.append("alter table ").append(tableName).append(" ").append(alterColumn).append(" ").append(columnName)
.append(" nclob ").append(defaultValueClause).append(notnullClause).append(alterColumnSuffix)
.endOfStatement();
}
} else if (isStringType(currentType)) {
// strings can always be converted to nclob
// Note: we do not add default clause here to avoid error[SAP DBTech JDBC: [336]: invalid default value:
// default value cannot be created on column of data type NCLOB
alterTable(writer, tableName).append(alterColumn, columnName).append("nclob").append(notnullClause);
}
buffer.append("alter table ").append(tableName).append(" ").append(alterColumn).append(" ").append(columnName)
.append(" ").append(type).append(defaultValueClause).append(notnullClause).append(alterColumnSuffix);
return buffer.getBuffer();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public String alterColumnDefaultValue(String tableName, String columnName, String defaultValue) {
throw new UnsupportedOperationException();
}
@Override
public String alterColumnNotnull(String tableName, String columnName, boolean notnull) {
return null;
}
@Override
public DdlHandler createDdlHandler(DatabaseConfig config) {
return new HanaDdlHandler(config, this);
}
@Override
public String alterColumnType(String tableName, String columnName, String type) {
return null;
alterTable(writer, tableName).append(alterColumn, columnName).append(type).append(defaultValueClause).append(notnullClause);
}
@Override
@@ -120,20 +93,17 @@ public abstract class AbstractHanaDdl extends PlatformDdl {
@Override
public String alterTableDropUniqueConstraint(String tableName, String uniqueConstraintName) {
DdlBuffer buffer = new BaseDdlBuffer(null);
try {
buffer.append("delimiter $$").newLine();
buffer.append("do").newLine();
buffer.append("begin").newLine();
buffer.append("declare exit handler for sql_error_code 397 begin end").endOfStatement();
buffer.append("exec 'alter table ").append(tableName).append(" ").append(dropUniqueConstraint).append(" ")
.append(maxConstraintName(uniqueConstraintName)).append("'").endOfStatement();
buffer.append("end").endOfStatement();
buffer.append("$$");
return buffer.getBuffer();
} catch (IOException e) {
throw new RuntimeException(e);
}
DdlBuffer buffer = new BaseDdlBuffer();
buffer.append("delimiter $$").newLine();
buffer.append("do").newLine();
buffer.append("begin").newLine();
buffer.append("declare exit handler for sql_error_code 397 begin end").endOfStatement();
buffer.append("exec 'alter table ").append(tableName).append(" ").append(dropUniqueConstraint).append(" ")
.append(maxConstraintName(uniqueConstraintName)).append("'").endOfStatement();
buffer.append("end").endOfStatement();
buffer.append("$$");
return buffer.getBuffer();
}
@Override
@@ -146,9 +116,8 @@ public abstract class AbstractHanaDdl extends PlatformDdl {
* foreign keys. That's why we call a user stored procedure here
*/
@Override
public void alterTableDropColumn(DdlBuffer buffer, String tableName, String columnName) throws IOException {
buffer.append("CALL usp_ebean_drop_column('").append(tableName).append("', '").append(columnName).append("')")
.endOfStatement();
public void alterTableDropColumn(DdlWrite writer, String tableName, String columnName) {
alterTable(writer, tableName).raw("CALL usp_ebean_drop_column('").append(tableName).append("', '").append(columnName).append("')");
}
/**
@@ -222,4 +191,71 @@ public abstract class AbstractHanaDdl extends PlatformDdl {
return type != null
&& (type.startsWith("varchar") || type.startsWith("nvarchar") || "clob".equals(type) || "nclob".equals(type));
}
@Override
protected DdlAlterTable alterTable(DdlWrite writer, String tableName) {
return writer.applyAlterTable(tableName, HanaAlterTableWrite::new);
}
/**
* Joins alter table commands and add open/closing brackets for the alter statements
*/
private static class HanaAlterTableWrite extends BaseAlterTableWrite {
public HanaAlterTableWrite(String tableName) {
super(tableName);
}
@Override
protected List<AlterCmd> postProcessCommands(List<AlterCmd> cmds) {
List<AlterCmd> newCmds = new ArrayList<>();
Map<String, List<AlterCmd>> batches = new LinkedHashMap<>();
Set<String> columns = new HashSet<>();
for (AlterCmd cmd : cmds) {
switch (cmd.getOperation()) {
case "add":
case "alter":
case "drop":
if (cmd.getColumn() != null && !columns.add(cmd.getColumn())) {
// column already seen
flushBatches(newCmds, batches);
columns.clear();
}
batches.computeIfAbsent(cmd.getOperation(), k -> new ArrayList<>()).add(cmd);
break;
default:
flushBatches(newCmds, batches);
columns.clear();
newCmds.add(cmd);
}
}
flushBatches(newCmds, batches);
return newCmds;
}
/**
* Merges add/alter/drop commands into one statement.
*/
private void flushBatches(List<AlterCmd> newCmds, Map<String, List<AlterCmd>> batches) {
for (Entry<String, List<AlterCmd>> entry : batches.entrySet()) {
AlterCmd raw = newRawCommand("alter table ").append(tableName()).append(" ")
.append(entry.getKey()).append(" (");
List<AlterCmd> cmds = entry.getValue();
for (int i = 0; i < cmds.size(); i++) {
AlterCmd cmd = cmds.get(i);
if (i > 0) {
raw.append(",\n ");
}
raw.append(cmd.getColumn());
if (!cmd.getAlternation().isEmpty()) {
raw.append(" ").append(cmd.getAlternation());
}
}
raw.append(")");
newCmds.add(raw);
}
batches.clear();
}
}
}
@@ -0,0 +1,152 @@
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlAlterTable;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
/**
* Contains alter statements per table.
*
* @author Roland Praml, FOCONIS AG
*/
public class BaseAlterTableWrite implements DdlAlterTable {
protected static final String RAW_OPERATION = "$RAW";
public class AlterCmd {
// the command (e.g. "alter", "modify"
private final String operation;
// the affected column (note: each column can only be altered once on MariaDB)
private final String column;
private final DdlBuffer alternationBuffer = new BaseDdlBuffer() {
@Override
public DdlBuffer endOfStatement() {
throw new UnsupportedOperationException();
};
};
protected AlterCmd(String operation, String column) {
this.operation = operation;
this.column = column;
}
public AlterCmd append(String content) {
alternationBuffer.append(content);
return this;
}
public String getOperation() {
return operation;
}
public String getColumn() {
return column;
}
public String getAlternation() {
return alternationBuffer.getBuffer();
}
protected void write(Appendable target) throws IOException {
if (operation.equals(RAW_OPERATION)) {
// this is a raw command. e.g. an USP call. Must be done in the correct order
// of all alter commands
target.append(getAlternation());
} else {
target.append("alter table ").append(tableName).append(' ').append(operation);
if (column != null) {
target.append(' ').append(column);
}
if (!getAlternation().isEmpty()) {
target.append(' ').append(getAlternation());
}
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
try {
write(sb);
} catch (IOException e) {
throw new RuntimeException(e);
}
return sb.toString();
}
}
private final String tableName;
private List<AlterCmd> cmds = new ArrayList<>();
private boolean historyHandled;
public BaseAlterTableWrite(String tableName) {
this.tableName = tableName;
}
public String tableName() {
return tableName;
}
protected AlterCmd newRawCommand(String sql) {
AlterCmd cmd = new AlterCmd(RAW_OPERATION, null);
cmd.alternationBuffer.append(sql);
return cmd;
}
public AlterCmd newOperation(String operation, String column) {
return new AlterCmd(operation, column);
}
/**
* Adds a statement. The statement is prefixed with "alter table TABLENAME" and may be batched, if platform supports this. The
* returned StringBuilder can be used, to complete the statement
*/
@Override
public DdlBuffer append(String operation, String column) {
AlterCmd cmd = new AlterCmd(operation, column);
cmds.add(cmd);
return cmd.alternationBuffer;
}
@Override
public DdlBuffer raw(String sql) {
AlterCmd cmd = newRawCommand(sql);
cmds.add(cmd);
return cmd.alternationBuffer;
}
/**
* Method can be overwritten to return a new list of commands. The given list must not be modified, but a new command list with
* modified commands can be returned (e.g. to handle DB2 reorg or special syntax in Hana)
*/
protected List<AlterCmd> postProcessCommands(List<AlterCmd> cmds) {
return cmds;
}
/**
* Writes the DDL to <code>target</code>.
*/
@Override
public void write(Appendable target) throws IOException {
for (AlterCmd cmd : postProcessCommands(Collections.unmodifiableList(cmds))) {
cmd.write(target);
target.append(";\n");
}
}
@Override
public boolean isHistoryHandled() {
return historyHandled;
}
@Override
public void setHistoryHandled() {
historyHandled = true;
}
}
@@ -1,45 +1,34 @@
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
import io.ebeaninternal.dbmigration.model.MConfiguration;
import java.io.IOException;
import java.io.StringWriter;
/**
* Base implementation of DdlBuffer using an underlying writer.
*/
public class BaseDdlBuffer implements DdlBuffer {
protected final StringWriter writer;
protected final StringBuilder writer;
protected final MConfiguration configuration;
public BaseDdlBuffer(MConfiguration configuration) {
this.configuration = configuration;
this.writer = new StringWriter();
}
@Override
public MConfiguration getConfiguration() {
return configuration;
public BaseDdlBuffer() {
this.writer = new StringBuilder();
}
@Override
public boolean isEmpty() {
return writer.getBuffer().length() == 0;
return writer.length() == 0;
}
@Override
public DdlBuffer appendWithSpace(String foreignKeyRestrict) throws IOException {
if (foreignKeyRestrict != null && !foreignKeyRestrict.isEmpty()) {
writer.append(" ").append(foreignKeyRestrict);
public DdlBuffer appendWithSpace(String content) {
if (content != null && !content.isEmpty()) {
writer.append(" ").append(content);
}
return this;
}
@Override
public DdlBuffer appendStatement(String content) throws IOException {
public DdlBuffer appendStatement(String content) {
if (content != null && !content.isEmpty()) {
writer.append(content);
endOfStatement();
@@ -48,19 +37,19 @@ public class BaseDdlBuffer implements DdlBuffer {
}
@Override
public DdlBuffer append(String content) throws IOException {
public DdlBuffer append(String content) {
writer.append(content);
return this;
}
@Override
public DdlBuffer append(String content, int space) throws IOException {
public DdlBuffer append(String content, int space) {
writer.append(content);
appendSpace(space, content);
return this;
}
protected void appendSpace(int max, String content) throws IOException {
protected void appendSpace(int max, String content) {
int space = max - content.length();
if (space > 0) {
for (int i = 0; i < space; i++) {
@@ -71,7 +60,7 @@ public class BaseDdlBuffer implements DdlBuffer {
}
@Override
public DdlBuffer endOfStatement() throws IOException {
public DdlBuffer endOfStatement() {
writer.append(";\n");
return this;
}
@@ -81,7 +70,7 @@ public class BaseDdlBuffer implements DdlBuffer {
* This should be just whitespace or a sql comment.
*/
@Override
public DdlBuffer end() throws IOException {
public DdlBuffer end() {
if (!isEmpty()) {
writer.append("\n");
}
@@ -89,7 +78,7 @@ public class BaseDdlBuffer implements DdlBuffer {
}
@Override
public DdlBuffer newLine() throws IOException {
public DdlBuffer newLine() {
writer.append("\n");
return this;
}
@@ -11,7 +11,6 @@ import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlOptions;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite;
import io.ebeaninternal.dbmigration.ddlgeneration.TableDdl;
import io.ebeaninternal.dbmigration.ddlgeneration.platform.util.IndexSet;
import io.ebeaninternal.dbmigration.migration.AddColumn;
import io.ebeaninternal.dbmigration.migration.AddHistoryTable;
import io.ebeaninternal.dbmigration.migration.AddTableComment;
@@ -32,12 +31,9 @@ import io.ebeaninternal.dbmigration.model.MTable;
import io.ebeaninternal.dbmigration.model.MTableIdentity;
import io.ebeaninternal.server.deploy.IdentityMode;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import static io.ebean.util.StringHelper.replace;
import static io.ebeaninternal.api.PlatformMatch.matchPlatform;
@@ -48,12 +44,6 @@ import static io.ebeaninternal.dbmigration.ddlgeneration.platform.SplitColumns.s
*/
public class BaseTableDdl implements TableDdl {
enum HistorySupport {
NONE,
SQL2011,
TRIGGER_BASED
}
protected final DbConstraintNaming naming;
protected final NamingConvention namingConvention;
@@ -62,12 +52,6 @@ public class BaseTableDdl implements TableDdl {
protected final String historyTableSuffix;
/**
* Used to check that indexes on foreign keys should be skipped as a unique index on the columns
* already exists.
*/
protected final IndexSet indexSet = new IndexSet();
/**
* Used when unique constraints specifically for OneToOne can't be created normally (MsSqlServer).
*/
@@ -75,22 +59,9 @@ public class BaseTableDdl implements TableDdl {
protected final List<UniqueConstraint> externalCompoundUnique = new ArrayList<>();
// counters used when constraint names are truncated due to maximum length
// and these counters are used to keep the constraint name unique
protected int countCheck;
protected int countUnique;
protected int countForeignKey;
protected int countIndex;
/**
* Base tables that have associated history tables that need their triggers/functions regenerated as
* columns have been added, removed, included or excluded.
*/
protected final Map<String, HistoryTableUpdate> regenerateHistoryTriggers = new LinkedHashMap<>();
private final boolean strictMode;
private final HistorySupport historySupport;
private final boolean alterHistoryTables;
/**
* Helper class that is used to execute the migration ddl before and after the migration action.
@@ -141,29 +112,29 @@ public class BaseTableDdl implements TableDdl {
after = getScriptsForPlatform(alter.getAfter());
}
void writeBefore(DdlBuffer buffer) throws IOException {
void write(DdlWrite writer) {
if (!before.isEmpty()) {
buffer.end();
}
if (!before.isEmpty() && withHistory) {
buffer.append("-- NOTE: table has @History - special migration may be necessary").newLine();
}
for (String ddlScript : before) {
buffer.appendStatement(translate(ddlScript, tableName, columnName, defaultValue));
}
}
void writeAfter(DdlBuffer buffer) throws IOException {
if (!after.isEmpty() && withHistory) {
buffer.append("-- NOTE: table has @History - special migration may be necessary").newLine();
}
// here we run post migration scripts
for (String ddlScript : after) {
buffer.appendStatement(translate(ddlScript, tableName, columnName, defaultValue));
writer.apply().end();
if (withHistory) {
writer.apply().append("-- NOTE: table has @History - special migration may be necessary").newLine();
}
for (String ddlScript : before) {
writer.apply().appendStatement(translate(ddlScript, tableName, columnName, defaultValue));
}
}
// effective order in DDL.sql:
// 'before' goes to apply-buffer
// altered columns will be in the alterTable buffers.
// 'after' goes to the post-alter-buffer
if (!after.isEmpty()) {
buffer.end();
writer.applyPostAlter().append("-- NOTE: table has @History - special migration may be necessary").newLine();
// here we run post migration scripts
for (String ddlScript : after) {
writer.applyPostAlter().appendStatement(translate(ddlScript, tableName, columnName, defaultValue));
}
writer.applyPostAlter().end();
}
}
@@ -211,9 +182,9 @@ public class BaseTableDdl implements TableDdl {
this.strictMode = config.isDdlStrictMode();
DbHistorySupport hist = platformDdl.getPlatform().getHistorySupport();
if (hist == null) {
this.historySupport = HistorySupport.NONE;
this.alterHistoryTables = false;
} else {
this.historySupport = hist.isStandardsBased() ? HistorySupport.SQL2011 : HistorySupport.TRIGGER_BASED;
this.alterHistoryTables = platformDdl.historyDdl.alterHistoryTables();
}
}
@@ -221,13 +192,8 @@ public class BaseTableDdl implements TableDdl {
* Reset counters and index set for each table processed.
*/
protected void reset() {
indexSet.clear();
externalUnique.clear();
externalCompoundUnique.clear();
countCheck = 0;
countUnique = 0;
countForeignKey = 0;
countIndex = 0;
}
/**
@@ -235,7 +201,7 @@ public class BaseTableDdl implements TableDdl {
* and add them to the appropriate 'apply' and 'rollback' buffers.
*/
@Override
public void generate(DdlWrite writer, CreateTable createTable) throws IOException {
public void generate(DdlWrite writer, CreateTable createTable) {
reset();
String tableName = lowerTableName(createTable.getName());
@@ -267,7 +233,7 @@ public class BaseTableDdl implements TableDdl {
}
}
if (platformDdl.isInlineForeignKeys()) {
writeInlineForeignKeys(writer, createTable);
writeInlineForeignKeys(apply, createTable);
}
apply.newLine().append(")");
addTableStorageEngine(apply, createTable);
@@ -308,7 +274,7 @@ public class BaseTableDdl implements TableDdl {
/**
* Add table and column comments (separate from the create table statement).
*/
private void addComments(DdlBuffer apply, CreateTable createTable) throws IOException {
private void addComments(DdlBuffer apply, CreateTable createTable) {
if (!platformDdl.isInlineComments()) {
String tableComment = createTable.getComment();
if (hasValue(tableComment)) {
@@ -325,7 +291,7 @@ public class BaseTableDdl implements TableDdl {
/**
* Add the table storage engine clause.
*/
private void addTableStorageEngine(DdlBuffer apply, CreateTable createTable) throws IOException {
private void addTableStorageEngine(DdlBuffer apply, CreateTable createTable) {
if (platformDdl.isIncludeStorageEngine()) {
platformDdl.tableStorageEngine(apply, createTable.getStorageEngine());
}
@@ -334,7 +300,7 @@ public class BaseTableDdl implements TableDdl {
/**
* Add the table comment inline with the create table statement.
*/
private void addTableCommentInline(DdlBuffer apply, CreateTable createTable) throws IOException {
private void addTableCommentInline(DdlBuffer apply, CreateTable createTable) {
if (platformDdl.isInlineComments()) {
String tableComment = createTable.getComment();
if (!StringHelper.isNull(tableComment)) {
@@ -343,7 +309,7 @@ public class BaseTableDdl implements TableDdl {
}
}
private void writeTableColumns(DdlBuffer apply, List<Column> columns, DdlIdentity identity) throws IOException {
private void writeTableColumns(DdlBuffer apply, List<Column> columns, DdlIdentity identity) {
platformDdl.writeTableColumns(apply, columns, identity);
}
@@ -351,7 +317,7 @@ public class BaseTableDdl implements TableDdl {
* Specific handling of OneToOne unique constraints for MsSqlServer.
* For all other DB platforms these unique constraints are done inline as per normal.
*/
protected void writeUniqueOneToOneConstraints(DdlWrite write, CreateTable createTable) throws IOException {
protected void writeUniqueOneToOneConstraints(DdlWrite writer, CreateTable createTable) {
String tableName = createTable.getName();
for (Column col : externalUnique) {
String uqName = col.getUniqueOneToOne();
@@ -359,8 +325,9 @@ public class BaseTableDdl implements TableDdl {
uqName = col.getUnique();
}
String[] columnNames = {col.getName()};
write.apply().appendStatement(platformDdl.alterTableAddUniqueConstraint(tableName, uqName, columnNames, Boolean.TRUE.equals(col.isNotnull()) ? null : columnNames));
write.dropAllForeignKeys().appendStatement(platformDdl.dropIndex(uqName, tableName));
String[] nullableColumns = Boolean.TRUE.equals(col.isNotnull()) ? null : columnNames;
writer.applyPostAlter().appendStatement(platformDdl.alterTableAddUniqueConstraint(tableName, uqName, columnNames, nullableColumns));
writer.dropAllForeignKeys().appendStatement(platformDdl.dropIndex(uqName, tableName));
}
for (UniqueConstraint constraint : externalCompoundUnique) {
@@ -368,12 +335,12 @@ public class BaseTableDdl implements TableDdl {
String[] columnNames = split(constraint.getColumnNames());
String[] nullableColumns = split(constraint.getNullableColumns());
write.apply().appendStatement(platformDdl.alterTableAddUniqueConstraint(tableName, uqName, columnNames, nullableColumns));
write.dropAllForeignKeys().appendStatement(platformDdl.dropIndex(uqName, tableName));
writer.applyPostAlter().appendStatement(platformDdl.alterTableAddUniqueConstraint(tableName, uqName, columnNames, nullableColumns));
writer.dropAllForeignKeys().appendStatement(platformDdl.dropIndex(uqName, tableName));
}
}
protected void writeSequence(DdlWrite writer, DdlIdentity identity) throws IOException {
protected void writeSequence(DdlWrite writer, DdlIdentity identity) {
String seqName = identity.getSequenceName();
String createSeq = platformDdl.createSequence(seqName, identity);
if (hasValue(createSeq)) {
@@ -382,75 +349,75 @@ public class BaseTableDdl implements TableDdl {
}
}
protected void createWithHistory(DdlWrite writer, String name) throws IOException {
protected void createWithHistory(DdlWrite writer, String name) {
MTable table = writer.getTable(name);
platformDdl.createWithHistory(writer, table);
}
protected void writeInlineForeignKeys(DdlWrite write, CreateTable createTable) throws IOException {
protected void writeInlineForeignKeys(DdlBuffer buffer, CreateTable createTable) {
for (Column column : createTable.getColumn()) {
String references = column.getReferences();
if (hasValue(references)) {
writeInlineForeignKey(write, column);
writeInlineForeignKey(buffer, column);
}
}
writeInlineCompoundForeignKeys(write, createTable);
writeInlineCompoundForeignKeys(buffer, createTable);
}
protected void writeInlineForeignKey(DdlWrite write, Column column) throws IOException {
protected void writeInlineForeignKey(DdlBuffer buffer, Column column) {
String fkConstraint = platformDdl.tableInlineForeignKey(new WriteForeignKey(null, column));
write.apply().append(",").newLine().append(" ").append(fkConstraint);
buffer.append(",").newLine().append(" ").append(fkConstraint);
}
protected void writeInlineCompoundForeignKeys(DdlWrite write, CreateTable createTable) throws IOException {
protected void writeInlineCompoundForeignKeys(DdlBuffer buffer, CreateTable createTable) {
for (ForeignKey key : createTable.getForeignKey()) {
String fkConstraint = platformDdl.tableInlineForeignKey(new WriteForeignKey(null, key));
write.apply().append(",").newLine().append(" ").append(fkConstraint);
buffer.append(",").newLine().append(" ").append(fkConstraint);
}
}
protected void writeAddForeignKeys(DdlWrite write, CreateTable createTable) throws IOException {
protected void writeAddForeignKeys(DdlWrite writer, CreateTable createTable) {
for (Column column : createTable.getColumn()) {
String references = column.getReferences();
if (hasValue(references)) {
writeForeignKey(write, createTable.getName(), column);
writeForeignKey(writer, createTable.getName(), column);
}
}
writeAddCompoundForeignKeys(write, createTable);
writeAddCompoundForeignKeys(writer, createTable);
}
protected void writeAddCompoundForeignKeys(DdlWrite write, CreateTable createTable) throws IOException {
protected void writeAddCompoundForeignKeys(DdlWrite writer, CreateTable createTable) {
for (ForeignKey key : createTable.getForeignKey()) {
writeForeignKey(write, new WriteForeignKey(createTable.getName(), key));
writeForeignKey(writer, new WriteForeignKey(createTable.getName(), key));
}
}
protected void writeForeignKey(DdlWrite write, String tableName, Column column) throws IOException {
writeForeignKey(write, new WriteForeignKey(tableName, column));
protected void writeForeignKey(DdlWrite writer, String tableName, Column column) {
writeForeignKey(writer, new WriteForeignKey(tableName, column));
}
protected void writeForeignKey(DdlWrite write, WriteForeignKey request) throws IOException {
DdlBuffer fkeyBuffer = write.applyForeignKeys();
protected void writeForeignKey(DdlWrite writer, WriteForeignKey request) {
DdlBuffer fkeyBuffer = writer.applyForeignKeys();
String tableName = lowerTableName(request.table());
if (request.indexName() != null) {
// no matching unique constraint so add the index
fkeyBuffer.appendStatement(platformDdl.createIndex(new WriteCreateIndex(request.indexName(), tableName, request.cols(), false)));
}
alterTableAddForeignKey(write.getOptions(), fkeyBuffer, request);
alterTableAddForeignKey(writer.getOptions(), fkeyBuffer, request);
fkeyBuffer.end();
write.dropAllForeignKeys().appendStatement(platformDdl.alterTableDropForeignKey(tableName, request.fkName()));
writer.dropAllForeignKeys().appendStatement(platformDdl.alterTableDropForeignKey(tableName, request.fkName()));
if (hasValue(request.indexName())) {
write.dropAllForeignKeys().appendStatement(platformDdl.dropIndex(request.indexName(), tableName));
writer.dropAllForeignKeys().appendStatement(platformDdl.dropIndex(request.indexName(), tableName));
}
write.dropAllForeignKeys().end();
writer.dropAllForeignKeys().end();
}
protected void alterTableAddForeignKey(DdlOptions options, DdlBuffer buffer, WriteForeignKey request) throws IOException {
protected void alterTableAddForeignKey(DdlOptions options, DdlBuffer buffer, WriteForeignKey request) {
buffer.appendStatement(platformDdl.alterTableAddForeignKey(options, request));
}
protected void appendColumns(String[] columns, DdlBuffer buffer) throws IOException {
protected void appendColumns(String[] columns, DdlBuffer buffer) {
buffer.append(" (");
for (int i = 0; i < columns.length; i++) {
if (i > 0) {
@@ -464,18 +431,18 @@ public class BaseTableDdl implements TableDdl {
/**
* Add 'drop table' statement to the buffer.
*/
protected void dropTable(DdlBuffer buffer, String tableName) throws IOException {
protected void dropTable(DdlBuffer buffer, String tableName) {
buffer.appendStatement(platformDdl.dropTable(tableName));
}
/**
* Add 'drop sequence' statement to the buffer.
*/
protected void dropSequence(DdlBuffer buffer, String sequenceName) throws IOException {
protected void dropSequence(DdlBuffer buffer, String sequenceName) {
buffer.appendStatement(platformDdl.dropSequence(sequenceName));
}
protected void writeCompoundUniqueConstraints(DdlBuffer apply, CreateTable createTable) throws IOException {
protected void writeCompoundUniqueConstraints(DdlBuffer apply, CreateTable createTable) {
boolean inlineUniqueWhenNull = platformDdl.isInlineUniqueWhenNullable();
for (UniqueConstraint uniqueConstraint : createTable.getUniqueConstraint()) {
if (platformInclude(uniqueConstraint.getPlatforms())) {
@@ -498,7 +465,7 @@ public class BaseTableDdl implements TableDdl {
/**
* Write the unique constraints inline with the create table statement.
*/
protected void writeUniqueConstraints(DdlBuffer apply, CreateTable createTable) throws IOException {
protected void writeUniqueConstraints(DdlBuffer apply, CreateTable createTable) {
boolean inlineUniqueWhenNullable = platformDdl.isInlineUniqueWhenNullable();
List<Column> columns = new WriteUniqueConstraint(createTable.getColumn()).uniqueKeys();
for (Column column : columns) {
@@ -515,7 +482,7 @@ public class BaseTableDdl implements TableDdl {
/**
* Write the unique constraint inline with the create table statement.
*/
protected void inlineUniqueConstraintSingle(DdlBuffer buffer, Column column) throws IOException {
protected void inlineUniqueConstraintSingle(DdlBuffer buffer, Column column) {
String uqName = column.getUnique();
if (uqName == null) {
uqName = column.getUniqueOneToOne();
@@ -530,7 +497,7 @@ public class BaseTableDdl implements TableDdl {
/**
* Write the primary key constraint inline with the create table statement.
*/
protected void writePrimaryKeyConstraint(DdlBuffer buffer, String pkName, String[] pkColumns) throws IOException {
protected void writePrimaryKeyConstraint(DdlBuffer buffer, String pkName, String[] pkColumns) {
buffer.append(",").newLine();
buffer.append(" constraint ").append(pkName).append(" primary key");
appendColumns(pkColumns, buffer);
@@ -575,40 +542,43 @@ public class BaseTableDdl implements TableDdl {
}
@Override
public void generate(DdlWrite writer, CreateIndex index) throws IOException {
public void generate(DdlWrite writer, CreateIndex index) {
if (platformInclude(index.getPlatforms())) {
writer.apply().appendStatement(platformDdl.createIndex(new WriteCreateIndex(index)));
writer.applyForeignKeys().appendStatement(platformDdl.createIndex(new WriteCreateIndex(index)));
writer.dropAll().appendStatement(platformDdl.dropIndex(index.getIndexName(), index.getTableName(), Boolean.TRUE.equals(index.isConcurrent())));
}
}
@Override
public void generate(DdlWrite writer, DropIndex dropIndex) throws IOException {
public void generate(DdlWrite writer, DropIndex dropIndex) {
if (platformInclude(dropIndex.getPlatforms())) {
writer.apply().appendStatement(platformDdl.dropIndex(dropIndex.getIndexName(), dropIndex.getTableName(), Boolean.TRUE.equals(dropIndex.isConcurrent())));
writer.applyDropDependencies()
.appendStatement(platformDdl.dropIndex(dropIndex.getIndexName(), dropIndex.getTableName(), Boolean.TRUE.equals(dropIndex.isConcurrent())));
}
}
@Override
public void generate(DdlWrite writer, AddUniqueConstraint constraint) throws IOException {
public void generate(DdlWrite writer, AddUniqueConstraint constraint) {
if (platformInclude(constraint.getPlatforms())) {
if (DdlHelp.isDropConstraint(constraint.getColumnNames())) {
writer.apply().appendStatement(platformDdl.alterTableDropUniqueConstraint(constraint.getTableName(), constraint.getConstraintName()));
writer.applyDropDependencies()
.appendStatement(platformDdl.alterTableDropUniqueConstraint(constraint.getTableName(), constraint.getConstraintName()));
} else {
String[] cols = split(constraint.getColumnNames());
String[] nullableColumns = split(constraint.getNullableColumns());
writer.apply().appendStatement(platformDdl.alterTableAddUniqueConstraint(constraint.getTableName(), constraint.getConstraintName(), cols, nullableColumns));
writer.applyPostAlter()
.appendStatement(platformDdl.alterTableAddUniqueConstraint(constraint.getTableName(), constraint.getConstraintName(), cols, nullableColumns));
}
}
}
@Override
public void generate(DdlWrite writer, AlterForeignKey alterForeignKey) throws IOException {
public void generate(DdlWrite writer, AlterForeignKey alterForeignKey) {
if (DdlHelp.isDropForeignKey(alterForeignKey.getColumnNames())) {
writer.apply().appendStatement(platformDdl.alterTableDropForeignKey(alterForeignKey.getTableName(), alterForeignKey.getName()));
writer.applyDropDependencies().appendStatement(platformDdl.alterTableDropForeignKey(alterForeignKey.getTableName(), alterForeignKey.getName()));
} else {
writer.apply().appendStatement(platformDdl.alterTableAddForeignKey(writer.getOptions(), new WriteForeignKey(alterForeignKey)));
writer.applyForeignKeys().appendStatement(platformDdl.alterTableAddForeignKey(writer.getOptions(), new WriteForeignKey(alterForeignKey)));
}
}
@@ -616,7 +586,7 @@ public class BaseTableDdl implements TableDdl {
* Add add history table DDL.
*/
@Override
public void generate(DdlWrite writer, AddHistoryTable addHistoryTable) throws IOException {
public void generate(DdlWrite writer, AddHistoryTable addHistoryTable) {
platformDdl.addHistoryTable(writer, addHistoryTable);
}
@@ -624,36 +594,27 @@ public class BaseTableDdl implements TableDdl {
* Add drop history table DDL.
*/
@Override
public void generate(DdlWrite writer, DropHistoryTable dropHistoryTable) throws IOException {
public void generate(DdlWrite writer, DropHistoryTable dropHistoryTable) {
platformDdl.dropHistoryTable(writer, dropHistoryTable);
}
@Override
public void generateProlog(DdlWrite write) throws IOException {
platformDdl.generateProlog(write);
public void generateProlog(DdlWrite writer) {
platformDdl.generateProlog(writer);
}
/**
* Called at the end to generate additional ddl such as regenerate history triggers.
*/
@Override
public void generateEpilog(DdlWrite write) throws IOException {
if (!regenerateHistoryTriggers.isEmpty()) {
platformDdl.lockTables(write.applyHistoryTrigger(), regenerateHistoryTriggers.keySet());
for (HistoryTableUpdate update : this.regenerateHistoryTriggers.values()) {
platformDdl.regenerateHistoryTriggers(write, update);
}
platformDdl.unlockTables(write.applyHistoryTrigger(), regenerateHistoryTriggers.keySet());
}
platformDdl.generateEpilog(write);
public void generateEpilog(DdlWrite writer) {
platformDdl.generateEpilog(writer);
}
@Override
public void generate(DdlWrite writer, AddTableComment addTableComment) throws IOException {
public void generate(DdlWrite writer, AddTableComment addTableComment) {
if (hasValue(addTableComment.getComment())) {
platformDdl.addTableComment(writer.apply(), addTableComment.getName(), addTableComment.getComment());
platformDdl.addTableComment(writer.applyPostAlter(), addTableComment.getName(), addTableComment.getComment());
}
}
@@ -661,18 +622,20 @@ public class BaseTableDdl implements TableDdl {
* Add add column DDL.
*/
@Override
public void generate(DdlWrite writer, AddColumn addColumn) throws IOException {
public void generate(DdlWrite writer, AddColumn addColumn) {
String tableName = addColumn.getTableName();
List<Column> columns = addColumn.getColumn();
for (Column column : columns) {
alterTableAddColumn(writer.apply(), tableName, column, false, isTrue(addColumn.isWithHistory()));
alterTableAddColumn(writer, tableName, column, false, isTrue(addColumn.isWithHistory()));
}
if (isTrue(addColumn.isWithHistory()) && historySupport == HistorySupport.TRIGGER_BASED) {
if (isTrue(addColumn.isWithHistory())) {
platformDdl.regenerateHistoryTriggers(writer, tableName);
// make same changes to the history table
String historyTable = historyTable(tableName);
for (Column column : columns) {
regenerateHistoryTriggers(tableName, HistoryTableUpdate.Change.ADD, column.getName());
alterTableAddColumn(writer.apply(), historyTable, column, true, true);
if (alterHistoryTables) {
String historyTable = historyTable(tableName);
for (Column column : columns) {
alterTableAddColumn(writer, historyTable, column, true, true);
}
}
}
for (Column column : columns) {
@@ -680,22 +643,21 @@ public class BaseTableDdl implements TableDdl {
writeForeignKey(writer, tableName, column);
}
}
writer.apply().end();
}
/**
* Add drop table DDL.
*/
@Override
public void generate(DdlWrite writer, DropTable dropTable) throws IOException {
dropTable(writer.apply(), dropTable.getName());
public void generate(DdlWrite writer, DropTable dropTable) {
dropTable(writer.applyPostAlter(), dropTable.getName());
if (hasValue(dropTable.getSequenceCol())
&& platformDdl.getPlatform().getDbIdentity().isSupportsSequence()) {
String sequenceName = dropTable.getSequenceName();
if (!hasValue(sequenceName)) {
sequenceName = namingConvention.getSequenceName(dropTable.getName(), dropTable.getSequenceCol());
}
dropSequence(writer.apply(), sequenceName);
dropSequence(writer.applyPostAlter(), sequenceName);
}
}
@@ -703,30 +665,32 @@ public class BaseTableDdl implements TableDdl {
* Add drop column DDL.
*/
@Override
public void generate(DdlWrite writer, DropColumn dropColumn) throws IOException {
public void generate(DdlWrite writer, DropColumn dropColumn) {
String tableName = dropColumn.getTableName();
alterTableDropColumn(writer.apply(), tableName, dropColumn.getColumnName());
alterTableDropColumn(writer, tableName, dropColumn.getColumnName());
if (isTrue(dropColumn.isWithHistory()) && historySupport == HistorySupport.TRIGGER_BASED) {
if (isTrue(dropColumn.isWithHistory())) {
platformDdl.regenerateHistoryTriggers(writer, tableName);
// also drop from the history table
regenerateHistoryTriggers(tableName, HistoryTableUpdate.Change.DROP, dropColumn.getColumnName());
alterTableDropColumn(writer.apply(), historyTable(tableName), dropColumn.getColumnName());
if (alterHistoryTables) {
alterTableDropColumn(writer, historyTable(tableName), dropColumn.getColumnName());
}
}
writer.apply().end();
}
/**
* Add all the appropriate changes based on the column changes.
*/
@Override
public void generate(DdlWrite writer, AlterColumn alterColumn) throws IOException {
public void generate(DdlWrite writer, AlterColumn alterColumn) {
DdlMigrationHelp ddlHelp = new DdlMigrationHelp(alterColumn);
ddlHelp.writeBefore(writer.apply());
ddlHelp.write(writer);
if (isTrue(alterColumn.isHistoryExclude())) {
regenerateHistoryTriggers(alterColumn.getTableName(), HistoryTableUpdate.Change.EXCLUDE, alterColumn.getColumnName());
} else if (isFalse(alterColumn.isHistoryExclude())) {
regenerateHistoryTriggers(alterColumn.getTableName(), HistoryTableUpdate.Change.INCLUDE, alterColumn.getColumnName());
if (alterColumn.isHistoryExclude() != null) {
// CHECKME should we drop a small comment, if historyExclude changes, as not all DB systems will support this
// writer.apply().append("-- historyExclude of ").append(alterColumn.getTableName()).append(".").append(alterColumn.getColumnName())
// .append(" altered to ").append(String.valueOf(alterColumn.isHistoryExclude())).end();
platformDdl.regenerateHistoryTriggers(writer, alterColumn.getTableName());
}
if (hasValue(alterColumn.getDropForeignKey())) {
@@ -758,31 +722,21 @@ public class BaseTableDdl implements TableDdl {
// drop constraint before altering type etc
dropCheckConstraint(writer, alterColumn, alterColumn.getCheckConstraintName());
}
boolean alterBaseAttributes = false;
if (hasValue(alterColumn.getType())) {
alterColumnType(writer, alterColumn);
alterBaseAttributes = true;
}
if (hasValue(alterColumn.getDefaultValue())) {
alterColumnDefaultValue(writer, alterColumn);
alterBaseAttributes = true;
}
if (alterColumn.isNotnull() != null) {
alterColumnNotnull(writer, alterColumn);
alterBaseAttributes = true;
}
if (alterBaseAttributes) {
alterColumnBaseAttributes(writer, alterColumn);
if (hasValue(alterColumn.getType())
|| hasValue(alterColumn.getDefaultValue())
|| alterColumn.isNotnull() != null) {
alterColumn(writer, alterColumn);
}
if (alterCheckConstraint) {
// add constraint last (after potential type change)
addCheckConstraint(writer, alterColumn);
}
ddlHelp.writeAfter(writer.apply());
}
private void alterColumnComment(DdlWrite writer, AlterColumn alterColumn) throws IOException {
platformDdl.addColumnComment(writer.apply(), alterColumn.getTableName(), alterColumn.getColumnName(), alterColumn.getComment());
private void alterColumnComment(DdlWrite writer, AlterColumn alterColumn) {
platformDdl.addColumnComment(writer.applyPostAlter(), alterColumn.getTableName(), alterColumn.getColumnName(), alterColumn.getComment());
}
/**
@@ -793,114 +747,108 @@ public class BaseTableDdl implements TableDdl {
}
/**
* Register the base table that we need to regenerate the history triggers on.
* alter all the base attributes (type/default/notnull) of the column together.
* Some platforms (like mysql/sqlserver/hana) must do that in one statement,
* other platforms may use several statements for altering one of the base
* attributes.
*/
protected void regenerateHistoryTriggers(String baseTableName, HistoryTableUpdate.Change change, String column) {
HistoryTableUpdate update = regenerateHistoryTriggers.computeIfAbsent(baseTableName, HistoryTableUpdate::new);
update.add(change, column);
}
protected void alterColumn(DdlWrite writer, AlterColumn alter) {
platformDdl.alterColumn(writer, alter);
/**
* This is mysql specific - alter all the base attributes of the column together.
* Will be called, if there is a type, dbdefault or notnull change.
*/
protected void alterColumnBaseAttributes(DdlWrite writer, AlterColumn alter) throws IOException {
String ddl = platformDdl.alterColumnBaseAttributes(alter);
if (hasValue(ddl)) {
writer.apply().appendStatement(ddl);
if (isTrue(alter.isWithHistory()) && alter.getType() != null && historySupport == HistorySupport.TRIGGER_BASED) {
// mysql and sql server column type change allowing nulls in the history table column
regenerateHistoryTriggers(alter.getTableName(), HistoryTableUpdate.Change.ALTER, alter.getColumnName());
AlterColumn alterHistoryColumn = new AlterColumn();
alterHistoryColumn.setTableName(historyTable(alter.getTableName()));
alterHistoryColumn.setColumnName(alter.getColumnName());
alterHistoryColumn.setType(alter.getType());
String histColumnDdl = platformDdl.alterColumnBaseAttributes(alterHistoryColumn);
// write the apply to history table
writer.apply().appendStatement(histColumnDdl);
if (isTrue(alter.isWithHistory())) {
// we will apply only type changes or notNull -> null transition
boolean isNull = Boolean.FALSE.equals(alter.isNotnull());
boolean applyToHistory = alter.getType() != null || isNull;
boolean syncExact = platformDdl.getPlatform().isPlatform(Platform.DB2);
// DB2 needs exact sync for notnull/null
if (syncExact && alter.isNotnull() != null) {
applyToHistory = true;
}
if (applyToHistory) {
platformDdl.regenerateHistoryTriggers(writer, alter.getTableName());
if (alterHistoryTables) {
AlterColumn alterHistoryColumn = new AlterColumn();
alterHistoryColumn.setTableName(historyTable(alter.getTableName()));
alterHistoryColumn.setColumnName(alter.getColumnName());
// ignore default value (not needed on history tables)
alterHistoryColumn.setCurrentType(alter.getCurrentType());
alterHistoryColumn.setType(alter.getType());
if (syncExact) {
alterHistoryColumn.setCurrentNotnull(alter.isCurrentNotnull());
alterHistoryColumn.setNotnull(alter.isNotnull());
} else if (isNull) {
// do transition from notNull to null
alterHistoryColumn.setCurrentNotnull(Boolean.TRUE);
alterHistoryColumn.setNotnull(Boolean.FALSE);
} else {
// assume that the column contains null values from the past (required for platforms like mysql/sqlserver/hana)
alterHistoryColumn.setCurrentNotnull(Boolean.FALSE);
}
platformDdl.alterColumn(writer, alterHistoryColumn);
}
}
}
}
protected void alterColumnDefaultValue(DdlWrite writer, AlterColumn alter) throws IOException {
writer.apply().appendStatement(platformDdl.alterColumnDefaultValue(alter.getTableName(), alter.getColumnName(), alter.getDefaultValue()));
protected void dropCheckConstraint(DdlWrite writer, AlterColumn alter, String constraintName) {
writer.applyDropDependencies()
.appendStatement(platformDdl.alterTableDropConstraint(alter.getTableName(), constraintName));
}
protected void dropCheckConstraint(DdlWrite writer, AlterColumn alter, String constraintName) throws IOException {
writer.apply().appendStatement(platformDdl.alterTableDropConstraint(alter.getTableName(), constraintName));
protected void addCheckConstraint(DdlWrite writer, AlterColumn alter) {
writer.applyPostAlter()
.appendStatement(platformDdl.alterTableAddCheckConstraint(alter.getTableName(), alter.getCheckConstraintName(), alter.getCheckConstraint()));
}
protected void addCheckConstraint(DdlWrite writer, AlterColumn alter) throws IOException {
writer.apply().appendStatement(platformDdl.alterTableAddCheckConstraint(alter.getTableName(), alter.getCheckConstraintName(), alter.getCheckConstraint()));
protected void alterColumnAddForeignKey(DdlWrite writer, AlterColumn alterColumn) {
alterTableAddForeignKey(writer.getOptions(), writer.applyForeignKeys(), new WriteForeignKey(alterColumn));
}
protected void alterColumnNotnull(DdlWrite writer, AlterColumn alter) throws IOException {
writer.apply().appendStatement(platformDdl.alterColumnNotnull(alter.getTableName(), alter.getColumnName(), alter.isNotnull()));
protected void alterColumnDropForeignKey(DdlWrite writer, AlterColumn alter) {
writer.applyDropDependencies()
.appendStatement(platformDdl.alterTableDropForeignKey(alter.getTableName(), alter.getDropForeignKey()));
}
protected void alterColumnType(DdlWrite writer, AlterColumn alter) throws IOException {
String ddl = platformDdl.alterColumnType(alter.getTableName(), alter.getColumnName(), alter.getType());
if (hasValue(ddl)) {
writer.apply().appendStatement(ddl);
if (isTrue(alter.isWithHistory()) && historySupport == HistorySupport.TRIGGER_BASED) {
regenerateHistoryTriggers(alter.getTableName(), HistoryTableUpdate.Change.ALTER, alter.getColumnName());
// apply same type change to matching column in the history table
ddl = platformDdl.alterColumnType(historyTable(alter.getTableName()), alter.getColumnName(), alter.getType());
writer.apply().appendStatement(ddl);
}
}
protected void alterColumnDropUniqueConstraint(DdlWrite writer, AlterColumn alter) {
writer.applyDropDependencies()
.appendStatement(platformDdl.alterTableDropUniqueConstraint(alter.getTableName(), alter.getDropUnique()));
}
protected void alterColumnAddForeignKey(DdlWrite writer, AlterColumn alterColumn) throws IOException {
alterTableAddForeignKey(writer.getOptions(), writer.apply(), new WriteForeignKey(alterColumn));
}
protected void alterColumnDropForeignKey(DdlWrite writer, AlterColumn alter) throws IOException {
writer.apply().appendStatement(platformDdl.alterTableDropForeignKey(alter.getTableName(), alter.getDropForeignKey()));
}
protected void alterColumnDropUniqueConstraint(DdlWrite writer, AlterColumn alter) throws IOException {
writer.apply().appendStatement(platformDdl.alterTableDropUniqueConstraint(alter.getTableName(), alter.getDropUnique()));
}
protected void alterColumnAddUniqueOneToOneConstraint(DdlWrite writer, AlterColumn alter) throws IOException {
protected void alterColumnAddUniqueOneToOneConstraint(DdlWrite writer, AlterColumn alter) {
addUniqueConstraint(writer, alter, alter.getUniqueOneToOne());
}
protected void alterColumnAddUniqueConstraint(DdlWrite writer, AlterColumn alter) throws IOException {
protected void alterColumnAddUniqueConstraint(DdlWrite writer, AlterColumn alter) {
addUniqueConstraint(writer, alter, alter.getUnique());
}
protected void addUniqueConstraint(DdlWrite writer, AlterColumn alter, String uqName) throws IOException {
protected void addUniqueConstraint(DdlWrite writer, AlterColumn alter, String uqName) {
String[] cols = {alter.getColumnName()};
boolean notNull = alter.isNotnull() != null ? alter.isNotnull() : Boolean.TRUE.equals(alter.isNotnull());
writer.apply().appendStatement(platformDdl.alterTableAddUniqueConstraint(alter.getTableName(), uqName, cols, notNull ? null : cols));
writer.applyPostAlter()
.appendStatement(platformDdl.alterTableAddUniqueConstraint(alter.getTableName(), uqName, cols, notNull ? null : cols));
writer.dropAllForeignKeys().appendStatement(platformDdl.dropIndex(uqName, alter.getTableName()));
}
protected void alterTableDropColumn(DdlBuffer buffer, String tableName, String columnName) throws IOException {
platformDdl.alterTableDropColumn(buffer, tableName, columnName);
protected void alterTableDropColumn(DdlWrite writer, String tableName, String columnName) {
platformDdl.alterTableDropColumn(writer, tableName, columnName);
}
protected void alterTableAddColumn(DdlBuffer buffer, String tableName, Column column, boolean onHistoryTable, boolean withHistory) throws IOException {
protected void alterTableAddColumn(DdlWrite writer, String tableName, Column column, boolean onHistoryTable, boolean withHistory) {
DdlMigrationHelp help = new DdlMigrationHelp(tableName, column, withHistory);
if (!onHistoryTable) {
help.writeBefore(buffer);
help.write(writer);
}
platformDdl.alterTableAddColumn(buffer, tableName, column, onHistoryTable, help.getDefaultValue());
platformDdl.alterTableAddColumn(writer, tableName, column, onHistoryTable, help.getDefaultValue());
final String comment = column.getComment();
if (comment != null && !comment.isEmpty()) {
platformDdl.addColumnComment(buffer, tableName, column.getName(), comment);
platformDdl.addColumnComment(writer.applyPostAlter(), tableName, column.getName(), comment);
}
if (!onHistoryTable) {
help.writeAfter(buffer);
}
}
protected boolean isFalse(Boolean value) {
@@ -15,6 +15,7 @@ class ClickHouseDbArray {
mapping.put("integer[]", "Array(UInt32)");
mapping.put("bigint[]", "Array(UInt64)");
mapping.put("float[]", "Array(Float32)");
mapping.put("decimal[]", "Array(Decimal)");
}
/**
@@ -6,8 +6,6 @@ import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlHandler;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlOptions;
import java.io.IOException;
public class ClickHouseDdl extends PlatformDdl {
private static final String LOG_TABLE = "ENGINE = Log()";
@@ -16,6 +14,7 @@ public class ClickHouseDdl extends PlatformDdl {
super(platform);
this.includeStorageEngine = true;
this.identitySuffix = "";
this.columnNotNull = null;
}
@Override
@@ -32,7 +31,7 @@ public class ClickHouseDdl extends PlatformDdl {
* Add an table storage engine to the create table statement.
*/
@Override
public void tableStorageEngine(DdlBuffer apply, String storageEngine) throws IOException {
public void tableStorageEngine(DdlBuffer apply, String storageEngine) {
if (storageEngine == null) {
// default to Log() table but really should all be explicit (need arguments for MergeTree etc)
storageEngine = LOG_TABLE;
@@ -70,11 +69,6 @@ public class ClickHouseDdl extends PlatformDdl {
return null;
}
@Override
protected void writeColumnNotNull(DdlBuffer buffer) {
// do nothing
}
@Override
public void addTableComment(DdlBuffer apply, String tableName, String tableComment) {
// do nothing
@@ -21,21 +21,9 @@ public class CockroachDdl extends PlatformDdl {
return NativeDbArray.logicalToNative(logicalArrayType);
}
/**
* Map bigint, integer and smallint all into serial.
*/
@Override
public String asIdentityColumn(String columnDefn, DdlIdentity identity) {
if ("bigint".equalsIgnoreCase(columnDefn)) {
return "serial";
}
if ("integer".equalsIgnoreCase(columnDefn)) {
return "serial";
}
if ("smallint".equalsIgnoreCase(columnDefn)) {
return "serial";
}
return columnDefn;
return asIdentityStandardOptions(columnDefn, identity);
}
@Override
@@ -48,6 +36,12 @@ public class CockroachDdl extends PlatformDdl {
// do nothing
}
@Override
public String alterTableDropUniqueConstraint(String tableName, String uniqueConstraintName) {
// workaround for: https://github.com/cockroachdb/cockroach/issues/42840
return "drop index " + maxConstraintName(uniqueConstraintName) + " cascade";
}
@Override
public boolean isInlineComments() {
return false;
@@ -1,7 +1,14 @@
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
import io.ebean.annotation.ConstraintMode;
import java.util.ArrayList;
import java.util.List;
import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebean.util.StringHelper;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlAlterTable;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite;
import io.ebeaninternal.dbmigration.migration.Column;
/**
* DB2 platform specific DDL.
@@ -12,12 +19,13 @@ public class DB2Ddl extends PlatformDdl {
super(platform);
this.dropTableIfExists = "drop table ";
this.dropSequenceIfExists = "drop sequence ";
this.dropConstraintIfExists = "drop constraint";
this.dropIndexIfExists = "drop index ";
this.dropConstraintIfExists = "NOT USED";
this.dropIndexIfExists = "NOT USED";
this.identitySuffix = " generated by default as identity";
this.columnSetNull = "drop not null";
this.columnSetType = "set data type ";
this.inlineUniqueWhenNullable = false;
this.historyDdl = new Db2HistoryDdl();
}
@Override
@@ -30,7 +38,7 @@ public class DB2Ddl extends PlatformDdl {
throw new NullPointerException();
}
StringBuilder sb = new StringBuilder("create unique index ");
sb.append(uqName).append(" on ").append(tableName).append('(');
sb.append(maxConstraintName(uqName)).append(" on ").append(tableName).append('(');
for (int i = 0; i < columns.length; i++) {
if (i > 0) {
@@ -43,8 +51,143 @@ public class DB2Ddl extends PlatformDdl {
}
@Override
protected void appendForeignKeyOnUpdate(StringBuilder buffer, ConstraintMode mode) {
// do nothing, no on update clause for db2
public void alterTableAddColumn(DdlWrite writer, String tableName, Column column, boolean onHistoryTable, String defaultValue) {
String convertedType = convert(column.getType());
DdlBuffer buffer = alterTable(writer, tableName).append(addColumn, column.getName());
buffer.append(convertedType);
// Add default value also to history table if it is not excluded
if (defaultValue != null) {
buffer.append(" default ");
buffer.append(defaultValue);
}
if (isTrue(column.isNotnull())) {
buffer.appendWithSpace(columnNotNull);
}
// DB2 History table must match exact!
if (!onHistoryTable) {
// check constraints cannot be added in one statement for h2
if (!StringHelper.isNull(column.getCheckConstraint())) {
String ddl = alterTableAddCheckConstraint(tableName, column.getCheckConstraintName(), column.getCheckConstraint());
writer.applyPostAlter().appendStatement(ddl);
}
}
}
@Override
public String alterTableDropForeignKey(String tableName, String fkName) {
return alterTableDropConstraint(tableName, fkName);
};
@Override
public String alterTableDropUniqueConstraint(String tableName, String uniqueConstraintName) {
return alterTableDropConstraint(tableName, uniqueConstraintName)
+ "\n" + dropIndex(uniqueConstraintName, tableName);
}
@Override
public String alterTableDropConstraint(String tableName, String constraintName) {
StringBuilder sb = new StringBuilder(300);
sb.append("delimiter $$\n")
.append("begin\n")
.append("if exists (select constname from syscat.tabconst where tabschema = current_schema and constname = '")
.append(maxConstraintName(constraintName).toUpperCase())
.append("' and tabname = '").append(lowerTableName(tableName).toUpperCase()).append("') then\n")
.append(" prepare stmt from 'alter table ").append(lowerTableName(tableName))
.append(" drop constraint ").append(maxConstraintName(constraintName)).append("';\n")
.append(" execute stmt;\n")
.append("end if;\n")
.append("end$$");
return sb.toString();
}
@Override
public String dropIndex(String indexName, String tableName, boolean concurrent) {
StringBuilder sb = new StringBuilder(300);
sb.append("delimiter $$\n")
.append("begin\n")
.append("if exists (select indname from syscat.indexes where indschema = current_schema and indname = '")
.append(maxConstraintName(indexName).toUpperCase()).append("') then\n")
.append(" prepare stmt from 'drop index ").append(maxConstraintName(indexName)).append("';\n")
.append(" execute stmt;\n")
.append("end if;\n")
.append("end$$");
return sb.toString();
}
@Override
public String dropSequence(String sequenceName) {
StringBuilder sb = new StringBuilder(300);
sb.append("delimiter $$\n");
sb.append("begin\n");
sb.append("if exists (select seqschema from syscat.sequences where seqschema = current_schema and seqname = '")
.append(maxConstraintName(sequenceName).toUpperCase()).append("') then\n");
sb.append(" prepare stmt from 'drop sequence ").append(maxConstraintName(sequenceName)).append("';\n");
sb.append(" execute stmt;\n");
sb.append("end if;\n");
sb.append("end$$");
return sb.toString();
}
@Override
protected DdlAlterTable alterTable(DdlWrite writer, String tableName) {
return writer.applyAlterTable(tableName, Db2AlterTableWrite::new);
};
static class Db2AlterTableWrite extends BaseAlterTableWrite {
public Db2AlterTableWrite(String tableName) {
super(tableName);
}
@Override
protected List<AlterCmd> postProcessCommands(List<AlterCmd> cmds) {
List<AlterCmd> ret = new ArrayList<>(cmds.size() + 1);
boolean requiresReorg = false;
for (AlterCmd cmd : cmds) {
ret.add(cmd);
if (!requiresReorg && checkReorg(cmd)) {
requiresReorg = true;
}
}
if (requiresReorg) {
ret.add(newRawCommand("call sysproc.admin_cmd('reorg table " + tableName() + "')"));
}
return ret;
}
/**
* determine, if we need a reorg.
*
* See: https://www.ibm.com/docs/en/db2/11.5?topic=statements-alter-table The following is the full list of REORG-recommended
* ALTER statements that cause a version change and place the table into a REORG-pending state:
* <ul>
* <li>DROP COLUMN
* <li>ALTER COLUMN SET NOT NULL
* <li>ALTER COLUMN DROP NOT NULL
* <li>ALTER COLUMN SET DATA TYPE, except in the following situations:<br>
* Increasing the length of a VARCHAR or VARGRAPHIC column<br>
* Decreasing the length of a VARCHAR or VARGRAPHIC column without truncating trailing blanks from existing data, when no indexes
* exist on the column
* </ul>
*
*/
private boolean checkReorg(AlterCmd cmd) {
switch (cmd.getOperation()) {
case "drop column":
return true;
case "alter column":
String alter = cmd.getAlternation();
return alter.equals("set not null")
|| alter.equals("drop not default")
|| alter.startsWith("set data type"); // note: altering varchar length only is not detected here
default:
return false;
}
}
}
}
@@ -0,0 +1,138 @@
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
import java.util.Collection;
import io.ebean.config.DatabaseConfig;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlAlterTable;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite;
import io.ebeaninternal.dbmigration.migration.AddHistoryTable;
import io.ebeaninternal.dbmigration.migration.DropHistoryTable;
import io.ebeaninternal.dbmigration.model.MColumn;
import io.ebeaninternal.dbmigration.model.MTable;
/**
* DB2 History support.
*
* @author Roland Praml, FOCONIS AG
*/
public class Db2HistoryDdl implements PlatformHistoryDdl {
private String systemPeriodStart;
private String systemPeriodEnd;
private String transactionId;
private PlatformDdl platformDdl;
private String historySuffix;
@Override
public void configure(DatabaseConfig config, PlatformDdl platformDdl) {
this.systemPeriodStart = config.getAsOfSysPeriod() + "_start";
this.systemPeriodEnd = config.getAsOfSysPeriod() + "_end";
this.transactionId = config.getAsOfSysPeriod() + "_txn"; // required for DB2
this.platformDdl = platformDdl;
this.historySuffix = config.getHistoryTableSuffix();
}
@Override
public void createWithHistory(DdlWrite writer, MTable table) {
String tableName = table.getName();
String historyTableName = tableName + historySuffix;
DdlBuffer apply = writer.applyPostAlter();
apply.append(platformDdl.getCreateTableCommandPrefix()).append(" ").append(historyTableName).append(" (").newLine();
// create history table
Collection<MColumn> cols = table.allColumns();
for (MColumn column : cols) {
if (!column.isDraftOnly()) {
writeColumnDefinition(apply, column.getName(), column.getType(), column.isNotnull() || column.isPrimaryKey());
apply.append(",").newLine();
}
}
writeColumnDefinition(apply, systemPeriodStart, "timestamp(12)", true);
apply.append(",").newLine();
writeColumnDefinition(apply, systemPeriodEnd, "timestamp(12)", true);
apply.append(",").newLine();
writeColumnDefinition(apply, transactionId, "timestamp(12)", false);
apply.newLine().append(")").endOfStatement();
// enable system versioning
addSysPeriodColumns(writer, tableName);
enableSystemVersioning(apply, tableName);
platformDdl.alterTable(writer, tableName).setHistoryHandled();
// drop all: We do not drop columns here, as the whole table will be dropped
disableSystemVersioning(writer.dropAll(), tableName);
writer.dropAll().append("drop table ").append(historyTableName).endOfStatement();
}
void addSysPeriodColumns(DdlWrite writer, String baseTable) {
platformDdl.alterTableAddColumn(writer, baseTable, systemPeriodStart, "timestamp(12) not null generated always as row begin", null);
platformDdl.alterTableAddColumn(writer, baseTable, systemPeriodEnd, "timestamp(12) not null generated always as row end", null);
platformDdl.alterTableAddColumn(writer, baseTable, transactionId, "timestamp(12) generated always as transaction start id", null);
platformDdl.alterTable(writer, baseTable).append("add period system_time", null)
.append("(").append(systemPeriodStart).append(",").append(systemPeriodEnd).append(")");
}
@Override
public void dropHistoryTable(DdlWrite writer, DropHistoryTable dropHistoryTable) {
dropHistoryTable(writer, dropHistoryTable.getBaseTable(), dropHistoryTable.getBaseTable() + historySuffix);
}
protected void dropHistoryTable(DdlWrite writer, String baseTable, String historyTable) {
disableSystemVersioning(writer.apply(), baseTable);
writer.apply().append("alter table ").append(baseTable).append(" drop period system_time").endOfStatement();
// drop the period & period columns
platformDdl.alterTableDropColumn(writer, baseTable, systemPeriodStart);
platformDdl.alterTableDropColumn(writer, baseTable, systemPeriodEnd);
platformDdl.alterTableDropColumn(writer, baseTable, transactionId);
// drop the history table
writer.applyPostAlter().append("drop table ").append(historyTable).endOfStatement();
}
@Override
public void addHistoryTable(DdlWrite writer, AddHistoryTable addHistoryTable) {
MTable table = writer.getTable(addHistoryTable.getBaseTable());
if (table == null) {
throw new IllegalStateException("MTable " + addHistoryTable.getBaseTable() + " not found in writer? (required for history DDL)");
}
createWithHistory(writer, table);
}
@Override
public boolean alterHistoryTables() {
return true;
}
@Override
public void updateTriggers(DdlWrite writer, String tableName) {
DdlAlterTable alter = platformDdl.alterTable(writer, tableName);
MTable table = writer.getTable(tableName);
if (table.isWithHistory() && !alter.isHistoryHandled()) {
disableSystemVersioning(writer.apply(), tableName);
enableSystemVersioning(writer.applyPostAlter(), tableName);
alter.setHistoryHandled();
}
}
protected void writeColumnDefinition(DdlBuffer buffer, String columnName, String type, boolean isNotNull) {
String platformType = platformDdl.convert(type);
buffer.append(" ").append(platformDdl.lowerColumnName(columnName));
buffer.append(" ").append(platformType);
if (isNotNull) {
buffer.append(" not null");
}
}
public void disableSystemVersioning(DdlBuffer apply, String tableName) {
apply.append("alter table ").append(tableName).append(" drop versioning").endOfStatement();
}
public void enableSystemVersioning(DdlBuffer apply, String tableName) {
apply.append("alter table ").append(tableName).append(" add versioning use history table ").append(tableName).append(historySuffix).endOfStatement();
}
}
@@ -2,6 +2,7 @@ package io.ebeaninternal.dbmigration.ddlgeneration.platform;
import io.ebean.config.DatabaseConfig;
import io.ebean.config.DbConstraintNaming;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlAlterTable;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite;
import io.ebeaninternal.dbmigration.migration.AddHistoryTable;
@@ -9,8 +10,6 @@ import io.ebeaninternal.dbmigration.migration.DropHistoryTable;
import io.ebeaninternal.dbmigration.model.MColumn;
import io.ebeaninternal.dbmigration.model.MTable;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
/**
@@ -49,51 +48,20 @@ public abstract class DbTriggerBasedHistoryDdl implements PlatformHistoryDdl {
}
@Override
public void updateTriggers(DdlWrite writer, HistoryTableUpdate update) throws IOException {
MTable table = writer.getTable(update.getBaseTable());
if (table == null) {
throw new IllegalStateException("MTable " + update.getBaseTable() + " not found in writer? (required for history DDL)");
}
updateTriggers(writer, table, update);
}
/**
* Replace the existing triggers/stored procedures/views for history table support given the included columns.
*/
protected abstract void updateHistoryTriggers(DbTriggerUpdate triggerUpdate) throws IOException;
/**
* Process the HistoryTableUpdate which can result in changes to the apply, rollback
* and drop scripts.
*/
protected void updateTriggers(DdlWrite writer, MTable table, HistoryTableUpdate update) throws IOException {
writer.applyHistoryTrigger().append("-- changes: ").append(update.description()).newLine();
updateHistoryTriggers(createDbTriggerUpdate(writer, table));
}
protected DbTriggerUpdate createDbTriggerUpdate(DdlWrite writer, MTable table) {
List<String> columns = columnNamesForApply(table);
String baseTableName = table.getName();
String historyTableName = historyTableName(baseTableName);
return new DbTriggerUpdate(baseTableName, historyTableName, writer, columns);
}
@Override
public void dropHistoryTable(DdlWrite writer, DropHistoryTable dropHistoryTable) throws IOException {
public void dropHistoryTable(DdlWrite writer, DropHistoryTable dropHistoryTable) {
String baseTable = dropHistoryTable.getBaseTable();
// drop in appropriate order
dropTriggers(writer.applyDropDependencies(), baseTable);
dropHistoryTableEtc(writer.applyDropDependencies(), baseTable);
dropWithHistoryView(writer.applyDropDependencies(), baseTable);
dropHistoryTable(writer.applyDropDependencies(), baseTable);
dropSysPeriodColumns(writer, baseTable);
}
@Override
public void addHistoryTable(DdlWrite writer, AddHistoryTable addHistoryTable) throws IOException {
public void addHistoryTable(DdlWrite writer, AddHistoryTable addHistoryTable) {
String baseTable = addHistoryTable.getBaseTable();
MTable table = writer.getTable(baseTable);
@@ -105,27 +73,55 @@ public abstract class DbTriggerBasedHistoryDdl implements PlatformHistoryDdl {
}
@Override
public void createWithHistory(DdlWrite writer, MTable table) throws IOException {
public void createWithHistory(DdlWrite writer, MTable table) {
String baseTable = table.getName();
String whenCreatedColumn = table.getWhenCreatedColumn();
addSysPeriodColumns(writer, baseTable, table.getWhenCreatedColumn());
createHistoryTable(writer.applyPostAlter(), table);
createWithHistoryView(writer.applyPostAlter(), table.getName());
createTriggers(writer.applyPostAlter(), baseTable, columnNamesForApply(table));
writer.applyPostAlter().end();
// drop all scripts
dropTriggers(writer.dropAll(), baseTable);
dropHistoryTableEtc(writer.dropAll(), baseTable);
dropWithHistoryView(writer.dropAll(), baseTable);
dropHistoryTable(writer.dropAll(), baseTable);
// no need to dropSysPeriodColumns as whole table will be deleted soon
addHistoryTable(writer, table, whenCreatedColumn);
createStoredFunction(writer, table);
createTriggers(writer, table);
}
protected abstract void createTriggers(DdlWrite writer, MTable table) throws IOException;
@Override
public void updateTriggers(DdlWrite writer, String tableName) {
MTable table = writer.getTable(tableName);
if (table != null && table.isWithHistory()) {
DdlAlterTable alter = platformDdl.alterTable(writer, tableName);
if (!alter.isHistoryHandled()) {
// this code effectively disables history support before the table alter and enables it again
// immediately after the table alter. As all alters per table are altogether now, this can done here
dropTriggers(writer.apply(), tableName);
dropWithHistoryView(writer.apply(), tableName);
// here are the alter commands
createWithHistoryView(writer.applyPostAlter(), tableName);
createTriggers(writer.applyPostAlter(), tableName, columnNamesForApply(table));
protected abstract void dropTriggers(DdlBuffer buffer, String baseTable) throws IOException;
protected void createStoredFunction(DdlWrite writer, MTable table) throws IOException {
// do nothing
alter.setHistoryHandled();
}
}
}
/**
* Will add a history trigger to the buffer. The config
*
* @param buffer
* @param table
*/
protected abstract void createTriggers(DdlBuffer buffer, String baseTable, List<String> columnNames);
protected abstract void dropTriggers(DdlBuffer buffer, String baseTable);
protected String normalise(String tableName) {
return constraintNaming.normaliseTable(tableName);
}
@@ -150,35 +146,32 @@ public abstract class DbTriggerBasedHistoryDdl implements PlatformHistoryDdl {
return normalise(baseTableName) + "_history_del";
}
protected void addHistoryTable(DdlWrite writer, MTable table, String whenCreatedColumn) throws IOException {
protected void addHistoryTable(DdlWrite writer, MTable table, String whenCreatedColumn) {
String baseTableName = table.getName();
DdlBuffer apply = writer.applyHistoryView();
addSysPeriodColumns(apply, baseTableName, whenCreatedColumn);
createHistoryTable(apply, table);
createWithHistoryView(apply, baseTableName);
addSysPeriodColumns(writer, baseTableName, whenCreatedColumn);
createHistoryTable(writer.applyPostAlter(), table);
createWithHistoryView(writer.applyPostAlter(), baseTableName);
}
protected void addSysPeriodColumns(DdlBuffer apply, String baseTableName, String whenCreatedColumn) throws IOException {
apply.append("alter table ").append(baseTableName).append(" add column ")
.append(sysPeriodStart).append(" ").append(sysPeriodType).append(" default ").append(now).endOfStatement();
apply.append("alter table ").append(baseTableName).append(" add column ")
.append(sysPeriodEnd).append(" ").append(sysPeriodType).endOfStatement();
protected void addSysPeriodColumns(DdlWrite writer, String baseTableName, String whenCreatedColumn) {
platformDdl.alterTableAddColumn(writer, baseTableName, sysPeriodStart, sysPeriodType, now);
platformDdl.alterTableAddColumn(writer, baseTableName, sysPeriodEnd, sysPeriodType, null);
if (whenCreatedColumn != null) {
apply.append("update ").append(baseTableName).append(" set ").append(sysPeriodStart).append(" = ").append(whenCreatedColumn).endOfStatement();
writer.applyPostAlter()
.append("update ").append(baseTableName).append(" set ").append(sysPeriodStart).append(" = ").append(whenCreatedColumn).endOfStatement();
}
}
protected void createHistoryTable(DdlBuffer apply, MTable table) throws IOException {
protected void createHistoryTable(DdlBuffer apply, MTable table) {
createHistoryTableAs(apply, table);
createHistoryTableWithPeriod(apply);
}
protected void createHistoryTableAs(DdlBuffer apply, MTable table) throws IOException {
protected void createHistoryTableAs(DdlBuffer apply, MTable table) {
apply.append(platformDdl.getCreateTableCommandPrefix()).append(" ").append(table.getName()).append(historySuffix).append("(").newLine();
for (MColumn column : table.allColumns()) {
if (!column.isDraftOnly()) {
@@ -188,7 +181,7 @@ public abstract class DbTriggerBasedHistoryDdl implements PlatformHistoryDdl {
}
}
protected void createHistoryTableWithPeriod(DdlBuffer apply) throws IOException {
protected void createHistoryTableWithPeriod(DdlBuffer apply) {
writeColumnDefinition(apply, sysPeriodStart, sysPeriodType);
apply.append(",").newLine();
writeColumnDefinition(apply, sysPeriodEnd, sysPeriodType);
@@ -198,7 +191,7 @@ public abstract class DbTriggerBasedHistoryDdl implements PlatformHistoryDdl {
/**
* Write the column definition to the create table statement.
*/
protected void writeColumnDefinition(DdlBuffer buffer, String columnName, String type) throws IOException {
protected void writeColumnDefinition(DdlBuffer buffer, String columnName, String type) {
String platformType = platformDdl.convert(type);
buffer.append(" ");
@@ -206,57 +199,43 @@ public abstract class DbTriggerBasedHistoryDdl implements PlatformHistoryDdl {
buffer.append(platformType);
}
protected void createWithHistoryView(DdlBuffer apply, String baseTableName) throws IOException {
protected void createWithHistoryView(DdlBuffer apply, String baseTableName) {
apply
.append("create view ").append(baseTableName).append(viewSuffix)
.append(" as select * from ").append(baseTableName)
.append(" union all select * from ").append(baseTableName).append(historySuffix)
.endOfStatement().end();
.endOfStatement();
}
/**
* For postgres/h2/mysql we need to drop and recreate the view. Well, we could add columns to the end of the view
* but otherwise we need to drop and create it.
*/
protected void recreateHistoryView(DbTriggerUpdate update) throws IOException {
DdlBuffer buffer = update.dropDependencyBuffer();
// we need to drop the view early/first before any changes to the tables etc
buffer.append("drop view if exists ").append(update.getBaseTable()).append(viewSuffix).endOfStatement();
// recreate the view after all ddl modifications - the view requires ALL columns, also the historyExclude ones.
createWithHistoryView(update.historyViewBuffer(), update.getBaseTable());
}
protected void appendSysPeriodColumns(DdlBuffer apply, String prefix) throws IOException {
protected void appendSysPeriodColumns(DdlBuffer apply, String prefix) {
appendColumnName(apply, prefix, sysPeriodStart);
appendColumnName(apply, prefix, sysPeriodEnd);
}
protected void dropHistoryTableEtc(DdlBuffer buffer, String baseTableName) throws IOException {
buffer.append("drop view ").append(baseTableName).append(viewSuffix).endOfStatement();
dropSysPeriodColumns(buffer, baseTableName);
buffer.append("drop table ").append(baseTableName).append(historySuffix).endOfStatement().end();
protected void dropWithHistoryView(DdlBuffer apply, String baseTableName) {
apply.append("drop view ").append(baseTableName).append(viewSuffix).endOfStatement();
}
protected void dropSysPeriodColumns(DdlBuffer buffer, String baseTableName) throws IOException {
platformDdl.alterTableDropColumn(buffer, baseTableName, sysPeriodStart);
platformDdl.alterTableDropColumn(buffer, baseTableName, sysPeriodEnd);
protected void dropHistoryTable(DdlBuffer apply, String baseTableName) {
apply.append("drop table ").append(baseTableName).append(historySuffix).endOfStatement().end();
}
protected void appendInsertIntoHistory(DdlBuffer buffer, String historyTable, List<String> columns) throws IOException {
protected void dropSysPeriodColumns(DdlWrite writer, String baseTableName) {
platformDdl.alterTableDropColumn(writer, baseTableName, sysPeriodStart);
platformDdl.alterTableDropColumn(writer, baseTableName, sysPeriodEnd);
}
buffer.append(" insert into ").append(historyTable).append(" (").append(sysPeriodStart).append(",").append(sysPeriodEnd).append(",");
protected void appendInsertIntoHistory(DdlBuffer buffer, String baseTable, List<String> columns) {
buffer.append(" insert into ").append(baseTable).append(historySuffix).append(" (").append(sysPeriodStart).append(",").append(sysPeriodEnd).append(",");
appendColumnNames(buffer, columns, "");
buffer.append(") values (OLD.").append(sysPeriodStart).append(", ").append(sysPeriodEndValue).append(",");
appendColumnNames(buffer, columns, "OLD.");
buffer.append(");").newLine();
}
void appendColumnNames(DdlBuffer buffer, List<String> columns, String columnPrefix) throws IOException {
void appendColumnNames(DdlBuffer buffer, List<String> columns, String columnPrefix) {
for (int i = 0; i < columns.size(); i++) {
if (i > 0) {
buffer.append(", ");
@@ -269,7 +248,7 @@ public abstract class DbTriggerBasedHistoryDdl implements PlatformHistoryDdl {
/**
* Append a single column to the buffer if it is not null.
*/
void appendColumnName(DdlBuffer buffer, String prefix, String columnName) throws IOException {
void appendColumnName(DdlBuffer buffer, String prefix, String columnName) {
if (columnName != null) {
buffer.append(prefix).append(columnName);
}
@@ -287,4 +266,8 @@ public abstract class DbTriggerBasedHistoryDdl implements PlatformHistoryDdl {
return table.allHistoryColumns(true);
}
@Override
public boolean alterHistoryTables() {
return true;
}
}
@@ -1,71 +0,0 @@
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite;
import java.util.List;
/**
* DB trigger update when a change occurs on a table with history.
*/
public class DbTriggerUpdate {
private final String baseTableName;
private final String historyTableName;
private final DdlWrite writer;
private final List<String> columns;
public DbTriggerUpdate(String baseTableName, String historyTableName, DdlWrite writer, List<String> columns) {
this.baseTableName = baseTableName;
this.historyTableName = historyTableName;
this.writer = writer;
this.columns = columns;
}
/**
* Return the appropriate buffer for the current mode.
*/
public DdlBuffer historyViewBuffer() {
return writer.applyHistoryView();
}
/**
* Return the appropriate buffer for the current mode.
*/
public DdlBuffer historyTriggerBuffer() {
return writer.applyHistoryTrigger();
}
/**
* Return the appropriate drop dependency buffer for the current mode.
*/
public DdlBuffer dropDependencyBuffer() {
return writer.applyDropDependencies();
}
/**
* Return the base table name.
*/
public String getBaseTable() {
return baseTableName;
}
/**
* Return the history table name.
*/
public String getHistoryTable() {
return historyTableName;
}
/**
* Return the included columns.
*/
public List<String> getColumns() {
return columns;
}
}
@@ -1,10 +1,8 @@
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite;
import io.ebeaninternal.dbmigration.model.MTable;
import java.util.List;
import java.io.IOException;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
/**
* H2 history support using DB triggers to maintain a history table.
@@ -20,26 +18,16 @@ public class H2HistoryDdl extends DbTriggerBasedHistoryDdl {
}
@Override
protected void dropTriggers(DdlBuffer buffer, String baseTable) throws IOException {
protected void dropTriggers(DdlBuffer buffer, String baseTable) {
buffer.append("drop trigger ").append(updateTriggerName(baseTable)).endOfStatement();
}
@Override
protected void createTriggers(DdlWrite writer, MTable table) throws IOException {
String baseTableName = table.getName();
DdlBuffer apply = writer.applyHistoryTrigger();
addCreateTrigger(apply, updateTriggerName(baseTableName), baseTableName);
protected void createTriggers(DdlBuffer buffer, String baseTable, List<String> columnNames) {
addCreateTrigger(buffer, updateTriggerName(baseTable), baseTable);
}
@Override
protected void updateHistoryTriggers(DbTriggerUpdate update) throws IOException {
recreateHistoryView(update);
DdlBuffer buffer = update.historyTriggerBuffer();
dropTriggers(buffer, update.getBaseTable());
addCreateTrigger(buffer, updateTriggerName(update.getBaseTable()), update.getBaseTable());
}
private void addCreateTrigger(DdlBuffer apply, String triggerName, String baseTable) throws IOException {
private void addCreateTrigger(DdlBuffer apply, String triggerName, String baseTable) {
// Note that this does not take into account the historyTable name (excepts _history suffix) and
// does not take into account excluded columns (all columns included in history)
apply
@@ -3,8 +3,6 @@ package io.ebeaninternal.dbmigration.ddlgeneration.platform;
import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
import java.io.IOException;
public class HanaColumnStoreDdl extends AbstractHanaDdl {
public HanaColumnStoreDdl(DatabasePlatform platform) {
@@ -31,20 +29,16 @@ public class HanaColumnStoreDdl extends AbstractHanaDdl {
@Override
public String dropIndex(String indexName, String tableName, boolean concurrent) {
DdlBuffer buffer = new BaseDdlBuffer(null);
try {
buffer.append("delimiter $$").newLine();
buffer.append("do").newLine();
buffer.append("begin").newLine();
buffer.append("declare exit handler for sql_error_code 261 begin end").endOfStatement();
buffer.append("exec '").append(dropIndexIfExists).append(maxConstraintName(indexName)).append("'")
.endOfStatement();
buffer.append("end").endOfStatement();
buffer.append("$$");
return buffer.getBuffer();
} catch (IOException e) {
throw new RuntimeException(e);
}
DdlBuffer buffer = new BaseDdlBuffer();
buffer.append("delimiter $$").newLine();
buffer.append("do").newLine();
buffer.append("begin").newLine();
buffer.append("declare exit handler for sql_error_code 261 begin end").endOfStatement();
buffer.append("exec '").append(dropIndexIfExists).append(maxConstraintName(indexName)).append("'")
.endOfStatement();
buffer.append("end").endOfStatement();
buffer.append("$$");
return buffer.getBuffer();
}
}
@@ -1,11 +0,0 @@
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
import io.ebean.config.DatabaseConfig;
import io.ebeaninternal.dbmigration.ddlgeneration.BaseDdlHandler;
public class HanaDdlHandler extends BaseDdlHandler {
public HanaDdlHandler(DatabaseConfig config, PlatformDdl platformDdl) {
super(config, platformDdl, new HanaTableDdl(config, platformDdl));
}
}
@@ -1,6 +1,7 @@
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
import io.ebean.config.DatabaseConfig;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlAlterTable;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite;
import io.ebeaninternal.dbmigration.migration.AddHistoryTable;
@@ -8,11 +9,7 @@ import io.ebeaninternal.dbmigration.migration.DropHistoryTable;
import io.ebeaninternal.dbmigration.model.MColumn;
import io.ebeaninternal.dbmigration.model.MTable;
import java.io.IOException;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
public class HanaHistoryDdl implements PlatformHistoryDdl {
@@ -20,8 +17,6 @@ public class HanaHistoryDdl implements PlatformHistoryDdl {
private String systemPeriodEnd;
private PlatformDdl platformDdl;
private String historySuffix;
private final AtomicInteger counter = new AtomicInteger(0);
private Map<String, String> createdHistoryTables = new ConcurrentHashMap<>();
@Override
public void configure(DatabaseConfig config, PlatformDdl platformDdl) {
@@ -32,13 +27,10 @@ public class HanaHistoryDdl implements PlatformHistoryDdl {
}
@Override
public void createWithHistory(DdlWrite writer, MTable table) throws IOException {
public void createWithHistory(DdlWrite writer, MTable table) {
String tableName = table.getName();
String historyTableName = tableName + historySuffix;
DdlBuffer apply = writer.applyHistoryView();
if (apply.isEmpty()) {
createdHistoryTables.clear();
}
DdlBuffer apply = writer.applyPostAlter();
apply.append(platformDdl.getCreateTableCommandPrefix()).append(" ").append(historyTableName).append(" (").newLine();
@@ -65,20 +57,19 @@ public class HanaHistoryDdl implements PlatformHistoryDdl {
apply.append("alter table ").append(tableName).append(" add period for system_time(").append(systemPeriodStart)
.append(",").append(systemPeriodEnd).append(")").endOfStatement();
enableSystemVersioning(apply, tableName, historyTableName, true, false);
createdHistoryTables.put(tableName, historyTableName);
enableSystemVersioning(apply, tableName, true);
platformDdl.alterTable(writer, tableName).setHistoryHandled();
dropHistoryTable(writer.dropAll(), tableName, historyTableName);
}
@Override
public void dropHistoryTable(DdlWrite writer, DropHistoryTable dropHistoryTable) throws IOException {
public void dropHistoryTable(DdlWrite writer, DropHistoryTable dropHistoryTable) {
dropHistoryTable(writer.applyDropDependencies(), dropHistoryTable.getBaseTable(),
dropHistoryTable.getBaseTable() + historySuffix);
}
protected void dropHistoryTable(DdlBuffer apply, String baseTable, String historyTable) throws IOException {
protected void dropHistoryTable(DdlBuffer apply, String baseTable, String historyTable) {
// disable system versioning
disableSystemVersioning(apply, baseTable);
@@ -93,7 +84,7 @@ public class HanaHistoryDdl implements PlatformHistoryDdl {
}
@Override
public void addHistoryTable(DdlWrite writer, AddHistoryTable addHistoryTable) throws IOException {
public void addHistoryTable(DdlWrite writer, AddHistoryTable addHistoryTable) {
MTable table = writer.getTable(addHistoryTable.getBaseTable());
if (table == null) {
throw new IllegalStateException("MTable " + addHistoryTable.getBaseTable() + " not found in writer? (required for history DDL)");
@@ -102,12 +93,23 @@ public class HanaHistoryDdl implements PlatformHistoryDdl {
}
@Override
public void updateTriggers(DdlWrite write, HistoryTableUpdate baseTable) {
// nothing to do
public boolean alterHistoryTables() {
return true;
}
@Override
public void updateTriggers(DdlWrite writer, String tableName) {
DdlAlterTable alter = platformDdl.alterTable(writer, tableName);
MTable table = writer.getTable(tableName);
if (table.isWithHistory() && !alter.isHistoryHandled()) {
disableSystemVersioning(writer.apply(), tableName);
enableSystemVersioning(writer.applyPostAlter(), tableName, false);
alter.setHistoryHandled();
}
}
protected void writeColumnDefinition(DdlBuffer buffer, String columnName, String type, String defaultValue,
boolean isNotNull, String generated) throws IOException {
boolean isNotNull, String generated) {
String platformType = platformDdl.convert(type);
buffer.append(" ").append(platformDdl.lowerColumnName(columnName));
@@ -123,35 +125,16 @@ public class HanaHistoryDdl implements PlatformHistoryDdl {
}
}
public void disableSystemVersioning(DdlBuffer apply, String tableName) throws IOException {
disableSystemVersioning(apply, tableName, false);
public void disableSystemVersioning(DdlBuffer apply, String tableName) {
apply.append("alter table ").append(tableName).append(" drop system versioning").endOfStatement();
}
public void disableSystemVersioning(DdlBuffer apply, String tableName, boolean uniqueStatement) throws IOException {
apply.append("alter table ").append(tableName).append(" drop system versioning");
if (uniqueStatement) {
// needed for the DB migration test to prevent the statement from being filtered
// out as a duplicate
apply.append(" /* ").append(String.valueOf(counter.getAndIncrement())).append(" */");
}
apply.endOfStatement();
}
public void enableSystemVersioning(DdlBuffer apply, String tableName, String historyTableName, boolean validated,
boolean uniqueStatement) throws IOException {
apply.append("alter table ").append(tableName).append(" add system versioning history table ").append(historyTableName);
public void enableSystemVersioning(DdlBuffer apply, String tableName, boolean validated) {
apply.append("alter table ").append(tableName).append(" add system versioning history table ").append(tableName).append(historySuffix);
if (!validated) {
apply.append(" not validated");
}
if (uniqueStatement) {
// needed for the DB migration test to prevent the statement from being filtered
// out as a duplicate
apply.append(" /* ").append(String.valueOf(counter.getAndIncrement())).append(" */");
}
apply.endOfStatement();
}
public boolean isSystemVersioningEnabled(String tableName) {
return !createdHistoryTables.containsKey(tableName);
}
}
@@ -1,131 +0,0 @@
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
import io.ebean.config.DatabaseConfig;
import io.ebean.config.PropertiesWrapper;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite;
import io.ebeaninternal.dbmigration.migration.AddColumn;
import io.ebeaninternal.dbmigration.migration.AlterColumn;
import io.ebeaninternal.dbmigration.migration.Column;
import io.ebeaninternal.dbmigration.migration.DropColumn;
import io.ebeaninternal.dbmigration.model.MTable;
import java.io.IOException;
import java.util.List;
public class HanaTableDdl extends BaseTableDdl {
private final HanaHistoryDdl historyDdl;
private final boolean generateUniqueDdl;
public HanaTableDdl(DatabaseConfig config, PlatformDdl platformDdl) {
super(config, platformDdl);
this.historyDdl = (HanaHistoryDdl) platformDdl.historyDdl;
if (config.getProperties() != null) {
PropertiesWrapper wrapper = new PropertiesWrapper("ebean", "hana", config.getProperties(), config.getClassLoadConfig());
this.generateUniqueDdl = wrapper.getBoolean("generateUniqueDdl", false);
} else {
this.generateUniqueDdl = false;
}
}
@Override
protected void alterColumnDefaultValue(DdlWrite writer, AlterColumn alter) throws IOException {
// done in alterColumnBaseAttributes
}
@Override
public void generate(DdlWrite writer, AddColumn addColumn) throws IOException {
String tableName = addColumn.getTableName();
MTable table = writer.getTable(tableName);
if (table == null) {
super.generate(writer, addColumn);
return;
}
boolean manageSystemVersioning = isTrue(table.isWithHistory()) && historyDdl.isSystemVersioningEnabled(tableName);
if (manageSystemVersioning) {
historyDdl.disableSystemVersioning(writer.apply(), table.getName(), this.generateUniqueDdl);
}
super.generate(writer, addColumn);
if (manageSystemVersioning) {
// make same changes to the history table
String historyTable = historyTable(tableName);
List<Column> columns = addColumn.getColumn();
for (Column column : columns) {
alterTableAddColumn(writer.apply(), historyTable, column, true, true);
}
historyDdl.enableSystemVersioning(writer.apply(), table.getName(), historyTable, false, this.generateUniqueDdl);
}
}
@Override
public void generate(DdlWrite writer, AlterColumn alterColumn) throws IOException {
String tableName = alterColumn.getTableName();
MTable table = writer.getTable(tableName);
if (table == null) {
super.generate(writer, alterColumn);
return;
}
boolean manageSystemVersioning = isTrue(table.isWithHistory()) && historyDdl.isSystemVersioningEnabled(tableName);
if (manageSystemVersioning) {
historyDdl.disableSystemVersioning(writer.apply(), tableName, this.generateUniqueDdl);
}
super.generate(writer, alterColumn);
if (manageSystemVersioning) {
// make same changes to the history table
String historyTable = historyTable(tableName);
if (hasValue(alterColumn.getType()) || hasValue(alterColumn.getDefaultValue()) || alterColumn.isNotnull() != null) {
AlterColumn alterHistoryColumn = new AlterColumn();
alterHistoryColumn.setTableName(historyTable);
alterHistoryColumn.setColumnName(alterColumn.getColumnName());
alterHistoryColumn.setType(alterColumn.getType());
alterHistoryColumn.setDefaultValue(alterColumn.getDefaultValue());
alterHistoryColumn.setNotnull(alterColumn.isNotnull());
alterHistoryColumn.setCurrentType(alterColumn.getCurrentType());
alterHistoryColumn.setCurrentDefaultValue(alterColumn.getCurrentDefaultValue());
alterHistoryColumn.setCurrentNotnull(alterColumn.isCurrentNotnull());
String histColumnDdl = platformDdl.alterColumnBaseAttributes(alterHistoryColumn);
// write the apply to history table
writer.apply().append(histColumnDdl).endOfStatement();
}
historyDdl.enableSystemVersioning(writer.apply(), tableName, historyTable, false, this.generateUniqueDdl);
}
}
@Override
public void generate(DdlWrite writer, DropColumn dropColumn) throws IOException {
String tableName = dropColumn.getTableName();
MTable table = writer.getTable(tableName);
if (table == null) {
super.generate(writer, dropColumn);
return;
}
boolean manageSystemVersioning = isTrue(table.isWithHistory()) && historyDdl.isSystemVersioningEnabled(tableName);
if (manageSystemVersioning) {
historyDdl.disableSystemVersioning(writer.apply(), tableName, this.generateUniqueDdl);
}
super.generate(writer, dropColumn);
if (manageSystemVersioning) {
// also drop from the history table
String historyTable = historyTable(tableName);
alterTableDropColumn(writer.apply(), historyTable, dropColumn.getColumnName());
historyDdl.enableSystemVersioning(writer.apply(), tableName, historyTable, false, this.generateUniqueDdl);
}
}
}
@@ -1,79 +0,0 @@
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
import java.util.ArrayList;
import java.util.List;
/**
* Bean holding comments relating to a history table that needs to have it's
* associated triggers/function updated due to columns added/dropped/included
* or excluded.
*/
public class HistoryTableUpdate {
/**
* Column change type.
*/
public enum Change {
ADD,
DROP,
INCLUDE,
EXCLUDE,
ALTER
}
private static class Column {
final Change change;
final String column;
public Column(Change change, String column) {
this.change = change;
this.column = column;
}
@Override
public String toString() {
return description();
}
public String description() {
return change.name().toLowerCase() + " " + column;
}
}
private final String baseTable;
private final List<Column> columnChanges = new ArrayList<>();
/**
* Construct with a given base table name.
*/
public HistoryTableUpdate(String baseTable) {
this.baseTable = baseTable;
}
/**
* Return a description of the changes that cause the history trigger/function
* to be regenerated (added, included, excluded and dropped columns).
*/
public String description() {
return columnChanges.toString();
}
/**
* Add a comment for column added, dropped, included or excluded.
*/
public void add(Change change, String column) {
columnChanges.add(new Column(change, column));
}
/**
* Return the base table name.
*/
public String getBaseTable() {
return baseTable;
}
}
@@ -1,53 +1,59 @@
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
import io.ebean.config.DatabaseConfig;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlAlterTable;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite;
import io.ebeaninternal.dbmigration.migration.AddHistoryTable;
import io.ebeaninternal.dbmigration.migration.DropHistoryTable;
import io.ebeaninternal.dbmigration.model.MTable;
import java.io.IOException;
/**
* History DDL for MariaDB.
*/
public class MariaDbHistoryDdl implements PlatformHistoryDdl {
private PlatformDdl platformDdl;
@Override
public void configure(DatabaseConfig config, PlatformDdl platformDdl) {
// do nothing
this.platformDdl = platformDdl;
}
@Override
public void createWithHistory(DdlWrite writer, MTable table) throws IOException {
public void createWithHistory(DdlWrite writer, MTable table) {
String baseTable = table.getName();
enableSystemVersioning(writer, baseTable);
}
private void enableSystemVersioning(DdlWrite writer, String baseTable) throws IOException {
DdlBuffer apply = writer.applyHistoryView();
apply.append("alter table ").append(baseTable).append(" add system versioning").endOfStatement();
private void enableSystemVersioning(DdlWrite writer, String baseTable) {
platformDdl.alterTable(writer, baseTable).append("add system versioning", null);
DdlBuffer drop = writer.dropAll();
drop.append("alter table ").append(baseTable).append(" drop system versioning").endOfStatement();
}
@Override
public void dropHistoryTable(DdlWrite writer, DropHistoryTable dropHistoryTable) throws IOException {
public void dropHistoryTable(DdlWrite writer, DropHistoryTable dropHistoryTable) {
String baseTable = dropHistoryTable.getBaseTable();
DdlBuffer apply = writer.applyHistoryView();
apply.append("alter table ").append(baseTable).append(" drop system versioning").endOfStatement();
platformDdl.alterTable(writer, baseTable).append("drop system versioning", null);
}
@Override
public void addHistoryTable(DdlWrite writer, AddHistoryTable addHistoryTable) throws IOException {
public void addHistoryTable(DdlWrite writer, AddHistoryTable addHistoryTable) {
String baseTable = addHistoryTable.getBaseTable();
enableSystemVersioning(writer, baseTable);
}
@Override
public void updateTriggers(DdlWrite writer, HistoryTableUpdate baseTable) {
// do nothing
public void updateTriggers(DdlWrite writer, String tableName) {
MTable table = writer.getTable(tableName);
// For MariaDB we need to enable system_versioning_alter_history only once
// per DDL script. This info is stored in the virtual "__$HISTORY_FLAG__" table
DdlAlterTable history = platformDdl.alterTable(writer, "__$HISTORY_FLAG__");
if (table != null && table.isWithHistory() && !history.isHistoryHandled()) {
writer.apply().appendStatement("SET @@system_versioning_alter_history = 1");
history.setHistoryHandled();
}
}
}
@@ -3,12 +3,10 @@ package io.ebeaninternal.dbmigration.ddlgeneration.platform;
import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebean.util.StringHelper;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite;
import io.ebeaninternal.dbmigration.migration.AlterColumn;
import io.ebeaninternal.dbmigration.migration.Column;
import java.io.IOException;
import java.util.Collection;
/**
* MySql specific DDL.
*/
@@ -22,7 +20,7 @@ public class MySqlDdl extends PlatformDdl {
public MySqlDdl(DatabasePlatform platform) {
super(platform);
this.alterColumn = "modify";
this.alterColumn = "alter";
this.dropUniqueConstraint = "drop index";
this.historyDdl = new MySqlHistoryDdl();
this.inlineComments = true;
@@ -38,11 +36,11 @@ public class MySqlDdl extends PlatformDdl {
}
@Override
public void alterTableDropColumn(final DdlBuffer buffer, final String tableName, final String columnName) throws IOException {
public void alterTableDropColumn(DdlWrite writer, String tableName, String columnName) {
if (this.useMigrationStoredProcedures) {
buffer.append("CALL usp_ebean_drop_column('").append(tableName).append("', '").append(columnName).append("')").endOfStatement();
alterTable(writer, tableName).raw("CALL usp_ebean_drop_column('").append(tableName).append("', '").append(columnName).append("')");
} else {
super.alterTableDropColumn(buffer, tableName, columnName);
super.alterTableDropColumn(writer, tableName, columnName);
}
}
@@ -92,42 +90,35 @@ public class MySqlDdl extends PlatformDdl {
}
@Override
public String alterColumnType(String tableName, String columnName, String type) {
// can't alter itself - done in alterColumnBaseAttributes()
return null;
}
@Override
public String alterColumnNotnull(String tableName, String columnName, boolean notnull) {
// can't alter itself - done in alterColumnBaseAttributes()
return null;
}
@Override
public String alterColumnDefaultValue(String tableName, String columnName, String defaultValue) {
String suffix = DdlHelp.isDropDefault(defaultValue) ? columnDropDefault : columnSetDefault + " " + convertDefaultValue(defaultValue);
return "alter table " + tableName + " alter " + columnName + " " + suffix;
}
@Override
public String alterColumnBaseAttributes(AlterColumn alter) {
if (alter.getType() == null && alter.isNotnull() == null) {
// No type change or notNull change
// defaultValue change already handled in alterColumnDefaultValue
return null;
}
public void alterColumn(DdlWrite writer, AlterColumn alter) {
String tableName = alter.getTableName();
String columnName = alter.getColumnName();
String type = alter.getType() != null ? alter.getType() : alter.getCurrentType();
type = convert(type);
boolean notnull = (alter.isNotnull() != null) ? alter.isNotnull() : Boolean.TRUE.equals(alter.isCurrentNotnull());
String notnullClause = notnull ? " not null" : "";
return "alter table " + tableName + " modify " + columnName + " " + type + notnullClause;
if (alter.getType() == null && alter.isNotnull() == null) {
// No type change or notNull change -> handle default value change
if (hasValue(alter.getDefaultValue())) {
alterColumnDefault(writer, alter);
}
} else {
// we must regenerate whole statement -> read altered and current value
String type = alter.getType() != null ? alter.getType() : alter.getCurrentType();
type = convert(type);
boolean notnull = (alter.isNotnull() != null) ? alter.isNotnull() : Boolean.TRUE.equals(alter.isCurrentNotnull());
String defaultValue = alter.getDefaultValue() != null ? alter.getDefaultValue() : alter.getCurrentDefaultValue();
DdlBuffer buffer = alterTable(writer, tableName).append("modify", columnName);
buffer.append(type);
if (notnull) {
buffer.append(" not null");
}
if (hasValue(defaultValue) && !DdlHelp.isDropDefault(defaultValue)) {
buffer.append(" default ").append(convertDefaultValue(defaultValue));
}
}
}
@Override
protected void writeColumnDefinition(DdlBuffer buffer, Column column, DdlIdentity identity) throws IOException {
protected void writeColumnDefinition(DdlBuffer buffer, Column column, DdlIdentity identity) {
super.writeColumnDefinition(buffer, column, identity);
String comment = column.getComment();
if (!StringHelper.isNull(comment)) {
@@ -140,7 +131,7 @@ public class MySqlDdl extends PlatformDdl {
}
@Override
public void inlineTableComment(DdlBuffer apply, String tableComment) throws IOException {
public void inlineTableComment(DdlBuffer apply, String tableComment) {
if (tableComment.length() > 1000) {
tableComment = tableComment.substring(0, 1000);
}
@@ -151,7 +142,7 @@ public class MySqlDdl extends PlatformDdl {
* Add table comment as a separate statement (from the create table statement).
*/
@Override
public void addTableComment(DdlBuffer apply, String tableName, String tableComment) throws IOException {
public void addTableComment(DdlBuffer apply, String tableName, String tableComment) {
if (DdlHelp.isDropComment(tableComment)) {
tableComment = "";
}
@@ -163,32 +154,4 @@ public class MySqlDdl extends PlatformDdl {
// alter comment currently not supported as it requires to repeat whole column definition
}
/**
* Locks all tables for triggers that have to be updated.
*/
@Override
public void lockTables(DdlBuffer buffer, Collection<String> tables) throws IOException {
if (!tables.isEmpty()) {
buffer.append("lock tables ");
int i = 0;
for (String table : tables) {
if (i > 0) {
buffer.append(", ");
}
buffer.append(table).append(" write");
i++;
}
buffer.endOfStatement();
}
}
/**
* Unlocks all tables for triggers that have to be updated.
*/
@Override
public void unlockTables(DdlBuffer buffer, Collection<String> tables) throws IOException {
buffer.append("unlock tables").endOfStatement();
}
}
@@ -1,10 +1,8 @@
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite;
import io.ebeaninternal.dbmigration.model.MTable;
import java.util.List;
import java.io.IOException;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
/**
* MySql history support using DB triggers to maintain a history table.
@@ -15,54 +13,41 @@ public class MySqlHistoryDdl extends DbTriggerBasedHistoryDdl {
}
@Override
protected void dropTriggers(DdlBuffer buffer, String baseTable) throws IOException {
protected void dropTriggers(DdlBuffer buffer, String baseTable) {
buffer.append("drop trigger ").append(updateTriggerName(baseTable)).endOfStatement();
buffer.append("drop trigger ").append(deleteTriggerName(baseTable)).endOfStatement();
}
@Override
protected void createTriggers(DdlWrite writer, MTable table) throws IOException {
DbTriggerUpdate update = createDbTriggerUpdate(writer, table);
addBeforeUpdate(updateTriggerName(update.getBaseTable()), update);
addBeforeDelete(deleteTriggerName(update.getBaseTable()), update);
}
@Override
protected void updateHistoryTriggers(DbTriggerUpdate update) throws IOException {
protected void createTriggers(DdlBuffer buffer, String baseTable, List<String> columnNames) {
recreateHistoryView(update);
buffer.append("lock tables ").append(baseTable).append(" write").endOfStatement();
addBeforeUpdate(buffer, updateTriggerName(baseTable), baseTable, columnNames);
addBeforeDelete(buffer, deleteTriggerName(baseTable), baseTable, columnNames);
buffer.appendStatement("unlock tables");
DdlBuffer buffer = update.historyTriggerBuffer();
String baseTable = update.getBaseTable();
dropTriggers(buffer, baseTable);
addBeforeUpdate(updateTriggerName(baseTable), update);
addBeforeDelete(deleteTriggerName(baseTable), update);
}
private void addBeforeUpdate(String triggerName, DbTriggerUpdate update) throws IOException {
private void addBeforeUpdate(DdlBuffer apply, String triggerName, String tableName, List<String> columnNames) {
DdlBuffer apply = update.historyTriggerBuffer();
apply
.append("delimiter $$").newLine()
.append("create trigger ").append(triggerName).append(" before update on ").append(update.getBaseTable())
.append("create trigger ").append(triggerName).append(" before update on ").append(tableName)
.append(" for each row begin").newLine();
appendInsertIntoHistory(apply, update.getHistoryTable(), update.getColumns());
appendInsertIntoHistory(apply, tableName, columnNames);
apply
.append(" set NEW.").append(sysPeriod).append("_start = now(6)").endOfStatement()
.append("end$$").newLine();
}
private void addBeforeDelete(String triggerName, DbTriggerUpdate update) throws IOException {
private void addBeforeDelete(DdlBuffer apply, String triggerName, String tableName, List<String> columnNames) {
DdlBuffer apply = update.historyTriggerBuffer();
apply
.append("delimiter $$").newLine()
.append("create trigger ").append(triggerName).append(" before delete on ").append(update.getBaseTable())
.append("create trigger ").append(triggerName).append(" before delete on ").append(tableName)
.append(" for each row begin").newLine();
appendInsertIntoHistory(apply, update.getHistoryTable(), update.getColumns());
appendInsertIntoHistory(apply, tableName, columnNames);
apply.append("end$$").newLine();
}
@@ -6,8 +6,6 @@ import io.ebeaninternal.dbmigration.migration.AddHistoryTable;
import io.ebeaninternal.dbmigration.migration.DropHistoryTable;
import io.ebeaninternal.dbmigration.model.MTable;
import java.io.IOException;
/**
* Default history implementation that does nothing. Needs to be replaced
* with an appropriate implementation for the given database platform.
@@ -20,7 +18,7 @@ public class NoHistorySupportDdl implements PlatformHistoryDdl {
}
@Override
public void createWithHistory(DdlWrite writer, MTable table) throws IOException {
public void createWithHistory(DdlWrite writer, MTable table) {
// does nothing
}
@@ -30,12 +28,8 @@ public class NoHistorySupportDdl implements PlatformHistoryDdl {
}
@Override
public void addHistoryTable(DdlWrite writer, AddHistoryTable addHistoryTable) throws IOException {
public void addHistoryTable(DdlWrite writer, AddHistoryTable addHistoryTable) {
// does nothing
}
@Override
public void updateTriggers(DdlWrite write, HistoryTableUpdate update) {
// does nothing
}
}
@@ -1,10 +1,9 @@
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite;
import io.ebeaninternal.dbmigration.model.MTable;
import java.io.IOException;
import java.util.List;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
/**
* NuoDB history support using DB triggers to maintain a history table.
@@ -17,59 +16,43 @@ public class NuoDbHistoryDdl extends DbTriggerBasedHistoryDdl {
}
@Override
protected void dropTriggers(DdlBuffer buffer, String baseTable) throws IOException {
protected void dropTriggers(DdlBuffer buffer, String baseTable) {
buffer.append("drop trigger ").append(updateTriggerName(baseTable)).endOfStatement();
buffer.append("drop trigger ").append(deleteTriggerName(baseTable)).endOfStatement();
}
@Override
protected void createTriggers(DdlWrite writer, MTable table) throws IOException {
protected void createTriggers(DdlBuffer buffer, String baseTable, List<String> columnNames) {
DbTriggerUpdate update = createDbTriggerUpdate(writer, table);
addBeforeUpdate(updateTriggerName(update.getBaseTable()), update);
addBeforeDelete(deleteTriggerName(update.getBaseTable()), update);
addBeforeUpdate(buffer, updateTriggerName(baseTable), baseTable, columnNames);
addBeforeDelete(buffer, deleteTriggerName(baseTable), baseTable, columnNames);
}
@Override
protected void updateHistoryTriggers(DbTriggerUpdate update) throws IOException {
private void addBeforeUpdate(DdlBuffer apply, String triggerName, String tableName, List<String> columnNames) {
recreateHistoryView(update);
addTriggerStart(triggerName, tableName, apply, " before update for each row as ");
DdlBuffer buffer = update.historyTriggerBuffer();
String baseTable = update.getBaseTable();
dropTriggers(buffer, baseTable);
addBeforeUpdate(updateTriggerName(baseTable), update);
addBeforeDelete(deleteTriggerName(baseTable), update);
}
private void addBeforeUpdate(String triggerName, DbTriggerUpdate update) throws IOException {
DdlBuffer apply = update.historyTriggerBuffer();
addTriggerStart(triggerName, update, apply, " before update for each row as ");
apply.append(" NEW.sys_period_start = greatest(current_timestamp, date_add(OLD.sys_period_start, interval 1 microsecond))").endOfStatement();
appendInsertIntoHistory(apply, update.getHistoryTable(), update.getColumns());
appendInsertIntoHistory(apply, tableName, columnNames);
addEndTrigger(apply);
}
private void addBeforeDelete(String triggerName, DbTriggerUpdate update) throws IOException {
private void addBeforeDelete(DdlBuffer apply, String triggerName, String tableName, List<String> columnNames) {
DdlBuffer apply = update.historyTriggerBuffer();
addTriggerStart(triggerName, update, apply, " before delete for each row as");
appendInsertIntoHistory(apply, update.getHistoryTable(), update.getColumns());
addTriggerStart(triggerName, tableName, apply, " before delete for each row as");
appendInsertIntoHistory(apply, tableName, columnNames);
addEndTrigger(apply);
}
private void addTriggerStart(String triggerName, DbTriggerUpdate update, DdlBuffer apply, String s) throws IOException {
private void addTriggerStart(String triggerName, String baseTable, DdlBuffer apply, String s) {
apply
.append("delimiter $$").newLine()
.append("create or replace trigger ").append(triggerName).append(" for ").append(update.getBaseTable())
.append("create or replace trigger ").append(triggerName).append(" for ").append(baseTable)
.append(s).newLine();
}
private void addEndTrigger(DdlBuffer apply) throws IOException {
private void addEndTrigger(DdlBuffer apply) {
apply.append("end_trigger")
.endOfStatement()
.append("$$").newLine()
@@ -20,6 +20,8 @@ public class OracleDdl extends PlatformDdl {
this.columnSetNotnull = "not null";
this.columnSetNull = "null";
this.columnSetDefault = "default";
this.columnDropDefault = "default null"; // dropping default is not supported. See:
// https://stackoverflow.com/questions/8481532/how-do-i-remove-the-default-value-from-a-column-in-oracle
this.identitySuffix = " generated by default as identity";
}
@@ -33,6 +35,21 @@ public class OracleDdl extends PlatformDdl {
}
}
@Override
public String dropSequence(String sequenceName) {
return ignoreError(-2289, super.dropSequence(sequenceName));
}
@Override
public String alterTableDropConstraint(String tableName, String constraintName) {
return ignoreError(-2443, super.alterTableDropConstraint(tableName, constraintName));
}
@Override
public String alterTableDropUniqueConstraint(String tableName, String uniqueConstraintName) {
return ignoreError(-2443, super.alterTableDropUniqueConstraint(tableName, uniqueConstraintName));
}
@Override
protected void appendForeignKeyOnUpdate(StringBuilder buffer, ConstraintMode mode) {
// do nothing, no on update clause for oracle
@@ -57,4 +74,21 @@ public class OracleDdl extends PlatformDdl {
return asIdentityStandardOptions(columnDefn, identity);
}
/**
* generates anonymous pl/sql block that catches expected error so that we can
* effectively do a 'drop if exists'
*/
private String ignoreError(int errorNr, String statement) {
StringBuilder sb = new StringBuilder();
sb.append("delimiter $$\n")
.append("declare\n")
.append(" expected_error exception;\n")
.append(" pragma exception_init(expected_error, ").append(errorNr).append(");\n")
.append("begin\n")
.append(" execute immediate '").append(statement).append("';\n")
.append("exception\n")
.append(" when expected_error then null;\n")
.append("end;\n$$");
return sb.toString();
}
}
@@ -1,6 +1,7 @@
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
import io.ebean.annotation.ConstraintMode;
import io.ebean.annotation.Platform;
import io.ebean.config.DatabaseConfig;
import io.ebean.config.DbConstraintNaming;
import io.ebean.config.dbplatform.DatabasePlatform;
@@ -8,11 +9,7 @@ import io.ebean.config.dbplatform.DbDefaultValue;
import io.ebean.config.dbplatform.DbIdentity;
import io.ebean.config.dbplatform.IdType;
import io.ebean.util.StringHelper;
import io.ebeaninternal.dbmigration.ddlgeneration.BaseDdlHandler;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlHandler;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlOptions;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite;
import io.ebeaninternal.dbmigration.ddlgeneration.*;
import io.ebeaninternal.dbmigration.ddlgeneration.platform.util.PlatformTypeConverter;
import io.ebeaninternal.dbmigration.ddlgeneration.platform.util.VowelRemover;
import io.ebeaninternal.dbmigration.migration.AddHistoryTable;
@@ -21,9 +18,8 @@ import io.ebeaninternal.dbmigration.migration.Column;
import io.ebeaninternal.dbmigration.migration.DropHistoryTable;
import io.ebeaninternal.dbmigration.model.MTable;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
/**
* Controls the DDL generation for a specific database platform.
@@ -80,16 +76,12 @@ public class PlatformDdl {
protected String alterColumn = "alter column";
protected String alterColumnSuffix = "";
protected String dropUniqueConstraint = "drop constraint";
protected String addConstraint = "add constraint";
protected String addColumn = "add column";
protected String addColumnSuffix = "";
protected String columnSetType = "";
protected String columnSetDefault = "set default";
@@ -100,14 +92,14 @@ public class PlatformDdl {
protected String columnSetNull = "set null";
protected String columnNotNull = "not null";
protected String updateNullWithDefault = "update ${table} set ${column} = ${default} where ${column} is null";
protected String createTable = "create table";
protected String dropColumn = "drop column";
protected String dropColumnSuffix = "";
protected String addForeignKeySkipCheck = "";
protected String uniqueIndex = "unique";
@@ -234,7 +226,7 @@ public class PlatformDdl {
/**
* Write all the table columns converting to platform types as necessary.
*/
public void writeTableColumns(DdlBuffer apply, List<Column> columns, DdlIdentity identity) throws IOException {
public void writeTableColumns(DdlBuffer apply, List<Column> columns, DdlIdentity identity) {
for (int i = 0; i < columns.size(); i++) {
if (i > 0) {
apply.append(",");
@@ -258,7 +250,7 @@ public class PlatformDdl {
/**
* Write the column definition to the create table statement.
*/
protected void writeColumnDefinition(DdlBuffer buffer, Column column, DdlIdentity identity) throws IOException {
protected void writeColumnDefinition(DdlBuffer buffer, Column column, DdlIdentity identity) {
String columnDefn = convert(column.getType());
if (identity.useIdentity() && isTrue(column.isPrimaryKey())) {
@@ -275,20 +267,13 @@ public class PlatformDdl {
}
}
if (isTrue(column.isNotnull()) || isTrue(column.isPrimaryKey())) {
writeColumnNotNull(buffer);
buffer.appendWithSpace(columnNotNull);
}
// add check constraints later as we really want to give them a nice name
// so that the database can potentially provide a nice SQL error
}
/**
* Allow for platform overriding (e.g. ClickHouse).
*/
protected void writeColumnNotNull(DdlBuffer buffer) throws IOException {
buffer.append(" not null");
}
/**
* Returns the check constraint.
*/
@@ -317,12 +302,32 @@ public class PlatformDdl {
if (type == null) {
return null;
}
type = extract(type);
if (type.contains("[]")) {
return convertArrayType(type);
}
return typeConverter.convert(type);
}
// if columnType is different for different platforms, use pattern
// @Column(columnDefinition = PLATFORM1;DEFINITION1;PLATFORM2;DEFINITON2;DEFINITON-DEFAULT)
// e.g. @Column(columnDefinition = "db2;blob(64M);sqlserver,h2;varchar(227);varchar(127)")
private String extract(String type) {
String[] tmp = type.split(";");
if (tmp.length % 2 == 0) {
throw new IllegalArgumentException("You need an odd number of arguments. See Issue #2559 for details");
}
for (int i = 0; i < tmp.length - 2; i += 2) {
String[] platforms = tmp[i].split(",");
for (String plat : platforms) {
if (platform.isPlatform(Platform.valueOf(plat.toUpperCase(Locale.ENGLISH)))) {
return tmp[i + 1];
}
}
}
return tmp[tmp.length - 1]; // else
}
/**
* Convert the logical array type to a db platform specific type to support the array data.
*/
@@ -337,29 +342,29 @@ public class PlatformDdl {
/**
* Add history support to this table using the platform specific mechanism.
*/
public void createWithHistory(DdlWrite writer, MTable table) throws IOException {
public void createWithHistory(DdlWrite writer, MTable table) {
historyDdl.createWithHistory(writer, table);
}
/**
* Drop history support for a given table.
*/
public void dropHistoryTable(DdlWrite writer, DropHistoryTable dropHistoryTable) throws IOException {
public void dropHistoryTable(DdlWrite writer, DropHistoryTable dropHistoryTable) {
historyDdl.dropHistoryTable(writer, dropHistoryTable);
}
/**
* Add history support to an existing table.
*/
public void addHistoryTable(DdlWrite writer, AddHistoryTable addHistoryTable) throws IOException {
public void addHistoryTable(DdlWrite writer, AddHistoryTable addHistoryTable) {
historyDdl.addHistoryTable(writer, addHistoryTable);
}
/**
* Regenerate the history triggers (or function) due to a column being added/dropped/excluded or included.
*/
public void regenerateHistoryTriggers(DdlWrite write, HistoryTableUpdate update) throws IOException {
historyDdl.updateTriggers(write, update);
public void regenerateHistoryTriggers(DdlWrite writer, String tableName) {
historyDdl.updateTriggers(writer, tableName);
}
/**
@@ -521,13 +526,11 @@ public class PlatformDdl {
return buffer.toString();
}
public void alterTableAddColumn(DdlBuffer buffer, String tableName, Column column, boolean onHistoryTable, String defaultValue) throws IOException {
public void alterTableAddColumn(DdlWrite writer, String tableName, Column column, boolean onHistoryTable, String defaultValue) {
String convertedType = convert(column.getType());
buffer.append("alter table ").append(tableName)
.append(" ").append(addColumn).append(" ").append(column.getName())
.append(" ").append(convertedType);
DdlBuffer buffer = alterTable(writer, tableName).append(addColumn, column.getName());
buffer.append(convertedType);
// Add default value also to history table if it is not excluded
if (defaultValue != null) {
@@ -539,28 +542,35 @@ public class PlatformDdl {
if (!onHistoryTable) {
if (isTrue(column.isNotnull())) {
writeColumnNotNull(buffer);
buffer.appendWithSpace(columnNotNull);
}
buffer.append(addColumnSuffix);
buffer.endOfStatement();
// check constraints cannot be added in one statement for h2
if (!StringHelper.isNull(column.getCheckConstraint())) {
String ddl = alterTableAddCheckConstraint(tableName, column.getCheckConstraintName(), column.getCheckConstraint());
if (hasValue(ddl)) {
buffer.append(ddl).endOfStatement();
}
writer.applyPostAlter().appendStatement(ddl);
}
} else {
buffer.append(addColumnSuffix);
buffer.endOfStatement();
}
}
public void alterTableDropColumn(DdlBuffer buffer, String tableName, String columnName) throws IOException {
buffer.append("alter table ").append(tableName).append(" ").append(dropColumn).append(" ").append(columnName)
.append(dropColumnSuffix).endOfStatement();
/**
* This method is used from DbTriggerBasedHistoryDdl to add the sysPeriodColumns.
*/
public void alterTableAddColumn(DdlWrite writer, String tableName, String columnName, String columnType, String defaultValue) {
String convertedType = convert(columnType);
DdlBuffer buffer = alterTable(writer, tableName).append(addColumn, columnName);
buffer.append(convertedType);
if (defaultValue != null) {
buffer.append(" default ");
buffer.append(defaultValue);
}
}
public void alterTableDropColumn(DdlWrite writer, String tableName, String columnName) {
alterTable(writer, tableName).append(dropColumn, columnName);
}
/**
@@ -575,22 +585,27 @@ public class PlatformDdl {
/**
* Alter a column type.
* <p>
* Note that that MySql and SQL Server instead use alterColumnBaseAttributes()
* Note that that MySql, SQL Server, and HANA instead use alterColumn()
* </p>
*/
public String alterColumnType(String tableName, String columnName, String type) {
return "alter table " + tableName + " " + alterColumn + " " + columnName + " " + columnSetType + convert(type) + alterColumnSuffix;
protected void alterColumnType(DdlWrite writer, AlterColumn alter) {
alterTable(writer, alter.getTableName()).append(alterColumn, alter.getColumnName())
.append(columnSetType).append(convert(alter.getType()));
}
/**
* Alter a column adding or removing the not null constraint.
* <p>
* Note that that MySql, SQL Server, and HANA instead use alterColumnBaseAttributes()
* Note that that MySql, SQL Server, and HANA instead use alterColumn()
* </p>
*/
public String alterColumnNotnull(String tableName, String columnName, boolean notnull) {
String suffix = notnull ? columnSetNotnull : columnSetNull;
return "alter table " + tableName + " " + alterColumn + " " + columnName + " " + suffix + alterColumnSuffix;
protected void alterColumnNotnull(DdlWrite writer, AlterColumn alter) {
DdlBuffer buffer = alterTable(writer, alter.getTableName()).append(alterColumn, alter.getColumnName());
if (Boolean.TRUE.equals(alter.isNotnull())) {
buffer.append(columnSetNotnull);
} else {
buffer.append(columnSetNull);
}
}
/**
@@ -602,22 +617,46 @@ public class PlatformDdl {
/**
* Alter column setting the default value.
* <p>
* Note that that MySql, SQL Server, and HANA instead use alterColumn()
* </p>
*/
public String alterColumnDefaultValue(String tableName, String columnName, String defaultValue) {
String suffix = DdlHelp.isDropDefault(defaultValue) ? columnDropDefault : columnSetDefault + " " + convertDefaultValue(defaultValue);
return "alter table " + tableName + " " + alterColumn + " " + columnName + " " + suffix + alterColumnSuffix;
protected void alterColumnDefault(DdlWrite writer, AlterColumn alter) {
DdlBuffer buffer = alterTable(writer, alter.getTableName()).append(alterColumn, alter.getColumnName());
if (DdlHelp.isDropDefault(alter.getDefaultValue())) {
buffer.append(columnDropDefault);
} else {
buffer.append(columnSetDefault).appendWithSpace(convertDefaultValue(alter.getDefaultValue()));
}
}
/**
* Alter column setting both the type and not null constraint.
* Alter column setting (type, default value and not null constraint).
* <p>
* Used by MySql, SQL Server, and HANA as these require both column attributes to be set together.
* Used by MySql, SQL Server, and HANA as these require all column attributes to
* be set together.
* </p>
*/
public String alterColumnBaseAttributes(AlterColumn alter) {
// by default do nothing, only used by mysql, sql server, and HANA as they can only
// modify the column with the full column definition
return null;
public void alterColumn(DdlWrite writer, AlterColumn alter) {
if (hasValue(alter.getType())) {
alterColumnType(writer, alter);
}
if (hasValue(alter.getDefaultValue())) {
alterColumnDefault(writer, alter);
}
if (alter.isNotnull() != null) {
alterColumnNotnull(writer, alter);
}
}
/**
* Creates or replace a new DdlAlterTable for given tableName.
*/
protected DdlAlterTable alterTable(DdlWrite writer, String tableName) {
return writer.applyAlterTable(tableName, BaseAlterTableWrite::new);
}
protected void appendColumns(String[] columns, StringBuilder buffer) {
@@ -676,21 +715,21 @@ public class PlatformDdl {
/**
* Add an inline table comment to the create table statement.
*/
public void inlineTableComment(DdlBuffer apply, String tableComment) throws IOException {
public void inlineTableComment(DdlBuffer apply, String tableComment) {
// do nothing by default (MySql only)
}
/**
* Add an table storage engine to the create table statement.
*/
public void tableStorageEngine(DdlBuffer apply, String storageEngine) throws IOException {
public void tableStorageEngine(DdlBuffer apply, String storageEngine) {
// do nothing by default
}
/**
* Add table comment as a separate statement (from the create table statement).
*/
public void addTableComment(DdlBuffer apply, String tableName, String tableComment) throws IOException {
public void addTableComment(DdlBuffer apply, String tableName, String tableComment) {
if (DdlHelp.isDropComment(tableComment)) {
tableComment = "";
}
@@ -700,7 +739,7 @@ public class PlatformDdl {
/**
* Add column comment as a separate statement.
*/
public void addColumnComment(DdlBuffer apply, String table, String column, String comment) throws IOException {
public void addColumnComment(DdlBuffer apply, String table, String column, String comment) {
if (DdlHelp.isDropComment(comment)) {
comment = "";
}
@@ -710,14 +749,14 @@ public class PlatformDdl {
/**
* Use this to generate a prolog for each script (stored procedures)
*/
public void generateProlog(DdlWrite write) throws IOException {
public void generateProlog(DdlWrite writer) {
}
/**
* Use this to generate an epilog. Will be added at the end of script
*/
public void generateEpilog(DdlWrite write) throws IOException {
public void generateEpilog(DdlWrite writer) {
}
@@ -740,20 +779,6 @@ public class PlatformDdl {
return name;
}
/**
* Mysql-specific: Locks all tables for triggers that have to be updated.
*/
public void lockTables(DdlBuffer buffer, Collection<String> tables) throws IOException {
}
/**
* Mysql-specific: Unlocks all tables for triggers that have to be updated.
*/
public void unlockTables(DdlBuffer buffer, Collection<String> tables) throws IOException {
}
/**
* Returns the database-specific "create table" command prefix. For HANA this is
* either "create column table" or "create row table", for all other databases
@@ -769,7 +794,7 @@ public class PlatformDdl {
return false;
}
public void addTablePartition(DdlBuffer apply, String partitionMode, String partitionColumn) throws IOException {
public void addTablePartition(DdlBuffer apply, String partitionMode, String partitionColumn) {
// only supported by postgres initially
}
}

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