mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
168
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ef8d9c7eb0 | ||
|
|
a464c763d0 | ||
|
|
d4d1e571d3 | ||
|
|
92e85e32a2 | ||
|
|
ff1b01e5ca | ||
|
|
327f25c568 | ||
|
|
00a1324c52 | ||
|
|
75b9df942c | ||
|
|
946b390037 | ||
|
|
3a1e1e23f5 | ||
|
|
d9ea465102 | ||
|
|
3bc7f061eb | ||
|
|
0bc07d38b2 | ||
|
|
79f6d6d0f0 | ||
|
|
782e41098d | ||
|
|
0225fddf6d | ||
|
|
be3e08018e | ||
|
|
c9204eed3f | ||
|
|
edb6a0ebe2 | ||
|
|
826b507b77 | ||
|
|
8ad8f47c6b | ||
|
|
5944777a13 | ||
|
|
05a1b0d64e | ||
|
|
4d62958645 | ||
|
|
610a8b2df6 | ||
|
|
5b8bb41598 | ||
|
|
9e16d955ae | ||
|
|
197bb0509a | ||
|
|
5536aeb829 | ||
|
|
d629fb2dbd | ||
|
|
10c01574d2 | ||
|
|
cfad20c8e1 | ||
|
|
0ea375b4fc | ||
|
|
71fce1b4c5 | ||
|
|
db60065389 | ||
|
|
d3a765a532 | ||
|
|
fd4be0ca59 | ||
|
|
267a81b792 | ||
|
|
1615beadd1 | ||
|
|
a3e5c3de72 | ||
|
|
267b1b7303 | ||
|
|
c902caed24 | ||
|
|
662666e1a4 | ||
|
|
394f245e33 | ||
|
|
89da952b15 | ||
|
|
d927b8c2c2 | ||
|
|
6867c4568c | ||
|
|
e0e572a8b4 | ||
|
|
3c7555de36 | ||
|
|
75662aac5c | ||
|
|
e4ddcbd40a | ||
|
|
a8f390c3b7 | ||
|
|
f1b196cf2e | ||
|
|
04675ea76b | ||
|
|
8e44ad71e8 | ||
|
|
febd56c9c0 | ||
|
|
0d3649853a | ||
|
|
beed67567a | ||
|
|
0fe0803374 | ||
|
|
5fd7aca3d9 | ||
|
|
348fecddf7 | ||
|
|
b333449d84 | ||
|
|
87a97c2889 | ||
|
|
790147e42d | ||
|
|
3a93abaa7f | ||
|
|
1049d951d9 | ||
|
|
c3bdac5271 | ||
|
|
9bcba0b80d | ||
|
|
1529a2f12b | ||
|
|
b41b6da40e | ||
|
|
4285cbaeb2 | ||
|
|
26fd7c5498 | ||
|
|
6ec4e4b965 | ||
|
|
e3a20a351d | ||
|
|
9b8f7be98f | ||
|
|
61f5442e3b | ||
|
|
c5acd31da4 | ||
|
|
49fde7654e | ||
|
|
05338531ed | ||
|
|
eb4d906814 | ||
|
|
2a96a59deb | ||
|
|
f571da5154 | ||
|
|
ffad9abeef | ||
|
|
e8df81d78a | ||
|
|
ed19a96801 | ||
|
|
6d27e30b88 | ||
|
|
52aa1a2d91 | ||
|
|
ddbd816f6d | ||
|
|
00940c2b31 | ||
|
|
708ec64893 | ||
|
|
d0dd2d8203 | ||
|
|
faa921ac27 | ||
|
|
f2a99c7b01 | ||
|
|
b6ea9df444 | ||
|
|
e6cde5862d | ||
|
|
dec927bf9a | ||
|
|
ae41471c74 | ||
|
|
843d9d2700 | ||
|
|
475fd38be5 | ||
|
|
b88e4a35f8 | ||
|
|
c82f3783f0 | ||
|
|
bf99f9d08d | ||
|
|
f30c3869b6 | ||
|
|
3b32e4c018 | ||
|
|
e0669e9a9f | ||
|
|
95b1488aed | ||
|
|
897a97d415 | ||
|
|
1d71f617c2 | ||
|
|
1ca5789112 | ||
|
|
70ec8a3891 | ||
|
|
2dfa9d2e77 | ||
|
|
29a5a13dd9 | ||
|
|
7a3494ebd9 | ||
|
|
915bf29eaf | ||
|
|
dad4837b50 | ||
|
|
8fa8c687e9 | ||
|
|
aff54f5cf7 | ||
|
|
fa0336a404 | ||
|
|
7ccea9ff7e | ||
|
|
c2e4f862bc | ||
|
|
36bda117a6 | ||
|
|
08838770e9 | ||
|
|
137a7950ff | ||
|
|
e3980a14a2 | ||
|
|
ca9f48d019 | ||
|
|
e83e6b0f8f | ||
|
|
7d18329c18 | ||
|
|
c6fa60f28c | ||
|
|
3ab7ebe5e6 | ||
|
|
48e875714b | ||
|
|
5ba93ed927 | ||
|
|
9974102f1a | ||
|
|
ba27e09179 | ||
|
|
90066eee0c | ||
|
|
53c8827a52 | ||
|
|
3bb6f0ca65 | ||
|
|
6e5eb6b963 | ||
|
|
7bea0d0eb2 | ||
|
|
5a07a54544 | ||
|
|
684508b7ea | ||
|
|
ab72fd97b9 | ||
|
|
8486415249 | ||
|
|
6a74b84b8c | ||
|
|
999be3e0a7 | ||
|
|
a656b55526 | ||
|
|
dabb1451e9 | ||
|
|
cde00650ca | ||
|
|
6b96bea480 | ||
|
|
a731bfdfaf | ||
|
|
0ee153d6bc | ||
|
|
cb89b903fd | ||
|
|
a93e2e05c5 | ||
|
|
05ad6da7e6 | ||
|
|
0d3ea9626c | ||
|
|
b8b83c2ec8 | ||
|
|
d05dfae1d7 | ||
|
|
d0fcd4a13a | ||
|
|
b02adeccc1 | ||
|
|
b3f110b7a5 | ||
|
|
daf0ba67a4 | ||
|
|
cf3499f0e4 | ||
|
|
a72cbaf243 | ||
|
|
9ea2811aa3 | ||
|
|
0abef7396f | ||
|
|
101d9e85ef | ||
|
|
7a3be45efd | ||
|
|
f4d92eed18 | ||
|
|
db6f2cba75 |
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -1,15 +0,0 @@
|
||||
EbeanORM
|
||||
|
||||
Copyright 2012 Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -4,10 +4,12 @@
|
||||
[](https://github.com/ebean-orm/ebean/actions/workflows/multi-jdk-build.yml)
|
||||
[](https://github.com/ebean-orm/ebean/actions/workflows/jdk-18-ea.yml)
|
||||
|
||||
[](https://github.com/ebean-orm/ebean/actions/workflows/h2database.yml)
|
||||
[](https://github.com/ebean-orm/ebean/actions/workflows/postgres.yml)
|
||||
[](https://github.com/ebean-orm/ebean/actions/workflows/mysql.yml)
|
||||
[](https://github.com/ebean-orm/ebean/actions/workflows/mariadb.yml)
|
||||
[](https://github.com/ebean-orm/ebean/actions/workflows/sqlserver.yml)
|
||||
[](https://github.com/ebean-orm/ebean/actions/workflows/yugabyte.yml)
|
||||
|
||||
# Sponsors
|
||||
<table>
|
||||
|
||||
+2
-2
@@ -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);
|
||||
|
||||
+1
-12
@@ -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,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
@@ -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>
|
||||
|
||||
@@ -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
@@ -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();
|
||||
|
||||
+20
-2
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+2
-3
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+69
-41
@@ -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
-14
@@ -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;
|
||||
|
||||
|
||||
-3
@@ -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());
|
||||
|
||||
-1
@@ -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;
|
||||
|
||||
|
||||
+56
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
-8
@@ -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:
|
||||
|
||||
+2
@@ -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
-18
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+3
-5
@@ -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);
|
||||
}
|
||||
|
||||
+45
@@ -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();
|
||||
|
||||
|
||||
}
|
||||
+7
-16
@@ -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.
|
||||
|
||||
+15
-17
@@ -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);
|
||||
}
|
||||
|
||||
+104
-31
@@ -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 @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,
|
||||
* @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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+14
-16
@@ -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);
|
||||
}
|
||||
|
||||
+107
-71
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+152
@@ -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;
|
||||
}
|
||||
}
|
||||
+14
-25
@@ -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;
|
||||
}
|
||||
|
||||
+183
-235
@@ -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) {
|
||||
|
||||
+1
@@ -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)");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+2
-8
@@ -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
|
||||
|
||||
+7
-13
@@ -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;
|
||||
|
||||
+149
-6
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+138
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
+79
-96
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
-71
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+6
-18
@@ -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
|
||||
|
||||
+10
-16
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
-11
@@ -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));
|
||||
}
|
||||
}
|
||||
+26
-43
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
-131
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
-79
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+19
-13
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+30
-67
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+14
-29
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
+2
-8
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
+16
-33
@@ -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()
|
||||
|
||||
+34
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
+107
-82
@@ -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
Reference in New Issue
Block a user