mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
353
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7e233edcc3 | ||
|
|
a8b98282a1 | ||
|
|
b4506aa718 | ||
|
|
848a3b8888 | ||
|
|
67c711d75f | ||
|
|
3d62f58930 | ||
|
|
a30948d38d | ||
|
|
a8232d2d8b | ||
|
|
d4b8f23a5a | ||
|
|
bcf2a44187 | ||
|
|
f3102ba02c | ||
|
|
0351eab3a7 | ||
|
|
409e2b75ce | ||
|
|
dc968f16bf | ||
|
|
bbbb6482fb | ||
|
|
001968fcf8 | ||
|
|
6abcb186a4 | ||
|
|
f250447fbe | ||
|
|
bfa86f241b | ||
|
|
19459b71b4 | ||
|
|
5e97c3bbbc | ||
|
|
986eadd023 | ||
|
|
c6787d0901 | ||
|
|
3792e06859 | ||
|
|
c77446ba24 | ||
|
|
dba245c517 | ||
|
|
489eb483c0 | ||
|
|
11301846be | ||
|
|
d022e4aec8 | ||
|
|
aa788edb68 | ||
|
|
288adcdf68 | ||
|
|
ddb07ca202 | ||
|
|
524b592e82 | ||
|
|
0124f0f254 | ||
|
|
eddd6a36d6 | ||
|
|
91e309d770 | ||
|
|
5726410f6f | ||
|
|
054f7dc86f | ||
|
|
06b5ebc14e | ||
|
|
f6ee82428f | ||
|
|
e1d45dd79d | ||
|
|
08c455279f | ||
|
|
32dcbc6703 | ||
|
|
c9e733df4e | ||
|
|
606e1e6d3a | ||
|
|
fcb50ea13a | ||
|
|
5b26e77cfd | ||
|
|
9fc5d8a201 | ||
|
|
ba78c5e904 | ||
|
|
6627195fc2 | ||
|
|
b76c4a83ec | ||
|
|
3dcb82b1f5 | ||
|
|
ae55a40ebd | ||
|
|
8ba07419fa | ||
|
|
5f8f735bbe | ||
|
|
47829f3985 | ||
|
|
ec4f655312 | ||
|
|
04fda0a6b4 | ||
|
|
0a8c902790 | ||
|
|
9632279c2f | ||
|
|
262d52ed44 | ||
|
|
74330918e1 | ||
|
|
373598ab26 | ||
|
|
0096477757 | ||
|
|
a2a4a15f32 | ||
|
|
71dd0e5728 | ||
|
|
116cc3a3fe | ||
|
|
92132d6613 | ||
|
|
d6e3292a7d | ||
|
|
227a1ba032 | ||
|
|
953cae6ce8 | ||
|
|
98fc739600 | ||
|
|
fc3ab10984 | ||
|
|
5b8ce8eaa0 | ||
|
|
97cf8b30f6 | ||
|
|
7e66e0db1f | ||
|
|
572bb41b73 | ||
|
|
088fcfb296 | ||
|
|
54172aec6c | ||
|
|
5c1de0a886 | ||
|
|
c292da736b | ||
|
|
987fe38618 | ||
|
|
f4ed813c08 | ||
|
|
a358fba31d | ||
|
|
76783d525a | ||
|
|
3f0f5c7fde | ||
|
|
6df1058aab | ||
|
|
335c5fb69b | ||
|
|
94ed568812 | ||
|
|
1c23720605 | ||
|
|
ccba5d08ef | ||
|
|
641ada001e | ||
|
|
fca80ac649 | ||
|
|
379cc39e38 | ||
|
|
386d3a37f1 | ||
|
|
37612c6f83 | ||
|
|
7984553d96 | ||
|
|
d592e7d35f | ||
|
|
5a0b65b4f2 | ||
|
|
aaefaa5dcd | ||
|
|
f3e66c459a | ||
|
|
16d5e04809 | ||
|
|
b01df515bd | ||
|
|
7fda911931 | ||
|
|
e332aace16 | ||
|
|
c79231c846 | ||
|
|
efad23d482 | ||
|
|
fe8a32ea18 | ||
|
|
31099f6dda | ||
|
|
58f4f791f6 | ||
|
|
b27989f541 | ||
|
|
7bc1a902ed | ||
|
|
358720776e | ||
|
|
417ee4061e | ||
|
|
394cb3854a | ||
|
|
547fa342c4 | ||
|
|
f8b8a41bce | ||
|
|
ba39897b18 | ||
|
|
1437843f08 | ||
|
|
7c705e2baa | ||
|
|
2caeb4fff1 | ||
|
|
84190f3c2a | ||
|
|
46b158a0a0 | ||
|
|
b172a32710 | ||
|
|
f8ef87f7a8 | ||
|
|
ea54d1b794 | ||
|
|
b1780948a8 | ||
|
|
1a0f3a6614 | ||
|
|
580b51381e | ||
|
|
75e9770d5e | ||
|
|
10937de24b | ||
|
|
18aeedc153 | ||
|
|
9ca1a87f8b | ||
|
|
111354f391 | ||
|
|
79879fb326 | ||
|
|
9f6ccdee66 | ||
|
|
bbf469bd54 | ||
|
|
ad97ac2be9 | ||
|
|
9d83017374 | ||
|
|
98ec00a2d6 | ||
|
|
24971bcc86 | ||
|
|
c1c45139a0 | ||
|
|
116425b460 | ||
|
|
48acb6294b | ||
|
|
61f5057528 | ||
|
|
b91ef46243 | ||
|
|
0eddcc30bb | ||
|
|
24ec0fefba | ||
|
|
5ac28cb3fb | ||
|
|
d4635fb615 | ||
|
|
b9774e64e9 | ||
|
|
f29ba8383e | ||
|
|
a15dd33380 | ||
|
|
f22563b36a | ||
|
|
fe17ec5dbb | ||
|
|
85fdf8646d | ||
|
|
bd9acab335 | ||
|
|
0a6941bda5 | ||
|
|
215417a43c | ||
|
|
60c1a5b111 | ||
|
|
5166fbed96 | ||
|
|
851f40e7b0 | ||
|
|
845faf74ff | ||
|
|
c0d4dac2b3 | ||
|
|
f6c3279e86 | ||
|
|
48f0da9343 | ||
|
|
ce0d73cf23 | ||
|
|
1585bd7cd0 | ||
|
|
1603c69156 | ||
|
|
7cd9dc0c8d | ||
|
|
e4304494e1 | ||
|
|
0612d89e9a | ||
|
|
e6f779268a | ||
|
|
815d846695 | ||
|
|
4b74062d80 | ||
|
|
1dd0841f00 | ||
|
|
3a9668fe6c | ||
|
|
93f802f7fe | ||
|
|
8cde0da419 | ||
|
|
14f984ea3e | ||
|
|
253bebb9bb | ||
|
|
483538bbc1 | ||
|
|
c0ef6d8b34 | ||
|
|
7f06863b19 | ||
|
|
8be7ee1b7d | ||
|
|
15e2fde864 | ||
|
|
4e5140c877 | ||
|
|
13ed298ee8 | ||
|
|
e83a6f05bc | ||
|
|
a0c312e5a4 | ||
|
|
1eabb7fdb4 | ||
|
|
9e170b40f6 | ||
|
|
efd5e16511 | ||
|
|
c4e0d7aedc | ||
|
|
d1584bed40 | ||
|
|
689d201b04 | ||
|
|
22407506ff | ||
|
|
009f91b949 | ||
|
|
3bd281bea0 | ||
|
|
30c3a435d6 | ||
|
|
0fe321b0ef | ||
|
|
8f12442ac7 | ||
|
|
40ab3c81dc | ||
|
|
d5a8bf38ad | ||
|
|
0e793036fb | ||
|
|
19b7637d46 | ||
|
|
5609bc6d02 | ||
|
|
fceeeacf88 | ||
|
|
4327108ddf | ||
|
|
cb77f33fc8 | ||
|
|
b687305be2 | ||
|
|
192305c61f | ||
|
|
03faf29bcf | ||
|
|
d389f8b5ac | ||
|
|
56348938fb | ||
|
|
9b0aafbfa8 | ||
|
|
9239d61c74 | ||
|
|
58a110e109 | ||
|
|
b255102780 | ||
|
|
3a14b4c87f | ||
|
|
e1d6bf5961 | ||
|
|
8e546bde0b | ||
|
|
29a97d84a1 | ||
|
|
c526b3ef57 | ||
|
|
032721d246 | ||
|
|
0731084ec0 | ||
|
|
11a3e49daa | ||
|
|
68481844ee | ||
|
|
96a9def513 | ||
|
|
98a4f046ee | ||
|
|
9db8c941dc | ||
|
|
fd4a6906bd | ||
|
|
da65256208 | ||
|
|
0d2615522f | ||
|
|
6e5e5fb666 | ||
|
|
8005ef8432 | ||
|
|
49fe97bbe4 | ||
|
|
95ab97df73 | ||
|
|
3be9833ee0 | ||
|
|
b82223dc1d | ||
|
|
17d97623d5 | ||
|
|
1fca5ba008 | ||
|
|
5bb97ee42f | ||
|
|
ae9a03e58c | ||
|
|
ca12761fb2 | ||
|
|
18a61416fd | ||
|
|
37ff2c7227 | ||
|
|
af4018403b | ||
|
|
d3b9bde5c2 | ||
|
|
d704fef294 | ||
|
|
bb4bb64795 | ||
|
|
402ab092d8 | ||
|
|
9769e4b574 | ||
|
|
e19fe5ccd3 | ||
|
|
11963e1ff7 | ||
|
|
ec0d4fbd07 | ||
|
|
4e66e348fc | ||
|
|
eb6fce5a72 | ||
|
|
21b33bb9cd | ||
|
|
430b3cff96 | ||
|
|
334a8b66bd | ||
|
|
204b9ca6e5 | ||
|
|
93f13113e6 | ||
|
|
ca1f95df7a | ||
|
|
0c9bcca584 | ||
|
|
a27433dc11 | ||
|
|
dbd789f4be | ||
|
|
7efbffb46d | ||
|
|
559383a810 | ||
|
|
1897ac67a0 | ||
|
|
4f2d669897 | ||
|
|
f50b18556e | ||
|
|
1dc8a7f314 | ||
|
|
b526d07eed | ||
|
|
97cd0909e8 | ||
|
|
39cb85fda6 | ||
|
|
498f567e37 | ||
|
|
99cecd6756 | ||
|
|
7ab374b4ee | ||
|
|
22d36bd1c4 | ||
|
|
ebc4d9fdc5 | ||
|
|
b1c41a58f2 | ||
|
|
40710f788d | ||
|
|
5513c46f78 | ||
|
|
8879bd2be8 | ||
|
|
4ab8ced4a3 | ||
|
|
5bb9e1b188 | ||
|
|
db97d4576f | ||
|
|
c581fa27ab | ||
|
|
bef4e476d7 | ||
|
|
e30e35bf4f | ||
|
|
2e1f02163c | ||
|
|
1ce84ec343 | ||
|
|
6dc21ce69b | ||
|
|
8d5621248f | ||
|
|
b73cc378b5 | ||
|
|
564c7b8317 | ||
|
|
f4a61cddaf | ||
|
|
456f5c1d6a | ||
|
|
ae0404b1a7 | ||
|
|
31f91e571d | ||
|
|
20acd56bb9 | ||
|
|
a764006523 | ||
|
|
84b8777c2b | ||
|
|
c0fc7d69a6 | ||
|
|
4807ca32be | ||
|
|
4c841a8f9f | ||
|
|
6babebfec5 | ||
|
|
660666a28b | ||
|
|
34550dd778 | ||
|
|
64bc0636d7 | ||
|
|
aa199da57d | ||
|
|
b265ffd7d6 | ||
|
|
00f4aee80a | ||
|
|
d6973ed88d | ||
|
|
2ada43f6ba | ||
|
|
e800a18b31 | ||
|
|
ea5ceb61ca | ||
|
|
972609281f | ||
|
|
4ea68ebce4 | ||
|
|
d01c6262b6 | ||
|
|
19e3d82d98 | ||
|
|
f06c1b83a9 | ||
|
|
ea504a93cf | ||
|
|
9fe47194ff | ||
|
|
ba3b1fea6f | ||
|
|
58088b2090 | ||
|
|
cca7a505a3 | ||
|
|
ece7466117 | ||
|
|
3451280679 | ||
|
|
bef2894949 | ||
|
|
06b6638926 | ||
|
|
53cf6c162c | ||
|
|
069b83b78d | ||
|
|
c0c56c0040 | ||
|
|
92c298b848 | ||
|
|
831d2a6179 | ||
|
|
90886193c0 | ||
|
|
deed0bb01d | ||
|
|
7f2c705b94 | ||
|
|
6c0401b191 | ||
|
|
331d28b512 | ||
|
|
9fd936c521 | ||
|
|
4a13fc307b | ||
|
|
adef15ce2b | ||
|
|
88340618af | ||
|
|
49b97887b0 | ||
|
|
6843c72149 | ||
|
|
f78c217d83 | ||
|
|
ede91ecf78 | ||
|
|
efe4e69ed1 | ||
|
|
8a3d9edd34 | ||
|
|
b9aa76c367 |
@@ -7,8 +7,11 @@
|
||||
target/
|
||||
logs/
|
||||
log/
|
||||
ebean-autotune.xml
|
||||
ebean-profiling*.xml
|
||||
/db
|
||||
/mydb.db
|
||||
!src/test/ddl-review/*.sql
|
||||
|
||||
|
||||
# Intellij project files
|
||||
|
||||
@@ -5,16 +5,7 @@
|
||||
|
||||
Ebean ORM
|
||||
==============
|
||||
[http://ebean-orm.github.io/](http://ebean-orm.github.io/ "Ebean ORM's Website")
|
||||
|
||||
|
||||
Maven Dependency
|
||||
----------------
|
||||
<dependency>
|
||||
<groupId>org.avaje.ebeanorm</groupId>
|
||||
<artifactId>avaje-ebeanorm</artifactId>
|
||||
<version>4.7.3</version>
|
||||
</dependency>
|
||||
[https://ebean-orm.github.io/](http://ebean-orm.github.io/ "Ebean ORM's Website")
|
||||
|
||||
|
||||
[Maven central - avaje-ebeanorm](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.avaje.ebeanorm%22%20AND%20a%3A%22avaje-ebeanorm%22 "maven central ebeanorm")
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<groupId>org.avaje.ebeanorm</groupId>
|
||||
<artifactId>avaje-ebeanorm</artifactId>
|
||||
<version>6.2.2</version>
|
||||
<version>6.10.1</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>avaje-ebeanorm</name>
|
||||
@@ -61,6 +61,14 @@
|
||||
<version>1.7.7</version>
|
||||
</dependency>
|
||||
|
||||
<!-- provided scope for Spring boot loader classpath scanning support -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-loader</artifactId>
|
||||
<version>1.2.7.RELEASE</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- provided scope for JsonNode support -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
@@ -109,10 +117,24 @@
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<version>9.4-1201-jdbc41</version>
|
||||
<version>9.4-1202-jdbc41</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!--<dependency>-->
|
||||
<!--<groupId>oracle</groupId>-->
|
||||
<!--<artifactId>oracle-jdbc</artifactId>-->
|
||||
<!--<version>7.0</version>-->
|
||||
<!--<scope>test</scope>-->
|
||||
<!--</dependency>-->
|
||||
|
||||
<!--<dependency>-->
|
||||
<!--<groupId>microsoft</groupId>-->
|
||||
<!--<artifactId>sqlserver-jdbc</artifactId>-->
|
||||
<!--<version>4.2</version>-->
|
||||
<!--<scope>test</scope>-->
|
||||
<!--</dependency>-->
|
||||
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
@@ -130,15 +152,17 @@
|
||||
<dependency>
|
||||
<groupId>org.avaje.ebeanorm</groupId>
|
||||
<artifactId>avaje-ebeanorm-agent</artifactId>
|
||||
<version>4.5.1</version>
|
||||
<version>4.7.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Provided scope so that the H2HistoryTrigger can live in Ebean core
|
||||
and not require a separate module for it -->
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<version>1.4.182</version>
|
||||
<scope>test</scope>
|
||||
<version>1.4.189</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -195,7 +219,7 @@
|
||||
<plugin>
|
||||
<groupId>org.avaje.ebeanorm</groupId>
|
||||
<artifactId>avaje-ebeanorm-mavenenhancer</artifactId>
|
||||
<version>4.5.1</version>
|
||||
<version>4.7.1</version>
|
||||
<executions>
|
||||
<!-- Not going to enhance Model bean -->
|
||||
<execution>
|
||||
@@ -204,7 +228,7 @@
|
||||
<configuration>
|
||||
<classSource>target/test-classes</classSource>
|
||||
<packages>com.avaje.tests.**</packages>
|
||||
<transformArgs>debug=1</transformArgs>
|
||||
<transformArgs>debug=2</transformArgs>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>enhance</goal>
|
||||
@@ -249,11 +273,11 @@
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.9.1</version>
|
||||
<configuration>
|
||||
<doctitle>Ebean 4</doctitle>
|
||||
<doctitle>Ebean 6</doctitle>
|
||||
<overview>src/main/java/com/avaje/ebean/overview.html</overview>
|
||||
<source>1.8</source>
|
||||
<doclet>org.avaje.doclet.PygmentsDoclet</doclet>
|
||||
<excludePackageNames>com.avaje.ebeaninternal.*:com.avaje.ebean.util</excludePackageNames>
|
||||
<excludePackageNames>com.avaje.ebeaninternal.*:com.avaje.ebean.util:com.avaje.ebean.dbmigration.ddlgeneration:com.avaje.ebean.dbmigration.migration:com.avaje.ebean.dbmigration.migrationreader:com.avaje.ebean.dbmigration.model</excludePackageNames>
|
||||
<docletArtifact>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>pygments-doclet</artifactId>
|
||||
|
||||
@@ -1,137 +0,0 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
/**
|
||||
* Administrative control of Autofetch during runtime.
|
||||
*/
|
||||
public interface AdminAutofetch {
|
||||
|
||||
/**
|
||||
* Return true if profiling is enabled.
|
||||
*/
|
||||
boolean isProfiling();
|
||||
|
||||
/**
|
||||
* Set to true to enable profiling.
|
||||
*/
|
||||
void setProfiling(boolean enable);
|
||||
|
||||
/**
|
||||
* Return true if autoFetch automatic query tuning is enabled.
|
||||
*/
|
||||
boolean isQueryTuning();
|
||||
|
||||
/**
|
||||
* Set to true to enable autoFetch automatic query tuning.
|
||||
*/
|
||||
void setQueryTuning(boolean enable);
|
||||
|
||||
/**
|
||||
* Returns the rate which profiling is collected. This is an int between 0 and
|
||||
* 100.
|
||||
*/
|
||||
double getProfilingRate();
|
||||
|
||||
/**
|
||||
* Set the rate at which profiling is collected after the base.
|
||||
*
|
||||
* @param rate
|
||||
* a int between 0 and 100.
|
||||
*/
|
||||
void setProfilingRate(double rate);
|
||||
|
||||
/**
|
||||
* Return the number of queries profiled after which profiling is collected at
|
||||
* a percentage rate.
|
||||
*/
|
||||
int getProfilingBase();
|
||||
|
||||
/**
|
||||
* Set a base number of queries to profile per query point.
|
||||
* <p>
|
||||
* After this amount of profiling has been obtained profiling is collected at
|
||||
* the Profiling Percentage rate.
|
||||
* </p>
|
||||
*/
|
||||
void setProfilingBase(int profilingBase);
|
||||
|
||||
/**
|
||||
* Return the minimum number of queries profiled before autoFetch will start
|
||||
* automatically tuning the queries.
|
||||
* <p>
|
||||
* This could be one which means start autoFetch tuning after the first
|
||||
* profiling information is collected.
|
||||
* </p>
|
||||
*/
|
||||
int getProfilingMin();
|
||||
|
||||
/**
|
||||
* Set the minimum number of queries profiled per query point before autoFetch
|
||||
* will automatically tune the queries.
|
||||
* <p>
|
||||
* Increasing this number will mean more profiling is collected before
|
||||
* autoFetch starts tuning the query.
|
||||
* </p>
|
||||
*/
|
||||
void setProfilingMin(int autoFetchMinThreshold);
|
||||
|
||||
/**
|
||||
* Fire a garbage collection (hint to the JVM). Assuming garbage collection
|
||||
* fires this will gather the usage profiling information.
|
||||
*/
|
||||
String collectUsageViaGC();
|
||||
|
||||
/**
|
||||
* This will take the current profiling information and update the "tuned
|
||||
* query detail".
|
||||
* <p>
|
||||
* This is done periodically and can also be manually invoked.
|
||||
* </p>
|
||||
*
|
||||
* @return a summary of the updates that occurred
|
||||
*/
|
||||
String updateTunedQueryInfo();
|
||||
|
||||
/**
|
||||
* Clear all the tuned query info.
|
||||
* <p>
|
||||
* Should only need do this for testing and playing around.
|
||||
* </p>
|
||||
*
|
||||
* @return the amount of tuned query information cleared.
|
||||
*/
|
||||
int clearTunedQueryInfo();
|
||||
|
||||
/**
|
||||
* Clear all the profiling information.
|
||||
* <p>
|
||||
* This means the profiling information will need to be re-gathered.
|
||||
* </p>
|
||||
* <p>
|
||||
* Should only need do this for testing and playing around.
|
||||
* </p>
|
||||
*
|
||||
* @return the amount of profiled information cleared.
|
||||
*/
|
||||
int clearProfilingInfo();
|
||||
|
||||
/**
|
||||
* Clear the query execution statistics.
|
||||
*/
|
||||
void clearQueryStatistics();
|
||||
|
||||
/**
|
||||
* Return the number of queries tuned by AutoFetch.
|
||||
*/
|
||||
int getTotalTunedQueryCount();
|
||||
|
||||
/**
|
||||
* Return the size of the TuneQuery map.
|
||||
*/
|
||||
int getTotalTunedQuerySize();
|
||||
|
||||
/**
|
||||
* Return the size of the profile map.
|
||||
*/
|
||||
int getTotalProfileSize();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
/**
|
||||
* Administrative control of AutoTune during runtime.
|
||||
*/
|
||||
public interface AutoTune {
|
||||
|
||||
/**
|
||||
* Fire a garbage collection (hint to the JVM). Assuming garbage collection
|
||||
* fires this will gather remaining usage profiling information.
|
||||
*/
|
||||
void collectProfiling();
|
||||
|
||||
}
|
||||
@@ -38,6 +38,33 @@ public interface BeanState {
|
||||
*/
|
||||
void setDisableLazyLoad(boolean disableLazyLoading);
|
||||
|
||||
/**
|
||||
* Set the loaded state of the property given it's name.
|
||||
*
|
||||
* <p>
|
||||
* Typically this would be used to set the loaded state of a property
|
||||
* to false to ensure that the specific property is excluded from a
|
||||
* stateless update.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // populate a bean via say JSON
|
||||
* User user = ...;
|
||||
*
|
||||
* // set loaded state on the email property to false so that
|
||||
* // the email property is not included in a stateless update
|
||||
* Ebean.getBeanState(user).setPropertyLoaded("email", false);
|
||||
*
|
||||
* user.update();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
*
|
||||
* This will throw an IllegalArgumentException if the property is unknown.
|
||||
*/
|
||||
void setPropertyLoaded(String propertyName, boolean loaded);
|
||||
|
||||
/**
|
||||
* For partially populated beans returns the properties that are loaded on the
|
||||
* bean.
|
||||
|
||||
@@ -80,7 +80,7 @@ public interface CallableSql {
|
||||
/**
|
||||
* Return the label that is put into the transaction log.
|
||||
*/
|
||||
public String getLabel();
|
||||
String getLabel();
|
||||
|
||||
/**
|
||||
* Set the label that is put in the transaction log.
|
||||
|
||||
@@ -80,17 +80,16 @@ final class DRawSqlColumnsParser {
|
||||
return new ColumnMapping.Column(indexPos++, sb.toString(), split[split.length - 1]);
|
||||
}
|
||||
|
||||
private int nextComma() {
|
||||
private void nextComma() {
|
||||
boolean inQuote = false;
|
||||
while (pos < end) {
|
||||
char c = sqlSelect.charAt(pos);
|
||||
if (c == '\'') {
|
||||
inQuote = !inQuote;
|
||||
} else if (!inQuote && c == ',') {
|
||||
return pos;
|
||||
return;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ class DRawSqlParser {
|
||||
private int placeHolderAndWhere;
|
||||
private int placeHolderHaving;
|
||||
private int placeHolderAndHaving;
|
||||
private boolean hasPlaceHolders;
|
||||
private final boolean hasPlaceHolders;
|
||||
|
||||
private int selectPos = -1;
|
||||
private int distinctPos = -1;
|
||||
@@ -98,19 +98,7 @@ class DRawSqlParser {
|
||||
}
|
||||
|
||||
private boolean hasPlaceHolders() {
|
||||
if (placeHolderWhere > -1) {
|
||||
return true;
|
||||
}
|
||||
if (placeHolderAndWhere > -1) {
|
||||
return true;
|
||||
}
|
||||
if (placeHolderHaving > -1) {
|
||||
return true;
|
||||
}
|
||||
if (placeHolderAndHaving > -1) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return placeHolderWhere > -1 || placeHolderAndWhere > -1 || placeHolderHaving > -1 || placeHolderAndHaving > -1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,7 +22,7 @@ import com.avaje.ebean.text.json.JsonContext;
|
||||
/**
|
||||
* This Ebean object is effectively a singleton that holds a map of registered
|
||||
* {@link EbeanServer}s. It additionally provides a convenient way to use the
|
||||
* 'default/primary' EbeanServer.
|
||||
* 'default' EbeanServer.
|
||||
* <p>
|
||||
* If you are using a Dependency Injection framework such as
|
||||
* <strong>Spring</strong> or <strong>Guice</strong> you will probably
|
||||
@@ -168,9 +168,9 @@ public final class Ebean {
|
||||
defaultServer = getWithCreate(defaultName.trim());
|
||||
}
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
} catch (Throwable e) {
|
||||
logger.error("Error trying to create the default EbeanServer", e);
|
||||
throw e;
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,7 +178,7 @@ public final class Ebean {
|
||||
if (defaultServer == null) {
|
||||
String msg = "The default EbeanServer has not been defined?";
|
||||
msg += " This is normally set via the ebean.datasource.default property.";
|
||||
msg += " Otherwise it should be registered programatically via registerServer()";
|
||||
msg += " Otherwise it should be registered programmatically via registerServer()";
|
||||
throw new PersistenceException(msg);
|
||||
}
|
||||
return defaultServer;
|
||||
@@ -217,8 +217,8 @@ public final class Ebean {
|
||||
/**
|
||||
* Register a server so we can get it by its name.
|
||||
*/
|
||||
private void register(EbeanServer server, boolean isPrimaryServer) {
|
||||
registerWithName(server.getName(), server, isPrimaryServer);
|
||||
private void register(EbeanServer server, boolean isDefaultServer) {
|
||||
registerWithName(server.getName(), server, isDefaultServer);
|
||||
}
|
||||
|
||||
private void registerWithName(String name, EbeanServer server, boolean isDefaultServer) {
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.OptimisticLockException;
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebean.annotation.CacheStrategy;
|
||||
import com.avaje.ebean.cache.ServerCacheManager;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.meta.MetaInfoManager;
|
||||
import com.avaje.ebean.plugin.SpiServer;
|
||||
import com.avaje.ebean.text.csv.CsvReader;
|
||||
import com.avaje.ebean.text.json.JsonContext;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.persistence.OptimisticLockException;
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Provides the API for fetching and saving beans to a particular DataSource.
|
||||
* <p>
|
||||
@@ -106,10 +106,9 @@ public interface EbeanServer {
|
||||
void shutdown(boolean shutdownDataSource, boolean deregisterDriver);
|
||||
|
||||
/**
|
||||
* Return the AdminAutofetch which is used to control and configure the
|
||||
* Autofetch service at runtime.
|
||||
* Return AutoTune which is used to control the AutoTune service at runtime.
|
||||
*/
|
||||
AdminAutofetch getAdminAutofetch();
|
||||
AutoTune getAutoTune();
|
||||
|
||||
/**
|
||||
* Return the name. This is used with {@link Ebean#getServer(String)} to get a
|
||||
@@ -128,6 +127,11 @@ public interface EbeanServer {
|
||||
*/
|
||||
MetaInfoManager getMetaInfoManager();
|
||||
|
||||
/**
|
||||
* Return the extended API intended for use by plugins.
|
||||
*/
|
||||
SpiServer getPluginApi();
|
||||
|
||||
/**
|
||||
* Return the BeanState for a given entity bean.
|
||||
* <p>
|
||||
@@ -1108,6 +1112,21 @@ public interface EbeanServer {
|
||||
@Nullable
|
||||
<T> T findUnique(Query<T> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute as a delete query deleting the 'root level' beans that match the predicates
|
||||
* in the query.
|
||||
* <p>
|
||||
* Note that if the query includes joins then the generated delete statement may not be
|
||||
* optimal depending on the database platform.
|
||||
* </p>
|
||||
*
|
||||
* @param query the query used for the delete
|
||||
* @param transaction the transaction to use (can be null)
|
||||
* @param <T> the type of entity bean to fetch.
|
||||
* @return the number of beans/rows that were deleted
|
||||
*/
|
||||
<T> int delete(Query<T> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute the sql query returning a list of MapBean.
|
||||
* <p>
|
||||
@@ -1205,7 +1224,6 @@ public interface EbeanServer {
|
||||
* public class Order { ...
|
||||
*
|
||||
* @OneToMany(cascade=CascadeType.ALL, mappedBy="order")
|
||||
* @JoinColumn(name="order_id")
|
||||
* List<OrderDetail> details;
|
||||
* ...
|
||||
* }
|
||||
@@ -1235,9 +1253,9 @@ public interface EbeanServer {
|
||||
void delete(Object bean) throws OptimisticLockException;
|
||||
|
||||
/**
|
||||
* Delete all the beans in the collection.
|
||||
* Delete the bean with an explicit transaction.
|
||||
*/
|
||||
int deleteAll(Collection<?> beans) throws OptimisticLockException;
|
||||
void delete(Object bean, Transaction transaction) throws OptimisticLockException;
|
||||
|
||||
/**
|
||||
* Delete the bean given its type and id.
|
||||
@@ -1249,6 +1267,16 @@ public interface EbeanServer {
|
||||
*/
|
||||
int delete(Class<?> beanType, Object id, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Delete all the beans in the collection.
|
||||
*/
|
||||
int deleteAll(Collection<?> beans) throws OptimisticLockException;
|
||||
|
||||
/**
|
||||
* Delete all the beans in the collection using an explicit transaction.
|
||||
*/
|
||||
int deleteAll(Collection<?> beans, Transaction transaction) throws OptimisticLockException;
|
||||
|
||||
/**
|
||||
* Delete several beans given their type and id values.
|
||||
*/
|
||||
@@ -1260,11 +1288,6 @@ public interface EbeanServer {
|
||||
*/
|
||||
void deleteAll(Class<?> beanType, Collection<?> ids, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Delete the bean with an explicit transaction.
|
||||
*/
|
||||
void delete(Object bean, Transaction transaction) throws OptimisticLockException;
|
||||
|
||||
/**
|
||||
* Execute a Sql Update Delete or Insert statement. This returns the number of
|
||||
* rows that where updated, deleted or inserted. If is executed in batch then
|
||||
|
||||
@@ -36,6 +36,51 @@ import java.util.Map;
|
||||
*/
|
||||
public interface ExpressionFactory {
|
||||
|
||||
/**
|
||||
* Path exists - for the given path in a JSON document.
|
||||
*/
|
||||
Expression jsonExists(String propertyName, String path);
|
||||
|
||||
/**
|
||||
* Path does not exist - for the given path in a JSON document.
|
||||
*/
|
||||
Expression jsonNotExists(String propertyName, String path);
|
||||
|
||||
/**
|
||||
* Equal to - for the given path in a JSON document.
|
||||
*/
|
||||
Expression jsonEqualTo(String propertyName, String path, Object val);
|
||||
|
||||
/**
|
||||
* Not Equal to - for the given path in a JSON document.
|
||||
*/
|
||||
Expression jsonNotEqualTo(String propertyName, String path, Object val);
|
||||
|
||||
/**
|
||||
* Greater than - for the given path in a JSON document.
|
||||
*/
|
||||
Expression jsonGreaterThan(String propertyName, String path, Object val);
|
||||
|
||||
/**
|
||||
* Greater than or equal to - for the given path in a JSON document.
|
||||
*/
|
||||
Expression jsonGreaterOrEqual(String propertyName, String path, Object val);
|
||||
|
||||
/**
|
||||
* Less than - for the given path in a JSON document.
|
||||
*/
|
||||
Expression jsonLessThan(String propertyName, String path, Object val);
|
||||
|
||||
/**
|
||||
* Less than or equal to - for the given path in a JSON document.
|
||||
*/
|
||||
Expression jsonLessOrEqualTo(String propertyName, String path, Object val);
|
||||
|
||||
/**
|
||||
* Between - for the given path in a JSON document.
|
||||
*/
|
||||
Expression jsonBetween(String propertyName, String path, Object lowerValue, Object upperValue);
|
||||
|
||||
/**
|
||||
* Equal To - property equal to the given value.
|
||||
*/
|
||||
|
||||
@@ -107,6 +107,18 @@ public interface ExpressionList<T> extends Serializable {
|
||||
*/
|
||||
Query<T> asOf(Timestamp asOf);
|
||||
|
||||
/**
|
||||
* Execute as a delete query deleting the 'root level' beans that match the predicates
|
||||
* in the query.
|
||||
* <p>
|
||||
* Note that if the query includes joins then the generated delete statement may not be
|
||||
* optimal depending on the database platform.
|
||||
* </p>
|
||||
*
|
||||
* @return the number of beans/rows that were deleted.
|
||||
*/
|
||||
int delete();
|
||||
|
||||
/**
|
||||
* Execute the query iterating over the results.
|
||||
*
|
||||
@@ -244,6 +256,15 @@ public interface ExpressionList<T> extends Serializable {
|
||||
*/
|
||||
List<Version<T>> findVersions();
|
||||
|
||||
/**
|
||||
* Return versions of a @History entity bean between the 2 timestamps.
|
||||
* <p>
|
||||
* Generally this query is expected to be a find by id or unique predicates query.
|
||||
* It will execute the query against the history returning the versions of the bean.
|
||||
* </p>
|
||||
*/
|
||||
List<Version<T>> findVersionsBetween(Timestamp start, Timestamp end);
|
||||
|
||||
/**
|
||||
* Add some filter predicate expressions to the many property.
|
||||
*/
|
||||
@@ -257,6 +278,24 @@ public interface ExpressionList<T> extends Serializable {
|
||||
*/
|
||||
Query<T> select(String properties);
|
||||
|
||||
/**
|
||||
* Set whether this query uses DISTINCT.
|
||||
* <p>
|
||||
* The select() clause MUST be specified when setDistinct(true) is set. The reason for this is that
|
||||
* generally ORM queries include the "id" property and this doesn't make sense for distinct queries.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<Customer> customers =
|
||||
* Ebean.find(Customer.class)
|
||||
* .setDistinct(true)
|
||||
* .select("name") // only select the customer name
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
Query<T> setDistinct(boolean distinct);
|
||||
|
||||
/**
|
||||
* Set the first row to fetch.
|
||||
*
|
||||
@@ -285,6 +324,13 @@ public interface ExpressionList<T> extends Serializable {
|
||||
*/
|
||||
Query<T> setUseCache(boolean useCache);
|
||||
|
||||
/**
|
||||
* Set to true to use the query for executing this query.
|
||||
*
|
||||
* @see Query#setUseQueryCache(boolean)
|
||||
*/
|
||||
Query<T> setUseQueryCache(boolean useCache);
|
||||
|
||||
/**
|
||||
* Add expressions to the having clause.
|
||||
* <p>
|
||||
@@ -299,20 +345,136 @@ public interface ExpressionList<T> extends Serializable {
|
||||
*/
|
||||
ExpressionList<T> where();
|
||||
|
||||
/**
|
||||
* Path exists - for the given path in a JSON document.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* where().jsonExists("content", "path.other")
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param propertyName the property that holds a JSON document
|
||||
* @param path the nested path in the JSON document in dot notation
|
||||
*/
|
||||
ExpressionList<T> jsonExists(String propertyName, String path);
|
||||
|
||||
/**
|
||||
* Path does not exist - for the given path in a JSON document.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* where().jsonNotExists("content", "path.other")
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param propertyName the property that holds a JSON document
|
||||
* @param path the nested path in the JSON document in dot notation
|
||||
*/
|
||||
ExpressionList<T> jsonNotExists(String propertyName, String path);
|
||||
|
||||
/**
|
||||
* Equal to expression for the value at the given path in the JSON document.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* where().jsonEqualTo("content", "path.other", 34)
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param propertyName the property that holds a JSON document
|
||||
* @param path the nested path in the JSON document in dot notation
|
||||
* @param value the value used to test against the document path's value
|
||||
*/
|
||||
ExpressionList<T> jsonEqualTo(String propertyName, String path, Object value);
|
||||
|
||||
/**
|
||||
* Not Equal to - for the given path in a JSON document.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* where().jsonNotEqualTo("content", "path.other", 34)
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param propertyName the property that holds a JSON document
|
||||
* @param path the nested path in the JSON document in dot notation
|
||||
* @param value the value used to test against the document path's value
|
||||
*/
|
||||
ExpressionList<T> jsonNotEqualTo(String propertyName, String path, Object value);
|
||||
|
||||
/**
|
||||
* Greater than - for the given path in a JSON document.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* where().jsonGreaterThan("content", "path.other", 34)
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
ExpressionList<T> jsonGreaterThan(String propertyName, String path, Object value);
|
||||
|
||||
/**
|
||||
* Greater than or equal to - for the given path in a JSON document.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* where().jsonGreaterOrEqual("content", "path.other", 34)
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
ExpressionList<T> jsonGreaterOrEqual(String propertyName, String path, Object value);
|
||||
|
||||
/**
|
||||
* Less than - for the given path in a JSON document.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* where().jsonLessThan("content", "path.other", 34)
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
ExpressionList<T> jsonLessThan(String propertyName, String path, Object value);
|
||||
|
||||
/**
|
||||
* Less than or equal to - for the given path in a JSON document.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* where().jsonLessOrEqualTo("content", "path.other", 34)
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
ExpressionList<T> jsonLessOrEqualTo(String propertyName, String path, Object value);
|
||||
|
||||
/**
|
||||
* Between - for the given path in a JSON document.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* where().jsonBetween("content", "orderDate", lowerDateTime, upperDateTime)
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
ExpressionList<T> jsonBetween(String propertyName, String path, Object lowerValue, Object upperValue);
|
||||
|
||||
/**
|
||||
* Add an Expression to the list.
|
||||
* <p>
|
||||
* This returns the list so that add() can be chained.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* Query<Customer> query = Ebean.createQuery(Customer.class);
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* Query<Customer> query = Ebean.find(Customer.class);
|
||||
* query.where()
|
||||
* .like("name","Rob%")
|
||||
* .eq("status", Customer.ACTIVE);
|
||||
* List<Customer> list = query.findList();
|
||||
* .like("name","Rob%")
|
||||
* .eq("status", Customer.ACTIVE);
|
||||
*
|
||||
* List<Customer> list = query.findList();
|
||||
* ...
|
||||
* </pre>
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
ExpressionList<T> add(Expression expr);
|
||||
|
||||
@@ -393,33 +555,36 @@ public interface ExpressionList<T> extends Serializable {
|
||||
* those options such as case insensitive etc.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* <pre>{@code
|
||||
*
|
||||
* // create an example bean and set the properties
|
||||
* // with the query parameters you want
|
||||
* Customer example = new Customer();
|
||||
* example.setName("Rob%");
|
||||
* example.setNotes("%something%");
|
||||
* example.setName("Rob%");
|
||||
* example.setNotes("%something%");
|
||||
*
|
||||
* List<Customer> list = Ebean.find(Customer.class).where()
|
||||
* // pass the bean into the where() clause
|
||||
* .exampleLike(example)
|
||||
* // you can add other expressions to the same query
|
||||
* .gt("id", 2).findList();
|
||||
* .gt("id", 2).findList();
|
||||
*
|
||||
* </pre>
|
||||
* }</pre>
|
||||
*
|
||||
* Similarly you can create an ExampleExpression
|
||||
*
|
||||
* <pre>
|
||||
* <pre>{@code
|
||||
*
|
||||
* Customer example = new Customer();
|
||||
* example.setName("Rob%");
|
||||
* example.setNotes("%something%");
|
||||
* example.setName("Rob%");
|
||||
* example.setNotes("%something%");
|
||||
*
|
||||
* // create a ExampleExpression with more control
|
||||
* ExampleExpression qbe = new ExampleExpression(example, true, LikeType.EQUAL_TO).includeZeros();
|
||||
*
|
||||
* List<Customer> list = Ebean.find(Customer.class).where().add(qbe).findList();
|
||||
* </pre>
|
||||
* List<Customer> list = Ebean.find(Customer.class).where().add(qbe).findList();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
ExpressionList<T> exampleLike(Object example);
|
||||
|
||||
@@ -547,6 +712,14 @@ public interface ExpressionList<T> extends Serializable {
|
||||
* then they are not translated. logical property name names (not fully
|
||||
* qualified) will still be translated to their physical name.
|
||||
* </p>
|
||||
*
|
||||
* <h4>Example:</h4>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // use a database function
|
||||
* raw("add_days(orderDate, 10) < ?", someDate)
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
ExpressionList<T> raw(String raw, Object value);
|
||||
|
||||
@@ -571,6 +744,12 @@ public interface ExpressionList<T> extends Serializable {
|
||||
* then they are not translated. logical property name names (not fully
|
||||
* qualified) will still be translated to their physical name.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* raw("orderQty < shipQty")
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
ExpressionList<T> raw(String raw);
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ import java.util.Set;
|
||||
* .sort("avgTimeMicros desc")
|
||||
* .gt("executionCount", 0)
|
||||
* .gt("lastQueryTime", nowMinus24Hrs)
|
||||
* .eq("autofetchTuned", true)
|
||||
* .eq("autoTuned", true)
|
||||
* .maxRows(10)
|
||||
* .filter(list);
|
||||
*
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Intended to be used as a base class for 'Finder' implementations that can then
|
||||
* be injected or used as public static fields on the associated entity bean.
|
||||
* <p>
|
||||
* These 'finders' are a place to organise all the finder methods for that bean type
|
||||
* and specific finder methods are expected to be added (find by unique properties etc).
|
||||
* </p>
|
||||
*
|
||||
* <h3>Testing</h3>
|
||||
* <p>
|
||||
* For testing the mocki-ebean project has the ability to replace the finder implementation
|
||||
*
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* public class CustomerFinder extends Finder<Customer> {
|
||||
*
|
||||
* public CustomerFinder() {
|
||||
* super(Customer.class);
|
||||
* }
|
||||
*
|
||||
* // Add your customer finder methods ...
|
||||
*
|
||||
* public Customer byName(String name) {
|
||||
* return query().eq("name", name).findUnique();
|
||||
* }
|
||||
*
|
||||
* public List<Customer> findNew() {
|
||||
* return query()
|
||||
* .eq("status", Customer.Status.NEW)
|
||||
* .orderBy("name")
|
||||
* .findList()
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* @Entity
|
||||
* public class Customer extends BaseModel {
|
||||
*
|
||||
* public static final CustomerFinder find = new CustomerFinder();
|
||||
* ...
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public class Finder<I, T> {
|
||||
|
||||
/**
|
||||
* The entity bean type.
|
||||
*/
|
||||
private final Class<T> type;
|
||||
|
||||
/**
|
||||
* The name of the EbeanServer, null for the default server.
|
||||
*/
|
||||
private final String serverName;
|
||||
|
||||
/**
|
||||
* Create with the type of the entity bean.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* public class CustomerFinder extends Finder<Customer> {
|
||||
*
|
||||
* public CustomerFinder() {
|
||||
* super(Customer.class);
|
||||
* }
|
||||
*
|
||||
* // ... add extra customer specific finder methods
|
||||
* }
|
||||
*
|
||||
* @Entity
|
||||
* public class Customer extends BaseModel {
|
||||
*
|
||||
* public static final CustomerFinder find = new CustomerFinder();
|
||||
* ...
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public Finder(Class<T> type) {
|
||||
this.type = type;
|
||||
this.serverName = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create with the type of the entity bean and specific server name.
|
||||
*/
|
||||
public Finder(Class<T> type, String serverName) {
|
||||
this.type = type;
|
||||
this.serverName = serverName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the underlying 'default' EbeanServer.
|
||||
*
|
||||
* <p>
|
||||
* This provides full access to the API such as explicit transaction demarcation etc.
|
||||
*
|
||||
*/
|
||||
public EbeanServer db() {
|
||||
return Ebean.getServer(serverName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return typically a different EbeanServer to the default.
|
||||
* <p>
|
||||
* This is equivalent to {@link Ebean#getServer(String)}
|
||||
*
|
||||
* @param server
|
||||
* The name of the EbeanServer. If this is null then the default EbeanServer is
|
||||
* returned.
|
||||
*/
|
||||
public EbeanServer db(String server) {
|
||||
return Ebean.getServer(server);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an entity reference for this ID.
|
||||
*
|
||||
* <p>
|
||||
* Equivalent to {@link EbeanServer#getReference(Class, Object)}
|
||||
*/
|
||||
public T ref(I id) {
|
||||
return db().getReference(type, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves an entity by ID.
|
||||
*
|
||||
* <p>
|
||||
* Equivalent to {@link EbeanServer#find(Class, Object)}
|
||||
*/
|
||||
@Nullable
|
||||
public T byId(I id) {
|
||||
return db().find(type, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a bean by Id.
|
||||
* <p>
|
||||
* Equivalent to {@link EbeanServer#delete(Class, Object)}
|
||||
*/
|
||||
public void deleteById(I id) {
|
||||
db().delete(type, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all entities of the given type.
|
||||
*/
|
||||
public List<T> all() {
|
||||
return query().findList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a query.
|
||||
* <p>
|
||||
* Equivalent to {@link EbeanServer#find(Class)}
|
||||
*/
|
||||
public Query<T> query() {
|
||||
return db().find(type);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,7 +2,6 @@ package com.avaje.ebean;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.text.PathProperties;
|
||||
import com.avaje.ebean.util.ClassUtil;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -193,7 +194,31 @@ public abstract class Model {
|
||||
public void markAsDirty() {
|
||||
db().markAsDirty(this);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Mark the property as unset or 'not loaded'.
|
||||
* <p>
|
||||
* This would be used to specify a property that we did not wish to include in a stateless update.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // populate an entity bean from JSON or whatever
|
||||
* User user = ...;
|
||||
*
|
||||
* // mark the email property as 'unset' so that it is not
|
||||
* // included in a 'stateless update'
|
||||
* user.markPropertyUnset("email");
|
||||
*
|
||||
* user.update();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param propertyName the name of the property on the bean to be marked as 'unset'
|
||||
*/
|
||||
public void markPropertyUnset(String propertyName) {
|
||||
((EntityBean)this)._ebean_getIntercept().setPropertyLoaded(propertyName, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert or update this entity depending on its state.
|
||||
*
|
||||
@@ -441,6 +466,7 @@ public abstract class Model {
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Find() {
|
||||
this.serverName = null;
|
||||
this.type = (Class<T>)ClassUtil.getSecondArgumentType(getClass());
|
||||
@@ -835,10 +861,10 @@ public abstract class Model {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a query with explicit 'Autofetch' use.
|
||||
* Create a query with explicit 'AutoTune' use.
|
||||
*/
|
||||
public Query<T> setAutofetch(boolean autofetch) {
|
||||
return query().setAutofetch(autofetch);
|
||||
public Query<T> setAutoTune(boolean autoTune) {
|
||||
return query().setAutoTune(autoTune);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -28,7 +28,7 @@ public final class OrderBy<T> implements Serializable {
|
||||
* Create an empty OrderBy with no associated query.
|
||||
*/
|
||||
public OrderBy() {
|
||||
this.list = new ArrayList<Property>(2);
|
||||
this.list = new ArrayList<Property>(3);
|
||||
}
|
||||
|
||||
private OrderBy(List<Property> list) {
|
||||
@@ -52,7 +52,7 @@ public final class OrderBy<T> implements Serializable {
|
||||
*/
|
||||
public OrderBy(Query<T> query, String orderByClause) {
|
||||
this.query = query;
|
||||
this.list = new ArrayList<Property>(2);
|
||||
this.list = new ArrayList<Property>(3);
|
||||
parse(orderByClause);
|
||||
}
|
||||
|
||||
@@ -83,6 +83,19 @@ public final class OrderBy<T> implements Serializable {
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the property is known to be contained in the order by clause.
|
||||
*/
|
||||
public boolean containsProperty(String propertyName) {
|
||||
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
if (propertyName.equals(list.get(i).getProperty())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copy of this OrderBy with the path trimmed.
|
||||
*/
|
||||
@@ -185,6 +198,18 @@ public final class OrderBy<T> implements Serializable {
|
||||
return list.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the orderBy removing any current order by properties.
|
||||
* <p>
|
||||
* This is intended to be used when some code creates a query with a
|
||||
* 'default' order by clause and some other code may clear the 'default'
|
||||
* order by clause and replace.
|
||||
* </p>
|
||||
*/
|
||||
public void clear() {
|
||||
list.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* A property and its ascending descending order.
|
||||
*/
|
||||
|
||||
@@ -159,6 +159,11 @@ public interface PagedList<T> {
|
||||
*/
|
||||
int getPageIndex();
|
||||
|
||||
/**
|
||||
* Return the page size used for this query.
|
||||
*/
|
||||
int getPageSize();
|
||||
|
||||
/**
|
||||
* Return true if there is a next page.
|
||||
* <p>
|
||||
|
||||
@@ -67,9 +67,9 @@ import java.util.Set;
|
||||
* ...
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Autofetch</h3>
|
||||
* <h3>AutoTune</h3>
|
||||
* <p>
|
||||
* Ebean has built in support for "Autofetch". This is a mechanism where a query
|
||||
* Ebean has built in support for "AutoTune". This is a mechanism where a query
|
||||
* can be automatically tuned based on profiling information that is collected.
|
||||
* </p>
|
||||
* <p>
|
||||
@@ -78,7 +78,7 @@ import java.util.Set;
|
||||
* more.
|
||||
* </p>
|
||||
* <p>
|
||||
* It is expected that Autofetch will be the default approach for many queries
|
||||
* It is expected that AutoTune will be the default approach for many queries
|
||||
* in a system. It is possibly not as useful where the result of a query is sent
|
||||
* to a remote client or where there is some requirement for "Read Consistency"
|
||||
* guarantees.
|
||||
@@ -338,23 +338,23 @@ public interface Query<T> extends Serializable {
|
||||
ExpressionFactory getExpressionFactory();
|
||||
|
||||
/**
|
||||
* Returns true if this query was tuned by autoFetch.
|
||||
* Returns true if this query was tuned by autoTune.
|
||||
*/
|
||||
boolean isAutofetchTuned();
|
||||
boolean isAutoTuned();
|
||||
|
||||
/**
|
||||
* Explicitly specify whether to use Autofetch for this query.
|
||||
* Explicitly specify whether to use AutoTune for this query.
|
||||
* <p>
|
||||
* If you do not call this method on a query the "Implicit Autofetch mode" is
|
||||
* used to determine if Autofetch should be used for a given query.
|
||||
* If you do not call this method on a query the "Implicit AutoTune mode" is
|
||||
* used to determine if AutoTune should be used for a given query.
|
||||
* </p>
|
||||
* <p>
|
||||
* Autofetch can add additional fetch paths to the query and specify which
|
||||
* AutoTune can add additional fetch paths to the query and specify which
|
||||
* properties are included for each path. If you have explicitly defined some
|
||||
* fetch paths Autofetch will not remove.
|
||||
* fetch paths AutoTune will not remove them.
|
||||
* </p>
|
||||
*/
|
||||
Query<T> setAutofetch(boolean autofetch);
|
||||
Query<T> setAutoTune(boolean autoTune);
|
||||
|
||||
/**
|
||||
* Set the default lazy loading batch size to use.
|
||||
@@ -366,6 +366,16 @@ public interface Query<T> extends Serializable {
|
||||
*/
|
||||
Query<T> setLazyLoadBatchSize(int lazyLoadBatchSize);
|
||||
|
||||
/**
|
||||
* Disable read auditing for this query.
|
||||
* <p>
|
||||
* This is intended to be used when the query is not a user initiated query and instead
|
||||
* part of the internal processing in an application to load a cache or document store etc.
|
||||
* In these cases we don't want the query to be part of read auditing.
|
||||
* </p>
|
||||
*/
|
||||
Query<T> setDisableReadAuditing();
|
||||
|
||||
/**
|
||||
* Explicitly set a comma delimited list of the properties to fetch on the
|
||||
* 'main' root level entity bean (aka partial object). Note that '*' means all
|
||||
@@ -723,12 +733,38 @@ public interface Query<T> extends Serializable {
|
||||
/**
|
||||
* Return versions of a @History entity bean.
|
||||
* <p>
|
||||
* Note that this query will work against view based history implementations
|
||||
* but not sql2011 standards based implementations that require a start and
|
||||
* end timestamp to be specified.
|
||||
* </p>
|
||||
* <p>
|
||||
* Generally this query is expected to be a find by id or unique predicates query.
|
||||
* It will execute the query against the history returning the versions of the bean.
|
||||
* </p>
|
||||
*/
|
||||
List<Version<T>> findVersions();
|
||||
|
||||
/**
|
||||
* Return versions of a @History entity bean between the 2 timestamps.
|
||||
* <p>
|
||||
* Generally this query is expected to be a find by id or unique predicates query.
|
||||
* It will execute the query against the history returning the versions of the bean.
|
||||
* </p>
|
||||
*/
|
||||
List<Version<T>> findVersionsBetween(Timestamp start, Timestamp end);
|
||||
|
||||
/**
|
||||
* Execute as a delete query deleting the 'root level' beans that match the predicates
|
||||
* in the query.
|
||||
* <p>
|
||||
* Note that if the query includes joins then the generated delete statement may not be
|
||||
* optimal depending on the database platform.
|
||||
* </p>
|
||||
*
|
||||
* @return the number of beans/rows that were deleted.
|
||||
*/
|
||||
int delete();
|
||||
|
||||
/**
|
||||
* Return the count of entities this query should return.
|
||||
* <p>
|
||||
@@ -1129,6 +1165,19 @@ public interface Query<T> extends Serializable {
|
||||
|
||||
/**
|
||||
* Set whether this query uses DISTINCT.
|
||||
* <p>
|
||||
* The select() clause MUST be specified when setDistinct(true) is set. The reason for this is that
|
||||
* generally ORM queries include the "id" property and this doesn't make sense for distinct queries.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<Customer> customers =
|
||||
* Ebean.find(Customer.class)
|
||||
* .setDistinct(true)
|
||||
* .select("name")
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
Query<T> setDistinct(boolean isDistinct);
|
||||
|
||||
|
||||
@@ -153,7 +153,7 @@ public interface SqlRow extends Serializable, Map<String, Object> {
|
||||
/**
|
||||
* Put all the values from t into this map.
|
||||
*/
|
||||
void putAll(Map<? extends String, ? extends Object> t);
|
||||
void putAll(Map<? extends String, ?> t);
|
||||
|
||||
/**
|
||||
* Return the size of the map.
|
||||
|
||||
@@ -2,7 +2,6 @@ package com.avaje.ebean;
|
||||
|
||||
import com.avaje.ebean.config.PersistBatch;
|
||||
|
||||
import javax.persistence.OptimisticLockException;
|
||||
import javax.persistence.PersistenceException;
|
||||
import javax.persistence.RollbackException;
|
||||
import java.io.Closeable;
|
||||
@@ -290,7 +289,7 @@ public interface Transaction extends Closeable {
|
||||
* <li>Transaction commit occurs</li>
|
||||
* </ul>
|
||||
*/
|
||||
void flushBatch() throws PersistenceException, OptimisticLockException;
|
||||
void flushBatch() throws PersistenceException;
|
||||
|
||||
/**
|
||||
* Return the underlying Connection object.
|
||||
|
||||
@@ -46,5 +46,5 @@ public enum TxType {
|
||||
* If there is an existing transaction throws an Exception. Method runs
|
||||
* without a transaction.
|
||||
*/
|
||||
NEVER;
|
||||
NEVER
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Marks an entity bean as being included in the change logging.
|
||||
*/
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ChangeLog {
|
||||
|
||||
/**
|
||||
* Specify if inserts should be explicitly Included or Excluded.
|
||||
* <p>
|
||||
* If not defined explicitly then the server default behaviour defined
|
||||
* on ServerConfig is used.
|
||||
* </p>
|
||||
*/
|
||||
ChangeLogInsertMode inserts() default ChangeLogInsertMode.DEFAULT;
|
||||
|
||||
/**
|
||||
* When specified only include update requests that have at least one
|
||||
* of the given properties as a dirty property.
|
||||
* <p>
|
||||
* This provides a way to filter requests to include in the change log such that
|
||||
* only updates that include at least one of the given properties is included
|
||||
* in the change log.
|
||||
* </p>
|
||||
*/
|
||||
String[] updatesThatInclude() default {};
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
/**
|
||||
* The mode used to determine if inserts should be included or not for a given bean type.
|
||||
*/
|
||||
public enum ChangeLogInsertMode {
|
||||
|
||||
/**
|
||||
* Use the default behaviour as defined on ServerConfig.
|
||||
*/
|
||||
DEFAULT,
|
||||
|
||||
/**
|
||||
* Include inserts in the change log.
|
||||
*/
|
||||
INCLUDE,
|
||||
|
||||
/**
|
||||
* Exclude inserts in the change log.
|
||||
*/
|
||||
EXCLUDE
|
||||
}
|
||||
@@ -10,15 +10,24 @@ import java.lang.annotation.Target;
|
||||
*
|
||||
* @author rvbiljouw
|
||||
*/
|
||||
@Target({ElementType.FIELD})
|
||||
@Target({ElementType.TYPE, ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Index {
|
||||
|
||||
/**
|
||||
* Name of the index
|
||||
*
|
||||
* @return index name
|
||||
* Name of the index. If left blank a name is derived using the built in naming convention.
|
||||
*/
|
||||
String value() default "";
|
||||
String name() default "";
|
||||
|
||||
/**
|
||||
* If set true indicates this is a unique index.
|
||||
*/
|
||||
boolean unique() default false;
|
||||
|
||||
/**
|
||||
* When placed on the class (rather than field) you can specify the columns
|
||||
* to include in the index in order.
|
||||
*/
|
||||
String[] columnNames() default {};
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Marks an entity bean as being included in read auditing.
|
||||
*/
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ReadAudit {
|
||||
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import java.util.Arrays;
|
||||
/**
|
||||
* Represent the call stack (stack trace elements).
|
||||
* <p>
|
||||
* Used with a query to identify a CallStackQuery for AutoFetch automatic query
|
||||
* Used with a query to identify a CallStackQuery for AutoTune automatic query
|
||||
* tuning.
|
||||
* </p>
|
||||
* <p>
|
||||
@@ -26,16 +26,12 @@ public final class CallStack implements Serializable {
|
||||
|
||||
private final StackTraceElement[] callStack;
|
||||
|
||||
public CallStack(StackTraceElement[] callStack) {
|
||||
public CallStack(StackTraceElement[] callStack, int zeroHash, int pathHash) {
|
||||
this.callStack = callStack;
|
||||
this.zeroHash = enc(callStack[0].hashCode());
|
||||
int hc = 0;
|
||||
for (int i = 1; i < callStack.length; i++) {
|
||||
hc = 31 * hc + callStack[i].hashCode();
|
||||
}
|
||||
this.pathHash = enc(hc);
|
||||
this.zeroHash = enc(zeroHash);
|
||||
this.pathHash = enc(pathHash);
|
||||
}
|
||||
|
||||
|
||||
public int hashCode() {
|
||||
int hc = 0;
|
||||
for (int i = 0; i < callStack.length; i++) {
|
||||
@@ -87,8 +83,19 @@ public final class CallStack implements Serializable {
|
||||
return zeroHash + ":" + pathHash + ":" + callStack[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the call stack lines appended with the given newLine string.
|
||||
*/
|
||||
public String description(String newLine) {
|
||||
StringBuilder sb = new StringBuilder(400);
|
||||
for (int i = 0; i < callStack.length; i++) {
|
||||
sb.append(callStack[i].toString()).append(newLine);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String getOriginKey(int queryHash) {
|
||||
return zeroHash + "." + enc(queryHash) + "." + pathHash;
|
||||
return enc(queryHash)+ "." + zeroHash + "." + pathHash;
|
||||
}
|
||||
|
||||
private static final int radix = 1 << 6;
|
||||
|
||||
@@ -45,7 +45,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
/**
|
||||
* The actual entity bean that 'owns' this intercept.
|
||||
*/
|
||||
private EntityBean owner;
|
||||
private final EntityBean owner;
|
||||
|
||||
private EntityBean embeddedOwner;
|
||||
private int embeddedOwnerIndex;
|
||||
@@ -72,7 +72,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
/**
|
||||
* Used when a bean is partially filled.
|
||||
*/
|
||||
private boolean[] loadedProps;
|
||||
private final boolean[] loadedProps;
|
||||
|
||||
private boolean fullyLoadedBean;
|
||||
|
||||
@@ -449,7 +449,18 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
public int getPropertyLength() {
|
||||
return owner._ebean_getPropertyNames().length;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the loaded state of the property given it's name.
|
||||
*/
|
||||
public void setPropertyLoaded(String propertyName, boolean loaded) {
|
||||
int position = findProperty(propertyName);
|
||||
if (position == -1) {
|
||||
throw new IllegalArgumentException("Property "+propertyName+" not found");
|
||||
}
|
||||
loadedProps[position] = loaded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the property to be treated as unloaded. Used for properties initialised in default
|
||||
* constructor.
|
||||
@@ -581,7 +592,29 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return true if any of the given property names are dirty.
|
||||
*/
|
||||
public boolean hasDirtyProperty(Set<String> propertyNames) {
|
||||
|
||||
String[] names = owner._ebean_getPropertyNames();
|
||||
int len = getPropertyLength();
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (changedProps != null && changedProps[i]) {
|
||||
// the property has been changed on this bean
|
||||
if (propertyNames.contains(names[i])) {
|
||||
return true;
|
||||
}
|
||||
} else if (embeddedDirty != null && embeddedDirty[i]) {
|
||||
if (propertyNames.contains(names[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a map of dirty properties with their new and old values.
|
||||
*/
|
||||
@@ -891,7 +924,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), Boolean.valueOf(oldValue), Boolean.valueOf(newValue));
|
||||
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), oldValue, newValue);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -906,7 +939,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), Integer.valueOf(oldValue), Integer.valueOf(newValue));
|
||||
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), oldValue, newValue);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -922,7 +955,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), Long.valueOf(oldValue), Long.valueOf(newValue));
|
||||
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), oldValue, newValue);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -937,7 +970,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), Double.valueOf(oldValue), Double.valueOf(newValue));
|
||||
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), oldValue, newValue);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -952,7 +985,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), Float.valueOf(oldValue), Float.valueOf(newValue));
|
||||
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), oldValue, newValue);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -967,7 +1000,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), Short.valueOf(oldValue), Short.valueOf(newValue));
|
||||
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), oldValue, newValue);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -982,7 +1015,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), Character.valueOf(oldValue), Character.valueOf(newValue));
|
||||
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), oldValue, newValue);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -997,7 +1030,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), Byte.valueOf(oldValue), Byte.valueOf(newValue));
|
||||
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), oldValue, newValue);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package com.avaje.ebean.bean;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Collects profile information for a bean (or reference/proxy bean) at a given
|
||||
* AutoFetchNode.
|
||||
* Collects profile information for a bean (or reference/proxy bean) at a given node.
|
||||
* <p>
|
||||
* The AutoFetchNode identifies the location of the bean in the object graph.
|
||||
* The node identifies the location of the bean in the object graph.
|
||||
* </p>
|
||||
* <p>
|
||||
* It has to use a weak reference so as to ensure that it does not stop the
|
||||
@@ -29,7 +29,7 @@ public final class NodeUsageCollector {
|
||||
/**
|
||||
* The properties used at this profile point.
|
||||
*/
|
||||
private final HashSet<String> used = new HashSet<String>();
|
||||
private final Set<String> used = new LinkedHashSet<String>();
|
||||
|
||||
/**
|
||||
* set to true if the bean is modified (setter called)
|
||||
@@ -105,7 +105,7 @@ public final class NodeUsageCollector {
|
||||
/**
|
||||
* Return the set of used properties.
|
||||
*/
|
||||
public HashSet<String> getUsed() {
|
||||
public Set<String> getUsed() {
|
||||
return used;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ public interface NodeUsageListener {
|
||||
* Collect node usage "profiling" information.
|
||||
* <p>
|
||||
* This is the properties that are used for a given bean in the object graph.
|
||||
* This information is used by autoFetch to tune queries.
|
||||
* This information is used by autoTune to tune queries.
|
||||
* </p>
|
||||
*/
|
||||
void collectNodeUsage(NodeUsageCollector collector);
|
||||
|
||||
@@ -82,6 +82,7 @@ public final class ObjectGraphNode implements Serializable {
|
||||
}
|
||||
|
||||
ObjectGraphNode e = (ObjectGraphNode) obj;
|
||||
//noinspection StringEquality
|
||||
return ((e.path == path) || (e.path != null && e.path.equals(path)))
|
||||
&& e.originQueryPoint.equals(originQueryPoint);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import java.io.Serializable;
|
||||
* The call stack is included so that the query can have different tuned fetches
|
||||
* for each unique call stack. For example, a query to fetch a customer could be
|
||||
* called by three different methods and each can be treated as a separate
|
||||
* origin point (and autoFetch can tune each one separately).
|
||||
* origin point (and autoTune can tune each one separately).
|
||||
* </p>
|
||||
*/
|
||||
public final class ObjectGraphOrigin implements Serializable {
|
||||
|
||||
@@ -74,12 +74,12 @@ public interface PersistenceContext {
|
||||
* The bean was previously deleted from this persistence context (can't hit
|
||||
* L2 cache).
|
||||
*/
|
||||
public static WithOption DELETED = new WithOption(true);
|
||||
public static final WithOption DELETED = new WithOption();
|
||||
|
||||
private final boolean deleted;
|
||||
private final Object bean;
|
||||
|
||||
private WithOption(boolean deleted) {
|
||||
private WithOption() {
|
||||
this.deleted = true;
|
||||
this.bean = null;
|
||||
}
|
||||
|
||||
@@ -40,7 +40,8 @@ public class ServerCacheStatistics {
|
||||
protected long evictByLRU;
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
//noinspection StringBufferReplaceableByString
|
||||
StringBuilder sb = new StringBuilder(80);
|
||||
sb.append(cacheName);
|
||||
sb.append(" maxSize:").append(maxSize);
|
||||
sb.append(" size:").append(size);
|
||||
|
||||
@@ -343,41 +343,41 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
return list.remove(o);
|
||||
}
|
||||
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
public boolean removeAll(Collection<?> beans) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyRemoveListening) {
|
||||
boolean changed = false;
|
||||
Iterator<?> it = c.iterator();
|
||||
while (it.hasNext()) {
|
||||
Object o = it.next();
|
||||
if (list.remove(o)) {
|
||||
modifyRemoval(o);
|
||||
for (Object bean : beans) {
|
||||
if (list.remove(bean)) {
|
||||
// register this bean as having been removed
|
||||
modifyRemoval(bean);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
return list.removeAll(c);
|
||||
return list.removeAll(beans);
|
||||
}
|
||||
|
||||
public boolean retainAll(Collection<?> c) {
|
||||
public boolean retainAll(Collection<?> retainBeans) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyRemoveListening) {
|
||||
boolean changed = false;
|
||||
Iterator<E> it = list.iterator();
|
||||
while (it.hasNext()) {
|
||||
Object o = it.next();
|
||||
if (!c.contains(o)) {
|
||||
Object bean = it.next();
|
||||
if (!retainBeans.contains(bean)) {
|
||||
// removing this bean
|
||||
it.remove();
|
||||
modifyRemoval(o);
|
||||
modifyRemoval(bean);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
return list.retainAll(c);
|
||||
return list.retainAll(retainBeans);
|
||||
}
|
||||
|
||||
public E set(int index, E element) {
|
||||
@@ -415,6 +415,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
|
||||
public <T> T[] toArray(T[] a) {
|
||||
init();
|
||||
//noinspection SuspiciousToArrayCall
|
||||
return list.toArray(a);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
package com.avaje.ebean.common;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollectionLoader;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Map capable of lazy loading.
|
||||
*/
|
||||
@@ -148,8 +147,7 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
public Collection<E> getActualDetails() {
|
||||
return map.values();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the map entrySet.
|
||||
* <p>
|
||||
@@ -159,7 +157,6 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
*/
|
||||
public Collection<?> getActualEntries() {
|
||||
return map.entrySet();
|
||||
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
@@ -195,9 +192,9 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
checkReadOnly();
|
||||
initClear();
|
||||
if (modifyRemoveListening) {
|
||||
for (K key : map.keySet()) {
|
||||
E o = map.remove(key);
|
||||
modifyRemoval(o);
|
||||
// add all beans to the removal list
|
||||
for (E bean : map.values()) {
|
||||
modifyRemoval(bean);
|
||||
}
|
||||
}
|
||||
map.clear();
|
||||
@@ -249,27 +246,30 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyListening) {
|
||||
Object o = map.put(key, value);
|
||||
modifyAddition(value);
|
||||
modifyRemoval(o);
|
||||
Object oldBean = map.put(key, value);
|
||||
if (value != oldBean) {
|
||||
// register the add of the new and the removal of the old
|
||||
modifyAddition(value);
|
||||
modifyRemoval(oldBean);
|
||||
}
|
||||
}
|
||||
return map.put(key, value);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public void putAll(Map<? extends K, ? extends E> t) {
|
||||
public void putAll(Map<? extends K, ? extends E> puts) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyListening) {
|
||||
Iterator it = t.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Map.Entry entry = (Map.Entry) it.next();
|
||||
Object o = map.put((K) entry.getKey(), (E) entry.getValue());
|
||||
modifyAddition((E) entry.getValue());
|
||||
modifyRemoval(o);
|
||||
for (Entry<? extends K, ? extends E> entry : puts.entrySet()) {
|
||||
Object oldBean = map.put(entry.getKey(), entry.getValue());
|
||||
if (entry.getValue() != oldBean) {
|
||||
modifyAddition(entry.getValue());
|
||||
modifyRemoval(oldBean);
|
||||
}
|
||||
}
|
||||
}
|
||||
map.putAll(t);
|
||||
map.putAll(puts);
|
||||
}
|
||||
|
||||
public E remove(Object key) {
|
||||
|
||||
@@ -192,32 +192,29 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
|
||||
return set.add(o);
|
||||
}
|
||||
|
||||
public boolean addAll(Collection<? extends E> c) {
|
||||
public boolean addAll(Collection<? extends E> addCollection) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyAddListening) {
|
||||
boolean changed = false;
|
||||
Iterator<? extends E> it = c.iterator();
|
||||
while (it.hasNext()) {
|
||||
E o = it.next();
|
||||
if (set.add(o)) {
|
||||
modifyAddition(o);
|
||||
for (E bean : addCollection) {
|
||||
if (set.add(bean)) {
|
||||
// register the addition of the bean
|
||||
modifyAddition(bean);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
return set.addAll(c);
|
||||
return set.addAll(addCollection);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
checkReadOnly();
|
||||
initClear();
|
||||
if (modifyRemoveListening) {
|
||||
Iterator<E> it = set.iterator();
|
||||
while (it.hasNext()) {
|
||||
E e = it.next();
|
||||
modifyRemoval(e);
|
||||
for (E bean : set) {
|
||||
modifyRemoval(bean);
|
||||
}
|
||||
}
|
||||
set.clear();
|
||||
@@ -262,41 +259,40 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
|
||||
return set.remove(o);
|
||||
}
|
||||
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
public boolean removeAll(Collection<?> beans) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyRemoveListening) {
|
||||
boolean changed = false;
|
||||
Iterator<?> it = c.iterator();
|
||||
while (it.hasNext()) {
|
||||
Object o = it.next();
|
||||
if (set.remove(o)) {
|
||||
modifyRemoval(o);
|
||||
for (Object bean : beans) {
|
||||
if (set.remove(bean)) {
|
||||
modifyRemoval(bean);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
return set.removeAll(c);
|
||||
return set.removeAll(beans);
|
||||
}
|
||||
|
||||
public boolean retainAll(Collection<?> c) {
|
||||
public boolean retainAll(Collection<?> beans) {
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyRemoveListening) {
|
||||
boolean changed = false;
|
||||
Iterator<?> it = set.iterator();
|
||||
while (it.hasNext()) {
|
||||
Object o = it.next();
|
||||
if (!c.contains(o)) {
|
||||
Object bean = it.next();
|
||||
if (!beans.contains(bean)) {
|
||||
// not retaining this bean so add it to the removal list
|
||||
it.remove();
|
||||
modifyRemoval(o);
|
||||
modifyRemoval(bean);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
return set.retainAll(c);
|
||||
return set.retainAll(beans);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
@@ -311,6 +307,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
|
||||
|
||||
public <T> T[] toArray(T[] a) {
|
||||
init();
|
||||
//noinspection SuspiciousToArrayCall
|
||||
return set.toArray(a);
|
||||
}
|
||||
|
||||
|
||||
@@ -40,9 +40,7 @@ class ModifyCollection<E> implements Collection<E> {
|
||||
|
||||
public boolean addAll(Collection<? extends E> collection) {
|
||||
boolean changed = false;
|
||||
Iterator<? extends E> it = collection.iterator();
|
||||
while (it.hasNext()) {
|
||||
E o = it.next();
|
||||
for (E o : collection) {
|
||||
if (c.add(o)) {
|
||||
owner.modifyAddition(o);
|
||||
changed = true;
|
||||
@@ -51,27 +49,33 @@ class ModifyCollection<E> implements Collection<E> {
|
||||
return changed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
c.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
return c.contains(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(Collection<?> collection) {
|
||||
return c.containsAll(collection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return c.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<E> iterator() {
|
||||
Iterator<E> it = c.iterator();
|
||||
return new ModifyIterator<E>(owner, it);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
if (c.remove(o)) {
|
||||
owner.modifyRemoval(o);
|
||||
@@ -80,42 +84,47 @@ class ModifyCollection<E> implements Collection<E> {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> collection) {
|
||||
boolean changed = false;
|
||||
Iterator<?> it = collection.iterator();
|
||||
while (it.hasNext()) {
|
||||
Object o = (Object) it.next();
|
||||
if (c.remove(o)) {
|
||||
owner.modifyRemoval(o);
|
||||
for (Object bean : collection) {
|
||||
if (c.remove(bean)) {
|
||||
owner.modifyRemoval(bean);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> collection) {
|
||||
boolean changed = false;
|
||||
Iterator<?> it = c.iterator();
|
||||
while (it.hasNext()) {
|
||||
Object o = (Object) it.next();
|
||||
if (!collection.contains(o)) {
|
||||
Object bean = it.next();
|
||||
if (!collection.contains(bean)) {
|
||||
// not retaining this bean so add to removals
|
||||
it.remove();
|
||||
owner.modifyRemoval(o);
|
||||
owner.modifyRemoval(bean);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return c.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] toArray() {
|
||||
return c.toArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T[] toArray(T[] a) {
|
||||
//noinspection SuspiciousToArrayCall
|
||||
return c.toArray(a);
|
||||
}
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ class ModifyHolder<E> implements Serializable {
|
||||
void modifyRemoval(Object bean) {
|
||||
if (bean != null) {
|
||||
// If it is to be added then just remove the addition
|
||||
if (!modifyAdditions.remove((E) bean)) {
|
||||
if (!modifyAdditions.remove(bean)) {
|
||||
modifyDeletions.add((E) bean);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.avaje.ebean.common;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
|
||||
@@ -39,12 +38,10 @@ class ModifyList<E> extends ModifyCollection<E> implements List<E> {
|
||||
owner.modifyAddition(element);
|
||||
}
|
||||
|
||||
public boolean addAll(int index, Collection<? extends E> co) {
|
||||
if (list.addAll(index, co)) {
|
||||
Iterator<? extends E> it = co.iterator();
|
||||
while (it.hasNext()) {
|
||||
E o = it.next();
|
||||
owner.modifyAddition(o);
|
||||
public boolean addAll(int index, Collection<? extends E> addCollection) {
|
||||
if (list.addAll(index, addCollection)) {
|
||||
for (E bean : addCollection) {
|
||||
owner.modifyAddition(bean);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -67,9 +67,7 @@ class ModifyListIterator<E> implements ListIterator<E> {
|
||||
}
|
||||
|
||||
public void set(E o) {
|
||||
if (last == null) {
|
||||
// in theory this is not allowed
|
||||
} else {
|
||||
if (last != null) {
|
||||
owner.modifyRemoval(last);
|
||||
owner.modifyAddition(o);
|
||||
}
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
|
||||
import javax.persistence.Inheritance;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Provides some base implementation for NamingConventions.
|
||||
*
|
||||
@@ -14,31 +12,39 @@ import org.slf4j.LoggerFactory;
|
||||
*/
|
||||
public abstract class AbstractNamingConvention implements NamingConvention {
|
||||
|
||||
/** The Constant logger. */
|
||||
private static final Logger logger = LoggerFactory.getLogger(AbstractNamingConvention.class);
|
||||
|
||||
/** The Constant DEFAULT_SEQ_FORMAT. */
|
||||
/**
|
||||
* The Constant DEFAULT_SEQ_FORMAT.
|
||||
*/
|
||||
public static final String DEFAULT_SEQ_FORMAT = "{table}_seq";
|
||||
|
||||
/** Sequence Format that includes the Primary Key column */
|
||||
/**
|
||||
* Sequence Format that includes the Primary Key column
|
||||
*/
|
||||
public static final String TABLE_PKCOLUMN_SEQ_FORMAT = "{table}_{column}_seq";
|
||||
|
||||
/** The catalog. */
|
||||
/**
|
||||
* The catalog.
|
||||
*/
|
||||
private String catalog;
|
||||
|
||||
/** The schema. */
|
||||
/**
|
||||
* The schema.
|
||||
*/
|
||||
private String schema;
|
||||
|
||||
/** The sequence format. */
|
||||
/**
|
||||
* The sequence format.
|
||||
*/
|
||||
private String sequenceFormat;
|
||||
|
||||
/** The database platform. */
|
||||
/**
|
||||
* The database platform.
|
||||
*/
|
||||
protected DatabasePlatform databasePlatform;
|
||||
|
||||
/** The max length of constraint names. */
|
||||
protected int maxConstraintNameLength;
|
||||
|
||||
/** Used to trim off extra prefix for M2M. */
|
||||
/**
|
||||
* Used to trim off extra prefix for M2M.
|
||||
*/
|
||||
protected int rhsPrefixLength = 3;
|
||||
|
||||
protected boolean useForeignKeyPrefix;
|
||||
@@ -62,8 +68,7 @@ public abstract class AbstractNamingConvention implements NamingConvention {
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct with the default sequence format ("{table}_seq") and
|
||||
* useForeignKeyPrefix as true.
|
||||
* Construct with the default sequence format ("{table}_seq") and useForeignKeyPrefix as true.
|
||||
*/
|
||||
public AbstractNamingConvention() {
|
||||
this(DEFAULT_SEQ_FORMAT);
|
||||
@@ -71,9 +76,6 @@ public abstract class AbstractNamingConvention implements NamingConvention {
|
||||
|
||||
public void setDatabasePlatform(DatabasePlatform databasePlatform) {
|
||||
this.databasePlatform = databasePlatform;
|
||||
this.maxConstraintNameLength = databasePlatform.getDbDdlSyntax().getMaxConstraintNameLength();
|
||||
|
||||
logger.trace("Using maxConstraintNameLength of " + maxConstraintNameLength);
|
||||
}
|
||||
|
||||
public String getSequenceName(String tableName, String pkColumn) {
|
||||
@@ -218,11 +220,11 @@ public abstract class AbstractNamingConvention implements NamingConvention {
|
||||
}
|
||||
buffer.append(rhsTableName);
|
||||
|
||||
int maxConstraintNameLength = databasePlatform.getDbDdlSyntax().getMaxConstraintNameLength();
|
||||
int maxTableNameLength = databasePlatform.getMaxTableNameLength();
|
||||
|
||||
// maxConstraintNameLength is used as the max table name length.
|
||||
if (buffer.length() > maxConstraintNameLength) {
|
||||
buffer.setLength(maxConstraintNameLength);
|
||||
if (buffer.length() > maxTableNameLength) {
|
||||
buffer.setLength(maxTableNameLength);
|
||||
}
|
||||
|
||||
return new TableName(lhsTable.getCatalog(), lhsTable.getSchema(), buffer.toString());
|
||||
@@ -239,7 +241,7 @@ public abstract class AbstractNamingConvention implements NamingConvention {
|
||||
if (t != null && !isEmpty(t.name())) {
|
||||
// Note: empty catalog and schema are converted to null
|
||||
// Only need to convert quoted identifiers from annotations
|
||||
return new TableName(quoteIdentifiers(t.catalog()), quoteIdentifiers(t.schema()), quoteIdentifiers(t.name()));
|
||||
return new TableName(quoteIdentifiers(t.catalog()), quoteIdentifiers(t.schema()), quoteIdentifiers(t.name()));
|
||||
}
|
||||
|
||||
// No annotation
|
||||
@@ -272,10 +274,7 @@ public abstract class AbstractNamingConvention implements NamingConvention {
|
||||
* Checks string is null or empty .
|
||||
*/
|
||||
protected boolean isEmpty(String s) {
|
||||
if (s == null || s.trim().length() == 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return s == null || s.trim().length() == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,218 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
/**
|
||||
* Defines the AutoTune behaviour for a EbeanServer.
|
||||
*/
|
||||
public class AutoTuneConfig {
|
||||
|
||||
private AutoTuneMode mode = AutoTuneMode.DEFAULT_ON;
|
||||
|
||||
private String queryTuningFile = "ebean-autotune.xml";
|
||||
|
||||
private boolean queryTuning;
|
||||
|
||||
private boolean queryTuningAddVersion;
|
||||
|
||||
private boolean profiling;
|
||||
|
||||
private String profilingFile = "ebean-profiling";
|
||||
|
||||
private int profilingBase = 5;
|
||||
|
||||
private double profilingRate = 0.01;
|
||||
|
||||
private int garbageCollectionWait = 100;
|
||||
|
||||
private boolean skipCollectionOnShutdown;
|
||||
|
||||
public AutoTuneConfig() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the file that holds the query tuning information.
|
||||
*/
|
||||
public String getQueryTuningFile() {
|
||||
return queryTuningFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the file that holds the query tuning information.
|
||||
*/
|
||||
public void setQueryTuningFile(String queryTuningFile) {
|
||||
this.queryTuningFile = queryTuningFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the file that profiling information is written to.
|
||||
*/
|
||||
public String getProfilingFile() {
|
||||
return profilingFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the file that profiling information is written to.
|
||||
*/
|
||||
public void setProfilingFile(String profilingFile) {
|
||||
this.profilingFile = profilingFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the mode used when autoTune has not been explicit defined on a
|
||||
* query.
|
||||
*/
|
||||
public AutoTuneMode getMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the mode used when autoTune has not been explicit defined on a query.
|
||||
*/
|
||||
public void setMode(AutoTuneMode mode) {
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the queries are being tuned.
|
||||
*/
|
||||
public boolean isQueryTuning() {
|
||||
return queryTuning;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if the queries should be tuned by autoTune.
|
||||
*/
|
||||
public void setQueryTuning(boolean queryTuning) {
|
||||
this.queryTuning = queryTuning;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the version property should be added when the query is
|
||||
* tuned.
|
||||
* <p>
|
||||
* If this is false then the version property will be added when profiling
|
||||
* detects that the bean is possibly going to be modified.
|
||||
* </p>
|
||||
*/
|
||||
public boolean isQueryTuningAddVersion() {
|
||||
return queryTuningAddVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true to force the version property to be always added by the query
|
||||
* tuning.
|
||||
* <p>
|
||||
* If this is false then the version property will be added when profiling
|
||||
* detects that the bean is possibly going to be modified.
|
||||
* </p>
|
||||
* <p>
|
||||
* Generally this is not expected to be turned on.
|
||||
* </p>
|
||||
*/
|
||||
public void setQueryTuningAddVersion(boolean queryTuningAddVersion) {
|
||||
this.queryTuningAddVersion = queryTuningAddVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if profiling information should be collected.
|
||||
*/
|
||||
public boolean isProfiling() {
|
||||
return profiling;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if profiling information should be collected.
|
||||
* <p>
|
||||
* The profiling information is collected and then used to generate the tuned
|
||||
* queries for autoTune.
|
||||
* </p>
|
||||
*/
|
||||
public void setProfiling(boolean profiling) {
|
||||
this.profiling = profiling;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the base number of queries to profile before changing to profile
|
||||
* only a percentage of following queries (profileRate).
|
||||
*/
|
||||
public int getProfilingBase() {
|
||||
return profilingBase;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the based number of queries to profile.
|
||||
*/
|
||||
public void setProfilingBase(int profilingBase) {
|
||||
this.profilingBase = profilingBase;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the rate (%) of queries to be profiled after the 'base' amount of
|
||||
* profiling.
|
||||
*/
|
||||
public double getProfilingRate() {
|
||||
return profilingRate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the rate (%) of queries to be profiled after the 'base' amount of
|
||||
* profiling.
|
||||
*/
|
||||
public void setProfilingRate(double profilingRate) {
|
||||
this.profilingRate = profilingRate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the time in millis to wait after a system gc to collect profiling
|
||||
* information.
|
||||
* <p>
|
||||
* The profiling information is collected on object finalise. As such we
|
||||
* generally don't want to trigger GC (let the JVM do its thing) but on
|
||||
* shutdown the autoTune manager will trigger System.gc() and then wait
|
||||
* (default 100 millis) to hopefully collect profiling information -
|
||||
* especially for short run unit tests.
|
||||
* </p>
|
||||
*/
|
||||
public int getGarbageCollectionWait() {
|
||||
return garbageCollectionWait;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the time in millis to wait after a System.gc() to collect profiling information.
|
||||
*/
|
||||
public void setGarbageCollectionWait(int garbageCollectionWait) {
|
||||
this.garbageCollectionWait = garbageCollectionWait;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if profiling collection should be skipped on shutdown.
|
||||
*/
|
||||
public boolean isSkipCollectionOnShutdown() {
|
||||
return skipCollectionOnShutdown;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if profiling collection should be skipped on shutdown.
|
||||
*/
|
||||
public void setSkipCollectionOnShutdown(boolean skipCollectionOnShutdown) {
|
||||
this.skipCollectionOnShutdown = skipCollectionOnShutdown;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the settings from the properties file.
|
||||
*/
|
||||
public void loadSettings(PropertiesWrapper p) {
|
||||
|
||||
queryTuning = p.getBoolean("autoTune.queryTuning", queryTuning);
|
||||
queryTuningAddVersion = p.getBoolean("autoTune.queryTuningAddVersion", queryTuningAddVersion);
|
||||
queryTuningFile = p.get("autoTune.queryTuningFile", queryTuningFile);
|
||||
|
||||
skipCollectionOnShutdown = p.getBoolean("autoTune.skipCollectionOnShutdown", skipCollectionOnShutdown);
|
||||
|
||||
mode = p.getEnum(AutoTuneMode.class, "autoTune.mode", mode);
|
||||
|
||||
profiling = p.getBoolean("autoTune.profiling", profiling);
|
||||
profilingBase = p.getInt("autoTune.profilingBase", profilingBase);
|
||||
profilingRate = p.getDouble("autoTune.profilingRate", profilingRate);
|
||||
profilingFile = p.get("autoTune.profilingFile", profilingFile);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
import com.avaje.ebean.Query;
|
||||
|
||||
/**
|
||||
* The mode for determining if AutoTune will be used for a given query when
|
||||
* {@link Query#setAutoTune(boolean)} has not been explicitly set on a query.
|
||||
* <p>
|
||||
* The explicit control of {@link Query#setAutoTune(boolean)} will always take
|
||||
* precedence. This mode is used when this has not been explicitly set on a
|
||||
* query.
|
||||
* </p>
|
||||
*/
|
||||
public enum AutoTuneMode {
|
||||
|
||||
/**
|
||||
* Don't implicitly use AutoTune. Must explicitly turn it on.
|
||||
*/
|
||||
DEFAULT_OFF,
|
||||
|
||||
/**
|
||||
* Use AutoTune implicitly. Must explicitly turn it off.
|
||||
*/
|
||||
DEFAULT_ON,
|
||||
|
||||
/**
|
||||
* Implicitly use AutoTune if the query has not got either select() or join()
|
||||
* defined.
|
||||
*/
|
||||
DEFAULT_ONIFEMPTY
|
||||
|
||||
}
|
||||
@@ -1,245 +0,0 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
/**
|
||||
* Defines the Autofetch behaviour for a EbeanServer.
|
||||
*/
|
||||
public class AutofetchConfig {
|
||||
|
||||
private AutofetchMode mode = AutofetchMode.DEFAULT_ONIFEMPTY;
|
||||
|
||||
private boolean queryTuning = false;
|
||||
|
||||
private boolean queryTuningAddVersion = false;
|
||||
|
||||
private boolean profiling = false;
|
||||
|
||||
private int profilingMin = 1;
|
||||
|
||||
private int profilingBase = 10;
|
||||
|
||||
private double profilingRate = 0.05;
|
||||
|
||||
private String logDirectory;
|
||||
|
||||
private int profileUpdateFrequency = 60;
|
||||
|
||||
private int garbageCollectionWait = 100;
|
||||
|
||||
private boolean garbageCollectionOnShutdown;
|
||||
|
||||
public AutofetchConfig() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the mode used when autofetch has not been explicit defined on a
|
||||
* query.
|
||||
*/
|
||||
public AutofetchMode getMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the mode used when autofetch has not been explicit defined on a query.
|
||||
*/
|
||||
public void setMode(AutofetchMode mode) {
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the queries are being tuned.
|
||||
*/
|
||||
public boolean isQueryTuning() {
|
||||
return queryTuning;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if the queries should be tuned by autofetch.
|
||||
*/
|
||||
public void setQueryTuning(boolean queryTuning) {
|
||||
this.queryTuning = queryTuning;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the version property should be added when the query is
|
||||
* tuned.
|
||||
* <p>
|
||||
* If this is false then the version property will be added when profiling
|
||||
* detects that the bean is possibly going to be modified.
|
||||
* </p>
|
||||
*/
|
||||
public boolean isQueryTuningAddVersion() {
|
||||
return queryTuningAddVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true to force the version property to be always added by the query
|
||||
* tuning.
|
||||
* <p>
|
||||
* If this is false then the version property will be added when profiling
|
||||
* detects that the bean is possibly going to be modified.
|
||||
* </p>
|
||||
*/
|
||||
public void setQueryTuningAddVersion(boolean queryTuningAddVersion) {
|
||||
this.queryTuningAddVersion = queryTuningAddVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if profiling information should be collected.
|
||||
*/
|
||||
public boolean isProfiling() {
|
||||
return profiling;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if profiling information should be collected.
|
||||
* <p>
|
||||
* The profiling information is collected and then used to generate the tuned
|
||||
* queries for autofetch.
|
||||
* </p>
|
||||
*/
|
||||
public void setProfiling(boolean profiling) {
|
||||
this.profiling = profiling;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the minimum number of queries to profile before autofetch will start
|
||||
* tuning the queries.
|
||||
*/
|
||||
public int getProfilingMin() {
|
||||
return profilingMin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the minimum number of queries to profile before autofetch will start
|
||||
* tuning the queries.
|
||||
*/
|
||||
public void setProfilingMin(int profilingMin) {
|
||||
this.profilingMin = profilingMin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the base number of queries to profile before changing to profile
|
||||
* only a percentage of following queries (profileRate).
|
||||
*/
|
||||
public int getProfilingBase() {
|
||||
return profilingBase;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the based number of queries to profile.
|
||||
*/
|
||||
public void setProfilingBase(int profilingBase) {
|
||||
this.profilingBase = profilingBase;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the rate (%) of queries to be profiled after the 'base' amount of
|
||||
* profiling.
|
||||
*/
|
||||
public double getProfilingRate() {
|
||||
return profilingRate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the rate (%) of queries to be profiled after the 'base' amount of
|
||||
* profiling.
|
||||
*/
|
||||
public void setProfilingRate(double profilingRate) {
|
||||
this.profilingRate = profilingRate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the log directory to put the autofetch log.
|
||||
*/
|
||||
public String getLogDirectory() {
|
||||
return logDirectory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the directory to put the autofetch log in.
|
||||
*/
|
||||
public void setLogDirectory(String logDirectory) {
|
||||
this.logDirectory = logDirectory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the frequency in seconds to update the autofetch tuned queries from
|
||||
* the profiled information.
|
||||
*/
|
||||
public int getProfileUpdateFrequency() {
|
||||
return profileUpdateFrequency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the frequency in seconds to update the autofetch tuned queries from the
|
||||
* profiled information.
|
||||
*/
|
||||
public void setProfileUpdateFrequency(int profileUpdateFrequency) {
|
||||
this.profileUpdateFrequency = profileUpdateFrequency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the time in millis to wait after a system gc to collect profiling
|
||||
* information.
|
||||
* <p>
|
||||
* The profiling information is collected on object finalise. As such we
|
||||
* generally don't want to trigger GC (let the JVM do its thing) but on
|
||||
* shutdown the autofetch manager will trigger System.gc() and then wait
|
||||
* (default 100 millis) to hopefully collect profiling information -
|
||||
* especially for short run unit tests.
|
||||
* </p>
|
||||
*/
|
||||
public int getGarbageCollectionWait() {
|
||||
return garbageCollectionWait;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the time in millis to wait after a System.gc() to collect profiling
|
||||
* information.
|
||||
*/
|
||||
public void setGarbageCollectionWait(int garbageCollectionWait) {
|
||||
this.garbageCollectionWait = garbageCollectionWait;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return true if GC should be trigger on shutdown.
|
||||
* <p>
|
||||
* Autofetch profiling information is collected as part of garbage collection.
|
||||
* </p>
|
||||
*/
|
||||
public boolean isGarbageCollectionOnShutdown() {
|
||||
return garbageCollectionOnShutdown;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if you want GC to trigger on shutdown.
|
||||
* <p>
|
||||
* This would be done if you want to try and collect Autofetch profiling information
|
||||
* on shutdown.
|
||||
* </p>
|
||||
*/
|
||||
public void setGarbageCollectionOnShutdown(boolean garbageCollectionOnShutdown) {
|
||||
this.garbageCollectionOnShutdown = garbageCollectionOnShutdown;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the settings from the properties file.
|
||||
*/
|
||||
public void loadSettings(PropertiesWrapper p) {
|
||||
|
||||
logDirectory = p.get("autofetch.logDirectory", logDirectory);
|
||||
queryTuning = p.getBoolean("autofetch.querytuning", queryTuning);
|
||||
queryTuningAddVersion = p.getBoolean("autofetch.queryTuningAddVersion", queryTuningAddVersion);
|
||||
garbageCollectionOnShutdown = p.getBoolean("autofetch.garbageCollectionOnShutdown", garbageCollectionOnShutdown);
|
||||
|
||||
profiling = p.getBoolean("autofetch.profiling", profiling);
|
||||
mode = p.getEnum(AutofetchMode.class, "autofetch.implicitmode", mode);
|
||||
|
||||
profilingMin = p.getInt("autofetch.profiling.min", profilingMin);
|
||||
profilingBase = p.getInt("autofetch.profiling.base", profilingBase);
|
||||
|
||||
profilingRate = p.getDouble("autofetch.profiling.rate", profilingRate);
|
||||
profileUpdateFrequency = p.getInt("autofetch.profiling.updatefrequency", profileUpdateFrequency);
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
import com.avaje.ebean.Query;
|
||||
|
||||
/**
|
||||
* The mode for determining if Autofetch will be used for a given query when
|
||||
* {@link Query#setAutofetch(boolean)} has not been explicitly set on a query.
|
||||
* <p>
|
||||
* The explicit control of {@link Query#setAutofetch(boolean)} will always take
|
||||
* precedence. This mode is used when this has not been explicitly set on a
|
||||
* query.
|
||||
* </p>
|
||||
*/
|
||||
public enum AutofetchMode {
|
||||
|
||||
/**
|
||||
* Don't implicitly use Autofetch. Must explicitly turn it on.
|
||||
*/
|
||||
DEFAULT_OFF,
|
||||
|
||||
/**
|
||||
* Use Autofetch implicitly. Must explicitly turn it off.
|
||||
*/
|
||||
DEFAULT_ON,
|
||||
|
||||
/**
|
||||
* Implicitly use Autofetch if the query has not got either select() or join()
|
||||
* defined.
|
||||
*/
|
||||
DEFAULT_ONIFEMPTY
|
||||
|
||||
}
|
||||
@@ -507,8 +507,7 @@ public class DataSourceConfig {
|
||||
|
||||
String customProperties = properties.get("customProperties", null);
|
||||
if (customProperties != null && customProperties.length() > 0) {
|
||||
Map<String, String> custProps = StringHelper.delimitedToMap(customProperties, ";", "=");
|
||||
this.customProperties = custProps;
|
||||
this.customProperties = StringHelper.delimitedToMap(customProperties, ";", "=");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,209 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
/**
|
||||
* Naming convention used for constraint names.
|
||||
* <p>
|
||||
* Note that these constraint names are trimmed in the PlatformDdl which can be overridden
|
||||
* but provides a decent default implementation.
|
||||
* </p>
|
||||
*/
|
||||
public class DbConstraintNaming {
|
||||
|
||||
/**
|
||||
* Defines how constraint names are shortened if required based on platform limitations.
|
||||
*/
|
||||
public interface MaxLength {
|
||||
|
||||
/**
|
||||
* Truncate or shorten the constraint name to support DB platform limitations.
|
||||
* <p>
|
||||
* There is a default implementation of this which is used if an implementation is
|
||||
* not specified.
|
||||
* </p>
|
||||
*/
|
||||
String maxLength(String constraintName, int count);
|
||||
}
|
||||
|
||||
protected String pkPrefix = "pk_";
|
||||
protected String pkSuffix = "";
|
||||
|
||||
protected String fkPrefix = "fk_";
|
||||
protected String fkMiddle = "_";
|
||||
protected String fkSuffix = "";
|
||||
|
||||
protected String fkIndexPrefix = "ix_";
|
||||
protected String fkIndexMiddle = "_";
|
||||
protected String fkIndexSuffix = "";
|
||||
|
||||
protected String indexPrefix = "ix_";
|
||||
protected String indexMiddle = "_";
|
||||
protected String indexSuffix = "";
|
||||
|
||||
protected String uqPrefix = "uq_";
|
||||
protected String uqSuffix = "";
|
||||
|
||||
protected String ckPrefix = "ck_";
|
||||
protected String ckSuffix = "";
|
||||
|
||||
protected MaxLength maxLength;
|
||||
|
||||
protected DbConstraintNormalise normalise;
|
||||
|
||||
/**
|
||||
* Construct using default of lower case for both table and column names.
|
||||
*/
|
||||
public DbConstraintNaming() {
|
||||
this(true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct specifying if lower case should be used (for both table and column names).
|
||||
*/
|
||||
public DbConstraintNaming(boolean lowerCase) {
|
||||
this(lowerCase, lowerCase);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct specifying if lower case should be used for both table and column names.
|
||||
*/
|
||||
public DbConstraintNaming(boolean lowerCaseTableNames, boolean lowerCaseColumnNames) {
|
||||
this.normalise = new DbConstraintNormalise(lowerCaseTableNames, lowerCaseColumnNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the MaxLength implementation used to truncate/shorten db constraint names as necessary.
|
||||
*/
|
||||
public MaxLength getMaxLength() {
|
||||
return maxLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the MaxLength implementation used to truncate/shorten db constraint names as necessary.
|
||||
*/
|
||||
public void setMaxLength(MaxLength maxLength) {
|
||||
this.maxLength = maxLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the primary key constraint name.
|
||||
*/
|
||||
public String primaryKeyName(String tableName) {
|
||||
|
||||
return pkPrefix + normaliseTable(tableName) + pkSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the foreign key constraint name given a single column foreign key.
|
||||
*/
|
||||
public String foreignKeyConstraintName(String tableName, String columnName) {
|
||||
return fkPrefix + normaliseTable(tableName) + fkMiddle + normaliseColumn(columnName) + fkSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the index name associated with a foreign key constraint given multiple columns.
|
||||
*/
|
||||
public String foreignKeyIndexName(String tableName, String[] columns) {
|
||||
|
||||
String colPart = joinColumnNames(columns);
|
||||
return fkIndexPrefix + normaliseTable(tableName) + fkIndexMiddle + colPart + fkIndexSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the index name associated with a foreign key constraint given a single column foreign key.
|
||||
*/
|
||||
public String foreignKeyIndexName(String tableName, String column) {
|
||||
|
||||
String colPart = normaliseTable(column);
|
||||
return fkIndexPrefix + normaliseTable(tableName) + fkIndexMiddle + colPart + fkIndexSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the index name for a general index (not associated with a foreign key).
|
||||
*/
|
||||
public String indexName(String tableName, String column) {
|
||||
|
||||
String colPart = normaliseTable(column);
|
||||
return indexPrefix + normaliseTable(tableName) + indexMiddle + colPart + indexSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the index name for a general index (not associated with a foreign key).
|
||||
*/
|
||||
public String indexName(String tableName, String[] columns) {
|
||||
|
||||
String colPart = joinColumnNames(columns);
|
||||
return indexPrefix + normaliseTable(tableName) + indexMiddle + colPart + indexSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Join the column names together with underscores.
|
||||
*/
|
||||
protected String joinColumnNames(String[] columns) {
|
||||
|
||||
if (columns.length == 1) {
|
||||
return normaliseColumn(columns[0]);
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < columns.length; i++) {
|
||||
if (i > 0) {
|
||||
sb.append("_");
|
||||
}
|
||||
sb.append(normaliseColumn(columns[i]));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the unique constraint name.
|
||||
*/
|
||||
public String uniqueConstraintName(String tableName, String columnName) {
|
||||
|
||||
return uqPrefix + normaliseTable(tableName) + "_" + normaliseColumn(columnName) + uqSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the unique constraint name.
|
||||
*/
|
||||
public String uniqueConstraintName(String tableName, String[] columns) {
|
||||
|
||||
String colPart = joinColumnNames(columns);
|
||||
return uqPrefix + normaliseTable(tableName) + "_" + colPart + uqSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the check constraint name.
|
||||
*/
|
||||
public String checkConstraintName(String tableName, String columnName) {
|
||||
|
||||
return ckPrefix + normaliseTable(tableName) + "_" + normaliseColumn(columnName) + ckSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalise the table name by trimming catalog and schema and removing any
|
||||
* quoted identifier characters (",',[,] etc).
|
||||
*/
|
||||
public String normaliseTable(String tableName) {
|
||||
return normalise.normaliseTable(tableName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalise the column name by removing any quoted identifier characters (",',[,] etc).
|
||||
*/
|
||||
public String normaliseColumn(String tableName) {
|
||||
return normalise.normaliseColumn(tableName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lower case the table name checking for quoted identifiers.
|
||||
*/
|
||||
public String lowerTableName(String tableName) {
|
||||
return normalise.lowerTableName(tableName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lower case the column name checking for quoted identifiers.
|
||||
*/
|
||||
public String lowerColumnName(String name) {
|
||||
return normalise.lowerColumnName(name);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
/**
|
||||
* Used to normalise table and column names which means stripping out
|
||||
* quoted identifier characters and any catalog or schema prefix.
|
||||
*/
|
||||
public class DbConstraintNormalise {
|
||||
|
||||
protected final String[] quotedIdentifiers;
|
||||
|
||||
protected final boolean lowerCaseTables;
|
||||
|
||||
protected final boolean lowerCaseColumns;
|
||||
|
||||
public DbConstraintNormalise() {
|
||||
this(true, true);
|
||||
}
|
||||
|
||||
public DbConstraintNormalise(boolean lowerCaseTables, boolean lowerCaseColumns) {
|
||||
this.lowerCaseTables = lowerCaseTables;
|
||||
this.lowerCaseColumns = lowerCaseColumns;
|
||||
this.quotedIdentifiers = new String[]{"\"", "'", "[", "]", "`"};
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalise the table name by trimming catalog and schema and removing any
|
||||
* quoted identifier characters (",',[,] etc).
|
||||
*/
|
||||
public String normaliseTable(String tableName) {
|
||||
|
||||
tableName = trimQuotes(tableName);
|
||||
int lastPeriod = tableName.lastIndexOf('.');
|
||||
if (lastPeriod > -1) {
|
||||
// trim off catalog and schema prefix
|
||||
tableName = tableName.substring(lastPeriod + 1);
|
||||
}
|
||||
if (lowerCaseTables) {
|
||||
tableName = tableName.toLowerCase();
|
||||
}
|
||||
return tableName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalise the column name by removing any quoted identifier characters.
|
||||
*/
|
||||
public String normaliseColumn(String columnName) {
|
||||
|
||||
columnName = trimQuotes(columnName);
|
||||
if (lowerCaseColumns) {
|
||||
columnName = columnName.toLowerCase();
|
||||
}
|
||||
return columnName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lower case the table name checking for quoted identifiers.
|
||||
*/
|
||||
public String lowerTableName(String tableName) {
|
||||
if (lowerCaseTables && notQuoted(tableName)) {
|
||||
return tableName.toLowerCase();
|
||||
}
|
||||
return tableName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lower case the column name checking for quoted identifiers.
|
||||
*/
|
||||
public String lowerColumnName(String name) {
|
||||
if (lowerCaseColumns && notQuoted(name)) {
|
||||
return name.toLowerCase();
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trim off the platform quoted identifier quotes like [ ' and ".
|
||||
*/
|
||||
public boolean notQuoted(String tableName) {
|
||||
|
||||
// remove quoted identifier characters
|
||||
for (int i = 0; i < quotedIdentifiers.length; i++) {
|
||||
if (tableName.contains(quotedIdentifiers[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trim off the platform quoted identifier quotes like [ ' and ".
|
||||
*/
|
||||
public String trimQuotes(String tableName) {
|
||||
|
||||
if (tableName == null) {
|
||||
return "";
|
||||
}
|
||||
// remove quoted identifier characters
|
||||
for (int i = 0; i < quotedIdentifiers.length; i++) {
|
||||
tableName = tableName.replace(quotedIdentifiers[i], "");
|
||||
}
|
||||
return tableName;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
/**
|
||||
* Configuration for the DB migration processing.
|
||||
*/
|
||||
public class DbMigrationConfig {
|
||||
|
||||
/**
|
||||
* Resource path for the migration xml and sql.
|
||||
* Typically you would change 'app' to be a better/more unique.
|
||||
*/
|
||||
private String resourcePath = "dbmigration/app";
|
||||
|
||||
/**
|
||||
* Return the resource path for db migrations.
|
||||
*/
|
||||
public String getResourcePath() {
|
||||
return resourcePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the resource path for db migrations.
|
||||
* <p>
|
||||
* Typically this would be something like "dbmigration/myapp" where myapp gives it a
|
||||
* unique resource path in the case there are multiple EbeanServer applications in the
|
||||
* single classpath.
|
||||
* </p>
|
||||
*/
|
||||
public void setResourcePath(String resourcePath) {
|
||||
this.resourcePath = resourcePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the settings from the PropertiesWrapper.
|
||||
*/
|
||||
public void loadSettings(PropertiesWrapper properties) {
|
||||
resourcePath = properties.get("migration.resourcePath", resourcePath);
|
||||
}
|
||||
}
|
||||
@@ -82,8 +82,7 @@ public interface NamingConvention {
|
||||
String getPropertyFromColumn(Class<?> beanClass, String dbColumnName);
|
||||
|
||||
/**
|
||||
* Return the sequence name given the table name (for DB's that use
|
||||
* sequences).
|
||||
* Return the sequence name given the table name (for DB's that use sequences).
|
||||
* <p>
|
||||
* Typically you might append "_seq" to the table name as an example.
|
||||
* </p>
|
||||
@@ -99,14 +98,14 @@ public interface NamingConvention {
|
||||
* Return true if a prefix should be used building a foreign key name.
|
||||
* <p>
|
||||
* This by default is true and this works well when the primary key column
|
||||
* names are simply "ID". In this case a prefix (such as "ORDER" and
|
||||
* "CUSTOMER" etc) is added to the foreign key column producing "ORDER_ID" and
|
||||
* "CUSTOMER_ID".
|
||||
* names are simply "id". In this case a prefix (such as "order" and
|
||||
* "customer" etc) is added to the foreign key column producing "order_id" and
|
||||
* "customer_id".
|
||||
* </p>
|
||||
* <p>
|
||||
* This should return false when your primary key columns are the same as the
|
||||
* foreign key columns. For example, when the primary key columns are
|
||||
* "ORDER_ID", "CUST_ID" etc ... and they are the same as the foreign key
|
||||
* "order_id", "cust_id" etc ... and they are the same as the foreign key
|
||||
* column names.
|
||||
* </p>
|
||||
*/
|
||||
|
||||
@@ -36,7 +36,7 @@ public enum PersistBatch {
|
||||
INHERIT(false);
|
||||
|
||||
|
||||
boolean forInsert;
|
||||
final boolean forInsert;
|
||||
|
||||
PersistBatch(boolean forInsert) {
|
||||
this.forInsert = forInsert;
|
||||
|
||||
@@ -27,12 +27,12 @@ final class PropertyExpression {
|
||||
/**
|
||||
* Used to detect the start of an expression.
|
||||
*/
|
||||
private static String START = "${";
|
||||
private static final String START = "${";
|
||||
|
||||
/**
|
||||
* Used to detect the end of an expression.
|
||||
*/
|
||||
private static String END = "}";
|
||||
private static final String END = "}";
|
||||
|
||||
/**
|
||||
* Specify the PropertyHolder.
|
||||
@@ -144,13 +144,7 @@ final class PropertyExpression {
|
||||
}
|
||||
|
||||
private static boolean isJndiExpression(String exp) {
|
||||
if (exp.startsWith("JNDI:")) {
|
||||
return true;
|
||||
}
|
||||
if (exp.startsWith("jndi:")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return exp.startsWith("JNDI:") || exp.startsWith("jndi:");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,7 +16,15 @@ public final class PropertyMap implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
|
||||
private final LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
|
||||
|
||||
/**
|
||||
* Return properties loaded from test-ebean.properties.
|
||||
*/
|
||||
public static Properties testProperties() {
|
||||
PropertyMap propertyMap = PropertyMapLoader.loadTestProperties();
|
||||
return (propertyMap == null) ? new Properties() : propertyMap.asProperties();
|
||||
}
|
||||
|
||||
public static Properties defaultProperties() {
|
||||
PropertyMap propertyMap = PropertyMapLoader.loadGlobalProperties();
|
||||
|
||||
@@ -14,17 +14,34 @@ final class PropertyMapLoader {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PropertyMapLoader.class);
|
||||
|
||||
/**
|
||||
* Load the <code>test-ebean.properties</code>.
|
||||
*/
|
||||
public static PropertyMap loadTestProperties() {
|
||||
return load(null, "test-ebean.properties", false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the ebean.properties (and test-ebean.properties if present).
|
||||
*/
|
||||
public static PropertyMap loadGlobalProperties() {
|
||||
|
||||
boolean loadTestProperties = false;
|
||||
String fileName = System.getenv("EBEAN_PROPS_FILE");
|
||||
if (fileName == null) {
|
||||
fileName = System.getProperty("ebean.props.file");
|
||||
if (fileName == null) {
|
||||
loadTestProperties = true;
|
||||
fileName = "ebean.properties";
|
||||
}
|
||||
}
|
||||
|
||||
return load(null, fileName);
|
||||
PropertyMap map = load(null, fileName, true);
|
||||
if (loadTestProperties) {
|
||||
// load test properties if present in classpath
|
||||
load(map, "test-ebean.properties", false);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -35,11 +52,13 @@ final class PropertyMapLoader {
|
||||
* @param fileName
|
||||
* the name of the properties file to load.
|
||||
*/
|
||||
public static PropertyMap load(PropertyMap p, String fileName) {
|
||||
public static PropertyMap load(PropertyMap p, String fileName, boolean errorOnNull) {
|
||||
|
||||
InputStream is = findInputStream(fileName);
|
||||
if (is == null) {
|
||||
logger.error(fileName + " not found");
|
||||
if (errorOnNull) {
|
||||
logger.error(fileName + " not found");
|
||||
}
|
||||
return p;
|
||||
} else {
|
||||
return load(p, is);
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
|
||||
/**
|
||||
* Unwrap the PreparedStatement to get the specific underlying implementation.
|
||||
* <p>
|
||||
* This is used to handle specific JDBC driver issues. Typically this means
|
||||
* getting the OraclePreparedStatement to handle Oracle specific issues etc.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public interface PstmtDelegate {
|
||||
|
||||
/**
|
||||
* Unwrap the PreparedStatement to get the specific underlying implementation.
|
||||
*
|
||||
* @param pstmt
|
||||
* the PreparedStatement coming out of the connection pool
|
||||
* @return the underlying PreparedStatement
|
||||
*/
|
||||
PreparedStatement unwrap(PreparedStatement pstmt);
|
||||
}
|
||||
@@ -8,6 +8,11 @@ import com.avaje.ebean.cache.ServerCacheManager;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebean.config.dbplatform.DbEncrypt;
|
||||
import com.avaje.ebean.event.*;
|
||||
import com.avaje.ebean.event.changelog.ChangeLogListener;
|
||||
import com.avaje.ebean.event.changelog.ChangeLogPrepare;
|
||||
import com.avaje.ebean.event.changelog.ChangeLogRegister;
|
||||
import com.avaje.ebean.event.readaudit.ReadAuditLogger;
|
||||
import com.avaje.ebean.event.readaudit.ReadAuditPrepare;
|
||||
import com.avaje.ebean.meta.MetaInfoManager;
|
||||
import com.avaje.ebean.util.ClassUtil;
|
||||
import com.fasterxml.jackson.core.JsonFactory;
|
||||
@@ -70,6 +75,11 @@ public class ServerConfig {
|
||||
|
||||
private ContainerConfig containerConfig;
|
||||
|
||||
/**
|
||||
* The underlying properties that were used during configuration.
|
||||
*/
|
||||
private Properties properties;
|
||||
|
||||
/**
|
||||
* The resource directory.
|
||||
*/
|
||||
@@ -120,9 +130,9 @@ public class ServerConfig {
|
||||
private CurrentUserProvider currentUserProvider;
|
||||
|
||||
/**
|
||||
* Config controlling the autofetch behaviour.
|
||||
* Config controlling the AutoTune behaviour.
|
||||
*/
|
||||
private AutofetchConfig autofetchConfig = new AutofetchConfig();
|
||||
private AutoTuneConfig autoTuneConfig = new AutoTuneConfig();
|
||||
|
||||
/**
|
||||
* The JSON format used for DateTime types. Default to millis.
|
||||
@@ -162,6 +172,12 @@ public class ServerConfig {
|
||||
*/
|
||||
private String asOfSysPeriod = "sys_period";
|
||||
|
||||
/**
|
||||
* Suffix appended to the base table to derive the view that contains the union
|
||||
* of the base table and the history table in order to support asOf queries.
|
||||
*/
|
||||
private String historyTableSuffix = "_history";
|
||||
|
||||
/**
|
||||
* Use for transaction scoped batch mode.
|
||||
*/
|
||||
@@ -198,11 +214,6 @@ public class ServerConfig {
|
||||
private ExternalTransactionManager externalTransactionManager;
|
||||
|
||||
/**
|
||||
* Used to unwrap PreparedStatements to perform JDBC Driver specific functions
|
||||
*/
|
||||
private PstmtDelegate pstmtDelegate;
|
||||
|
||||
/**
|
||||
* The data source (if programmatically provided).
|
||||
*/
|
||||
private DataSource dataSource;
|
||||
@@ -212,13 +223,23 @@ public class ServerConfig {
|
||||
*/
|
||||
private DataSourceConfig dataSourceConfig = new DataSourceConfig();
|
||||
|
||||
/**
|
||||
* The db migration config (migration resource path etc).
|
||||
*/
|
||||
private DbMigrationConfig migrationConfig = new DbMigrationConfig();
|
||||
|
||||
/**
|
||||
* Set to true if the DataSource uses autoCommit.
|
||||
* <p>
|
||||
* Indicates that Ebean should use autoCommit friendly Transactions and TransactionManager.
|
||||
*/
|
||||
private boolean autoCommitMode;
|
||||
|
||||
|
||||
/**
|
||||
* Set to true if transaction begin should be started with explicit statement.
|
||||
*/
|
||||
private boolean explicitTransactionBeginMode;
|
||||
|
||||
/**
|
||||
* The data source JNDI name if using a JNDI DataSource.
|
||||
*/
|
||||
@@ -239,6 +260,11 @@ public class ServerConfig {
|
||||
*/
|
||||
private NamingConvention namingConvention = new UnderscoreNamingConvention();
|
||||
|
||||
/**
|
||||
* Naming convention used in DDL generation for primary keys, foreign keys etc.
|
||||
*/
|
||||
private DbConstraintNaming constraintNaming = new DbConstraintNaming();
|
||||
|
||||
/**
|
||||
* Behaviour of update to include on the change properties.
|
||||
*/
|
||||
@@ -255,19 +281,35 @@ public class ServerConfig {
|
||||
private boolean updatesDeleteMissingChildren = true;
|
||||
|
||||
/**
|
||||
* Setting to indicate if UUID should be stored as binary(16) or varchar(40).
|
||||
* Setting to indicate if UUID should be stored as binary(16) or varchar(40) or native DB type (for H2 and Postgres).
|
||||
*/
|
||||
private boolean uuidStoreAsBinary;
|
||||
private DbUuid dbUuid = DbUuid.AUTO;
|
||||
|
||||
|
||||
private List<BeanFindController> findControllers = new ArrayList<BeanFindController>();
|
||||
private List<BeanPersistController> persistControllers = new ArrayList<BeanPersistController>();
|
||||
private List<BeanPostLoad> postLoaders = new ArrayList<BeanPostLoad>();
|
||||
private List<BeanPersistListener> persistListeners = new ArrayList<BeanPersistListener>();
|
||||
private List<BeanQueryAdapter> queryAdapters = new ArrayList<BeanQueryAdapter>();
|
||||
private List<BulkTableEventListener> bulkTableEventListeners = new ArrayList<BulkTableEventListener>();
|
||||
private List<ServerConfigStartup> configStartupListeners = new ArrayList<ServerConfigStartup>();
|
||||
private List<TransactionEventListener> transactionEventListeners = new ArrayList<TransactionEventListener>();
|
||||
|
||||
/**
|
||||
* By default inserts are included in the change log.
|
||||
*/
|
||||
private boolean changeLogIncludeInserts = true;
|
||||
|
||||
private ChangeLogPrepare changeLogPrepare;
|
||||
|
||||
private ChangeLogListener changeLogListener;
|
||||
|
||||
private ChangeLogRegister changeLogRegister;
|
||||
|
||||
private ReadAuditLogger readAuditLogger;
|
||||
|
||||
private ReadAuditPrepare readAuditPrepare;
|
||||
|
||||
private EncryptKeyManager encryptKeyManager;
|
||||
|
||||
private EncryptDeployManager encryptDeployManager;
|
||||
@@ -322,7 +364,6 @@ public class ServerConfig {
|
||||
private int queryCacheMaxIdleTime = 600;
|
||||
private int queryCacheMaxTimeToLive = 60*60*6;
|
||||
private Object objectMapper;
|
||||
private boolean diffFlatMode;
|
||||
|
||||
/**
|
||||
* Set to true if you want eq("someProperty", null) to generate 1=1 rather than "is null" sql expression.
|
||||
@@ -506,7 +547,7 @@ public class ServerConfig {
|
||||
/**
|
||||
* Return the JDBC batch mode to use per save(), delete(), insert() or update() request.
|
||||
* <p>
|
||||
* This makes sense when a save() or delete() etc cascades and executes multiple child statements. The best caase
|
||||
* This makes sense when a save() or delete() cascades and executes multiple child statements. The best case
|
||||
* for this is when saving a master/parent bean this cascade inserts many detail/child beans.
|
||||
* </p>
|
||||
* <p>
|
||||
@@ -624,6 +665,125 @@ public class ServerConfig {
|
||||
this.databaseSequenceBatchSize = databaseSequenceBatchSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ChangeLogPrepare.
|
||||
* <p>
|
||||
* This is used to set user context information to the ChangeSet in the
|
||||
* foreground thread prior to the logging occurring in a background thread.
|
||||
* </p>
|
||||
*/
|
||||
public ChangeLogPrepare getChangeLogPrepare() {
|
||||
return changeLogPrepare;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the ChangeLogPrepare.
|
||||
* <p>
|
||||
* This is used to set user context information to the ChangeSet in the
|
||||
* foreground thread prior to the logging occurring in a background thread.
|
||||
* </p>
|
||||
*/
|
||||
public void setChangeLogPrepare(ChangeLogPrepare changeLogPrepare) {
|
||||
this.changeLogPrepare = changeLogPrepare;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ChangeLogListener which actually performs the logging of change sets
|
||||
* in the background.
|
||||
*/
|
||||
public ChangeLogListener getChangeLogListener() {
|
||||
return changeLogListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the ChangeLogListener which actually performs the logging of change sets
|
||||
* in the background.
|
||||
*/
|
||||
public void setChangeLogListener(ChangeLogListener changeLogListener) {
|
||||
this.changeLogListener = changeLogListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ChangeLogRegister which controls which ChangeLogFilter is used for each
|
||||
* bean type and in this way provide fine grained control over which persist requests
|
||||
* are included in the change log.
|
||||
*/
|
||||
public ChangeLogRegister getChangeLogRegister() {
|
||||
return changeLogRegister;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the ChangeLogRegister which controls which ChangeLogFilter is used for each
|
||||
* bean type and in this way provide fine grained control over which persist requests
|
||||
* are included in the change log.
|
||||
*/
|
||||
public void setChangeLogRegister(ChangeLogRegister changeLogRegister) {
|
||||
this.changeLogRegister = changeLogRegister;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if inserts should be included in the change log by default.
|
||||
*/
|
||||
public boolean isChangeLogIncludeInserts() {
|
||||
return changeLogIncludeInserts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set if inserts should be included in the change log by default.
|
||||
*/
|
||||
public void setChangeLogIncludeInserts(boolean changeLogIncludeInserts) {
|
||||
this.changeLogIncludeInserts = changeLogIncludeInserts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ReadAuditLogger to use.
|
||||
*/
|
||||
public ReadAuditLogger getReadAuditLogger() {
|
||||
return readAuditLogger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the ReadAuditLogger to use. If not set the default implementation is used
|
||||
* which logs the read events in JSON format to a standard named SLF4J logger
|
||||
* (which can be configured in say logback to log to a separate log file).
|
||||
*/
|
||||
public void setReadAuditLogger(ReadAuditLogger readAuditLogger) {
|
||||
this.readAuditLogger = readAuditLogger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ReadAuditPrepare to use.
|
||||
*/
|
||||
public ReadAuditPrepare getReadAuditPrepare() {
|
||||
return readAuditPrepare;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the ReadAuditPrepare to use.
|
||||
* <p>
|
||||
* It is expected that an implementation is used that read user context information
|
||||
* (user id, user ip address etc) and sets it on the ReadEvent bean before it is sent
|
||||
* to the ReadAuditLogger.
|
||||
* </p>
|
||||
*/
|
||||
public void setReadAuditPrepare(ReadAuditPrepare readAuditPrepare) {
|
||||
this.readAuditPrepare = readAuditPrepare;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DB migration configuration.
|
||||
*/
|
||||
public DbMigrationConfig getMigrationConfig() {
|
||||
return migrationConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the DB migration configuration.
|
||||
*/
|
||||
public void setMigrationConfig(DbMigrationConfig migrationConfig) {
|
||||
this.migrationConfig = migrationConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the suffix appended to the base table to derive the view that contains the union
|
||||
* of the base table and the history table in order to support asOf queries.
|
||||
@@ -656,6 +816,20 @@ public class ServerConfig {
|
||||
this.asOfSysPeriod = asOfSysPeriod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the history table suffix (defaults to _history).
|
||||
*/
|
||||
public String getHistoryTableSuffix() {
|
||||
return historyTableSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the history table suffix.
|
||||
*/
|
||||
public void setHistoryTableSuffix(String historyTableSuffix) {
|
||||
this.historyTableSuffix = historyTableSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if we are running in a JTA Transaction manager.
|
||||
*/
|
||||
@@ -961,35 +1135,31 @@ public class ServerConfig {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the configuration for the Autofetch feature.
|
||||
* Return the constraint naming convention used in DDL generation.
|
||||
*/
|
||||
public AutofetchConfig getAutofetchConfig() {
|
||||
return autofetchConfig;
|
||||
public DbConstraintNaming getConstraintNaming() {
|
||||
return constraintNaming;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the configuration for the Autofetch feature.
|
||||
* Set the constraint naming convention used in DDL generation.
|
||||
*/
|
||||
public void setAutofetchConfig(AutofetchConfig autofetchConfig) {
|
||||
this.autofetchConfig = autofetchConfig;
|
||||
public void setConstraintNaming(DbConstraintNaming constraintNaming) {
|
||||
this.constraintNaming = constraintNaming;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the PreparedStatementDelegate.
|
||||
* Return the configuration for AutoTune.
|
||||
*/
|
||||
public PstmtDelegate getPstmtDelegate() {
|
||||
return pstmtDelegate;
|
||||
public AutoTuneConfig getAutoTuneConfig() {
|
||||
return autoTuneConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the PstmtDelegate which can be used to support JDBC driver specific
|
||||
* features.
|
||||
* <p>
|
||||
* Typically this means Oracle JDBC driver specific workarounds.
|
||||
* </p>
|
||||
* Set the configuration for AutoTune.
|
||||
*/
|
||||
public void setPstmtDelegate(PstmtDelegate pstmtDelegate) {
|
||||
this.pstmtDelegate = pstmtDelegate;
|
||||
public void setAutoTuneConfig(AutoTuneConfig autoTuneConfig) {
|
||||
this.autoTuneConfig = autoTuneConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1055,6 +1225,28 @@ public class ServerConfig {
|
||||
this.autoCommitMode = autoCommitMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if transaction begin should be started with explicit statement.
|
||||
*/
|
||||
public boolean isExplicitTransactionBeginMode() {
|
||||
return explicitTransactionBeginMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if transaction begin should be started with explicit statement.
|
||||
* <p>
|
||||
* This works for H2 and Postgres but not for Oracle - only use this if you first name
|
||||
* is Daryl or you have explicitly talked to Rob about this feature.
|
||||
* </p>
|
||||
* <p>
|
||||
* This is generally not expected to be turned on but instead allow transactions to start
|
||||
* implicitly which is generally the standard approach.
|
||||
* </p>
|
||||
*/
|
||||
public void setExplicitTransactionBeginMode(boolean explicitTransactionBeginMode) {
|
||||
this.explicitTransactionBeginMode = explicitTransactionBeginMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a value used to represent TRUE in the database.
|
||||
* <p>
|
||||
@@ -1274,19 +1466,18 @@ public class ServerConfig {
|
||||
this.dbEncrypt = dbEncrypt;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return true if UUID should be stored as binary(16) (as opposed to varchar(40)).
|
||||
* Return the DB type used to store UUID.
|
||||
*/
|
||||
public boolean isUuidStoreAsBinary() {
|
||||
return uuidStoreAsBinary;
|
||||
public DbUuid getDbUuid() {
|
||||
return dbUuid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if UUID should be stored as binary(16) (as opposed to varchar(40)).
|
||||
* Set the DB type used to store UUID.
|
||||
*/
|
||||
public void setUuidStoreAsBinary(boolean uuidStoreAsBinary) {
|
||||
this.uuidStoreAsBinary = uuidStoreAsBinary;
|
||||
public void setDbUuid(DbUuid dbUuid) {
|
||||
this.dbUuid = dbUuid;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1660,14 +1851,45 @@ public class ServerConfig {
|
||||
persistControllers.add(beanPersistController);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a BeanPostLoad instance.
|
||||
* <p>
|
||||
* Note alternatively you can use {@link #setPostLoaders(List)} to set
|
||||
* all the BeanPostLoad instances.
|
||||
* </p>
|
||||
*/
|
||||
public void add(BeanPostLoad postLoad) {
|
||||
postLoaders.add(postLoad);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of BeanFindController instances.
|
||||
*/
|
||||
public List<BeanFindController> getFindControllers() {
|
||||
return findControllers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the list of BeanFindController instances.
|
||||
*/
|
||||
public void setFindControllers(List<BeanFindController> findControllers) {
|
||||
this.findControllers = findControllers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of BeanPostLoader instances.
|
||||
*/
|
||||
public List<BeanPostLoad> getPostLoaders() {
|
||||
return postLoaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the list of BeanPostLoader instances.
|
||||
*/
|
||||
public void setPostLoaders(List<BeanPostLoad> postLoaders) {
|
||||
this.postLoaders = postLoaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the BeanPersistController instances.
|
||||
*/
|
||||
@@ -1812,14 +2034,40 @@ public class ServerConfig {
|
||||
* Load the settings from the given properties
|
||||
*/
|
||||
public void loadFromProperties(Properties properties) {
|
||||
// keep the properties used for configuration so that these are available for plugins
|
||||
this.properties = properties;
|
||||
PropertiesWrapper p = new PropertiesWrapper("ebean", name, properties);
|
||||
loadSettings(p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load settings from test-ebean.properties and do nothing if the properties is not found.
|
||||
* <p>
|
||||
* This is typically used when test-ebean.properties is put into the test class path and used
|
||||
* to configure Ebean for running tests.
|
||||
* </p>
|
||||
*/
|
||||
public void loadTestProperties() {
|
||||
Properties properties = PropertyMap.testProperties();
|
||||
if (!properties.isEmpty()) {
|
||||
PropertiesWrapper p = new PropertiesWrapper("ebean", name, properties);
|
||||
loadSettings(p);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the properties that we used for configuration and were set via a call to loadFromProperties().
|
||||
*/
|
||||
public Properties getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T createInstance(PropertiesWrapper p, Class<T> pluginType, String key) {
|
||||
private <T> T createInstance(PropertiesWrapper p, Class<T> pluginType, String key, T instance) {
|
||||
|
||||
if (instance != null) {
|
||||
return instance;
|
||||
}
|
||||
String classname = p.get(key, null);
|
||||
return classname == null ? null : (T) ClassUtil.newInstance(classname);
|
||||
}
|
||||
@@ -1838,8 +2086,8 @@ public class ServerConfig {
|
||||
/**
|
||||
* This is broken out for the same reason as above - preserve existing behaviour but let it be overridden.
|
||||
*/
|
||||
protected void loadAutofetchSettings(PropertiesWrapper p) {
|
||||
autofetchConfig.loadSettings(p);
|
||||
protected void loadAutoTuneSettings(PropertiesWrapper p) {
|
||||
autoTuneConfig.loadSettings(p);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1847,32 +2095,35 @@ public class ServerConfig {
|
||||
*/
|
||||
protected void loadSettings(PropertiesWrapper p) {
|
||||
|
||||
migrationConfig.loadSettings(p);
|
||||
|
||||
namingConvention = createNamingConvention(p, namingConvention);
|
||||
if (namingConvention != null) {
|
||||
namingConvention.loadFromProperties(p);
|
||||
}
|
||||
if (autofetchConfig == null) {
|
||||
autofetchConfig = new AutofetchConfig();
|
||||
if (autoTuneConfig == null) {
|
||||
autoTuneConfig = new AutoTuneConfig();
|
||||
}
|
||||
loadAutofetchSettings(p);
|
||||
loadAutoTuneSettings(p);
|
||||
|
||||
if (dataSourceConfig == null) {
|
||||
dataSourceConfig = new DataSourceConfig();
|
||||
}
|
||||
loadDataSourceSettings(p);
|
||||
|
||||
explicitTransactionBeginMode = p.getBoolean("explicitTransactionBeginMode", explicitTransactionBeginMode);
|
||||
autoCommitMode = p.getBoolean("autoCommitMode", autoCommitMode);
|
||||
useJtaTransactionManager = p.getBoolean("useJtaTransactionManager", useJtaTransactionManager);
|
||||
|
||||
currentUserProvider = createInstance(p, CurrentUserProvider.class, "currentUserProvider");
|
||||
disableClasspathSearch = p.getBoolean("disableClasspathSearch", disableClasspathSearch);
|
||||
databasePlatform = createInstance(p, DatabasePlatform.class, "databasePlatform");
|
||||
encryptKeyManager = createInstance(p, EncryptKeyManager.class, "encryptKeyManager");
|
||||
encryptDeployManager = createInstance(p, EncryptDeployManager.class, "encryptDeployManager");
|
||||
encryptor = createInstance(p, Encryptor.class, "encryptor");
|
||||
dbEncrypt = createInstance(p, DbEncrypt.class, "dbEncrypt");
|
||||
serverCacheFactory = createInstance(p, ServerCacheFactory.class, "serverCacheFactory");
|
||||
serverCacheManager = createInstance(p, ServerCacheManager.class, "serverCacheManager");
|
||||
currentUserProvider = createInstance(p, CurrentUserProvider.class, "currentUserProvider", currentUserProvider);
|
||||
databasePlatform = createInstance(p, DatabasePlatform.class, "databasePlatform", databasePlatform);
|
||||
encryptKeyManager = createInstance(p, EncryptKeyManager.class, "encryptKeyManager", encryptKeyManager);
|
||||
encryptDeployManager = createInstance(p, EncryptDeployManager.class, "encryptDeployManager", encryptDeployManager);
|
||||
encryptor = createInstance(p, Encryptor.class, "encryptor", encryptor);
|
||||
dbEncrypt = createInstance(p, DbEncrypt.class, "dbEncrypt", dbEncrypt);
|
||||
serverCacheFactory = createInstance(p, ServerCacheFactory.class, "serverCacheFactory", serverCacheFactory);
|
||||
serverCacheManager = createInstance(p, ServerCacheManager.class, "serverCacheManager", serverCacheManager);
|
||||
cacheWarmingDelay = p.getInt("cacheWarmingDelay", cacheWarmingDelay);
|
||||
classPathReaderClassName = p.get("classpathreader");
|
||||
|
||||
@@ -1907,16 +2158,21 @@ public class ServerConfig {
|
||||
|
||||
persistenceContextScope = PersistenceContextScope.valueOf(p.get("persistenceContextScope", "TRANSACTION"));
|
||||
|
||||
changeLogIncludeInserts = p.getBoolean("changeLogIncludeInserts", changeLogIncludeInserts);
|
||||
expressionEqualsWithNullAsNoop = p.getBoolean("expressionEqualsWithNullAsNoop", expressionEqualsWithNullAsNoop);
|
||||
diffFlatMode = p.getBoolean("diffFlatMode", diffFlatMode);
|
||||
|
||||
asOfViewSuffix = p.get("asOfViewSuffix", asOfViewSuffix);
|
||||
asOfSysPeriod = p.get("asOfSysPeriod", asOfSysPeriod);
|
||||
historyTableSuffix = p.get("historyTableSuffix", historyTableSuffix);
|
||||
dataSourceJndiName = p.get("dataSourceJndiName", dataSourceJndiName);
|
||||
databaseSequenceBatchSize = p.getInt("databaseSequenceBatchSize", databaseSequenceBatchSize);
|
||||
databaseBooleanTrue = p.get("databaseBooleanTrue", databaseBooleanTrue);
|
||||
databaseBooleanFalse = p.get("databaseBooleanFalse", databaseBooleanFalse);
|
||||
databasePlatformName = p.get("databasePlatformName", databasePlatformName);
|
||||
uuidStoreAsBinary = p.getBoolean("uuidStoreAsBinary", uuidStoreAsBinary);
|
||||
dbUuid = p.getEnum(DbUuid.class, "dbuuid", dbUuid);
|
||||
if (p.getBoolean("uuidStoreAsBinary", false)) {
|
||||
dbUuid = DbUuid.BINARY;
|
||||
}
|
||||
localTimeWithNanos = p.getBoolean("localTimeWithNanos", localTimeWithNanos);
|
||||
|
||||
lazyLoadBatchSize = p.getInt("lazyLoadBatchSize", lazyLoadBatchSize);
|
||||
@@ -1938,7 +2194,7 @@ public class ServerConfig {
|
||||
|
||||
private NamingConvention createNamingConvention(PropertiesWrapper properties, NamingConvention namingConvention) {
|
||||
|
||||
NamingConvention nc = createInstance(properties, NamingConvention.class, "namingconvention");
|
||||
NamingConvention nc = createInstance(properties, NamingConvention.class, "namingconvention", null);
|
||||
return (nc != null) ? nc : namingConvention;
|
||||
}
|
||||
|
||||
@@ -2020,22 +2276,6 @@ public class ServerConfig {
|
||||
this.objectMapper = objectMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if diff should return flat properties with dot notation rather than
|
||||
* embedded beans or reference beans (when the associated bean id is different).
|
||||
*/
|
||||
public boolean isDiffFlatMode() {
|
||||
return diffFlatMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if diff should return flat properties with dot notation rather than
|
||||
* embedded beans or reference beans (when the associated bean id is different).
|
||||
*/
|
||||
public void setDiffFlatMode(boolean diffFlatMode) {
|
||||
this.diffFlatMode = diffFlatMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if eq("someProperty", null) should to generate "1=1" rather than "is null" sql expression.
|
||||
*/
|
||||
@@ -2054,4 +2294,25 @@ public class ServerConfig {
|
||||
public void setExpressionEqualsWithNullAsNoop(boolean expressionEqualsWithNullAsNoop) {
|
||||
this.expressionEqualsWithNullAsNoop = expressionEqualsWithNullAsNoop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify how UUID is stored.
|
||||
*/
|
||||
public enum DbUuid {
|
||||
|
||||
/**
|
||||
* Store using native UUID in H2 and Postgres.
|
||||
*/
|
||||
AUTO,
|
||||
|
||||
/**
|
||||
* Store using DB VARCHAR.
|
||||
*/
|
||||
VARCHAR,
|
||||
|
||||
/**
|
||||
* Store using DB BINARY.
|
||||
*/
|
||||
BINARY
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,23 +3,26 @@ package com.avaje.ebean.config;
|
||||
/**
|
||||
* Converts between Camel Case and Underscore based names for both table and
|
||||
* column names (and is the default naming convention in Ebean).
|
||||
*
|
||||
*
|
||||
* @author emcgreal
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class UnderscoreNamingConvention extends AbstractNamingConvention {
|
||||
|
||||
/** Force toUnderscore to return in upper case. */
|
||||
/**
|
||||
* Force toUnderscore to return in upper case.
|
||||
*/
|
||||
private boolean forceUpperCase = false;
|
||||
|
||||
/** The digits compressed. */
|
||||
/**
|
||||
* The digits compressed.
|
||||
*/
|
||||
private boolean digitsCompressed = true;
|
||||
|
||||
/**
|
||||
* Create with a given sequence format.
|
||||
*
|
||||
* @param sequenceFormat
|
||||
* the sequence format
|
||||
*
|
||||
* @param sequenceFormat the sequence format
|
||||
*/
|
||||
public UnderscoreNamingConvention(String sequenceFormat) {
|
||||
super(sequenceFormat);
|
||||
@@ -34,39 +37,30 @@ public class UnderscoreNamingConvention extends AbstractNamingConvention {
|
||||
|
||||
/**
|
||||
* Returns the last part of the class name.
|
||||
*
|
||||
* @param beanClass
|
||||
* the bean class
|
||||
*
|
||||
*
|
||||
* @param beanClass the bean class
|
||||
* @return the table name from class
|
||||
*/
|
||||
public TableName getTableNameByConvention(Class<?> beanClass) {
|
||||
|
||||
return new TableName(getCatalog(),
|
||||
getSchema(),
|
||||
toUnderscoreFromCamel(beanClass.getSimpleName()));
|
||||
return new TableName(getCatalog(), getSchema(), toUnderscoreFromCamel(beanClass.getSimpleName()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts Camel case property name to underscore based column name.
|
||||
*
|
||||
*
|
||||
* @return the column from property
|
||||
*/
|
||||
public String getColumnFromProperty(Class<?> beanClass, String propertyName) {// Field
|
||||
// field)
|
||||
// {
|
||||
public String getColumnFromProperty(Class<?> beanClass, String propertyName) {
|
||||
|
||||
return toUnderscoreFromCamel(propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts underscore based column name to Camel case property name.
|
||||
*
|
||||
* @param beanClass
|
||||
* the bean class
|
||||
* @param dbColumnName
|
||||
* the db column name
|
||||
*
|
||||
*
|
||||
* @param beanClass the bean class
|
||||
* @param dbColumnName the db column name
|
||||
* @return the property from column
|
||||
*/
|
||||
public String getPropertyFromColumn(Class<?> beanClass, String dbColumnName) {
|
||||
@@ -110,7 +104,7 @@ public class UnderscoreNamingConvention extends AbstractNamingConvention {
|
||||
protected String toUnderscoreFromCamel(String camelCase) {
|
||||
|
||||
int lastUpper = -1;
|
||||
StringBuffer sb = new StringBuffer();
|
||||
StringBuilder sb = new StringBuilder(camelCase.length()+4);
|
||||
for (int i = 0; i < camelCase.length(); i++) {
|
||||
char c = camelCase.charAt(i);
|
||||
|
||||
@@ -144,16 +138,11 @@ public class UnderscoreNamingConvention extends AbstractNamingConvention {
|
||||
}
|
||||
|
||||
/**
|
||||
* To camel from underscore.
|
||||
*
|
||||
* @param underscore
|
||||
* the underscore
|
||||
*
|
||||
* @return the string
|
||||
* Convert and return the from string from underscore to camel case.
|
||||
*/
|
||||
protected String toCamelFromUnderscore(String underscore) {
|
||||
|
||||
StringBuffer result = new StringBuffer();
|
||||
StringBuilder result = new StringBuilder(underscore.length());
|
||||
String[] vals = underscore.split("_");
|
||||
|
||||
for (int i = 0; i < vals.length; i++) {
|
||||
|
||||
@@ -5,6 +5,7 @@ import java.sql.Types;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import com.avaje.ebean.BackgroundExecutor;
|
||||
import com.avaje.ebean.dbmigration.ddlgeneration.platform.DB2Ddl;
|
||||
|
||||
/**
|
||||
* DB2 specific platform.
|
||||
@@ -14,10 +15,11 @@ public class DB2Platform extends DatabasePlatform {
|
||||
public DB2Platform() {
|
||||
super();
|
||||
this.name = "db2";
|
||||
|
||||
// only support getGeneratedKeys with non-batch JDBC
|
||||
// so generally use SEQUENCE instead for H2
|
||||
this.maxTableNameLength = 18;
|
||||
this.maxConstraintNameLength = 18;
|
||||
this.sqlLimiter = new Db2SqlLimiter();
|
||||
this.platformDdl = new DB2Ddl(dbTypeMap, dbIdentity);
|
||||
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(true);
|
||||
this.dbIdentity.setSupportsSequence(true);
|
||||
|
||||
@@ -25,8 +27,6 @@ public class DB2Platform extends DatabasePlatform {
|
||||
dbTypeMap.put(Types.REAL, new DbType("real"));
|
||||
dbTypeMap.put(Types.TINYINT, new DbType("smallint"));
|
||||
dbTypeMap.put(Types.DECIMAL, new DbType("decimal", 15));
|
||||
|
||||
this.dbDdlSyntax.setIdentity("generated by default as identity");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import java.sql.Types;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import com.avaje.ebean.BackgroundExecutor;
|
||||
import com.avaje.ebean.Query;
|
||||
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.dbmigration.ddlgeneration.DdlHandler;
|
||||
import com.avaje.ebean.dbmigration.ddlgeneration.platform.PlatformDdl;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.Types;
|
||||
|
||||
/**
|
||||
* Database platform specific settings.
|
||||
*/
|
||||
@@ -17,6 +18,7 @@ public class DatabasePlatform {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DatabasePlatform.class);
|
||||
|
||||
|
||||
/**
|
||||
* Behavior used when ending a query only transaction (at read committed isolation level).
|
||||
*/
|
||||
@@ -50,33 +52,33 @@ public class DatabasePlatform {
|
||||
*/
|
||||
protected OnQueryOnly onQueryOnly = OnQueryOnly.ROLLBACK;
|
||||
|
||||
/**
|
||||
* The open quote used by quoted identifiers.
|
||||
/**
|
||||
* The open quote used by quoted identifiers.
|
||||
*/
|
||||
protected String openQuote = "\"";
|
||||
|
||||
/**
|
||||
* The close quote used by quoted identifiers.
|
||||
* The close quote used by quoted identifiers.
|
||||
*/
|
||||
protected String closeQuote = "\"";
|
||||
|
||||
/**
|
||||
* For limit/offset, row_number etc limiting of SQL queries.
|
||||
/**
|
||||
* For limit/offset, row_number etc limiting of SQL queries.
|
||||
*/
|
||||
protected SqlLimiter sqlLimiter = new LimitOffsetSqlLimiter();
|
||||
|
||||
/**
|
||||
* Mapping of JDBC to Database types.
|
||||
/**
|
||||
* Mapping of JDBC to Database types.
|
||||
*/
|
||||
protected DbTypeMap dbTypeMap = new DbTypeMap();
|
||||
|
||||
/**
|
||||
* DB specific DDL syntax.
|
||||
/**
|
||||
* Set to true if the DB has native UUID type support.
|
||||
*/
|
||||
protected DbDdlSyntax dbDdlSyntax = new DbDdlSyntax();
|
||||
protected boolean nativeUuidType;
|
||||
|
||||
/**
|
||||
* Defines DB identity/sequence features.
|
||||
/**
|
||||
* Defines DB identity/sequence features.
|
||||
*/
|
||||
protected DbIdentity dbIdentity = new DbIdentity();
|
||||
|
||||
@@ -85,28 +87,28 @@ public class DatabasePlatform {
|
||||
*/
|
||||
protected DbHistorySupport historySupport;
|
||||
|
||||
/**
|
||||
* The JDBC type to map booleans to (by default).
|
||||
/**
|
||||
* The JDBC type to map booleans to (by default).
|
||||
*/
|
||||
protected int booleanDbType = Types.BOOLEAN;
|
||||
|
||||
/**
|
||||
* The JDBC type to map Blob to.
|
||||
/**
|
||||
* The JDBC type to map Blob to.
|
||||
*/
|
||||
protected int blobDbType = Types.BLOB;
|
||||
|
||||
/**
|
||||
* The JDBC type to map Clob to.
|
||||
/**
|
||||
* The JDBC type to map Clob to.
|
||||
*/
|
||||
protected int clobDbType = Types.CLOB;
|
||||
|
||||
/**
|
||||
* For Oracle treat empty strings as null.
|
||||
/**
|
||||
* For Oracle treat empty strings as null.
|
||||
*/
|
||||
protected boolean treatEmptyStringsAsNull;
|
||||
|
||||
/**
|
||||
* The database platform name.
|
||||
/**
|
||||
* The database platform name.
|
||||
*/
|
||||
protected String name = "generic";
|
||||
|
||||
@@ -125,7 +127,7 @@ public class DatabasePlatform {
|
||||
* The like clause. Can be overridden to disable default escape character.
|
||||
*/
|
||||
protected String likeClause = "like ?";
|
||||
|
||||
|
||||
protected DbEncrypt dbEncrypt;
|
||||
|
||||
protected boolean idInExpandedForm;
|
||||
@@ -145,6 +147,20 @@ public class DatabasePlatform {
|
||||
*/
|
||||
protected boolean disallowBatchOnCascade;
|
||||
|
||||
protected PlatformDdl platformDdl;
|
||||
|
||||
/**
|
||||
* The maximum length of table names - used specifically when derived
|
||||
* default table names for intersection tables.
|
||||
*/
|
||||
protected int maxTableNameLength = 60;
|
||||
|
||||
/**
|
||||
* A value of 60 is a reasonable default for all databases except
|
||||
* Oracle (limited to 30) and DB2 (limited to 18).
|
||||
*/
|
||||
protected int maxConstraintNameLength = 60;
|
||||
|
||||
/**
|
||||
* Instantiates a new database platform.
|
||||
*/
|
||||
@@ -157,13 +173,42 @@ public class DatabasePlatform {
|
||||
* "generic" is returned when no specific database platform has been set or
|
||||
* found.
|
||||
* </p>
|
||||
*
|
||||
* @return the name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum table name length.
|
||||
* <p>
|
||||
* This is used when deriving names of intersection tables.
|
||||
* </p>
|
||||
*/
|
||||
public int getMaxTableNameLength() {
|
||||
return maxTableNameLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum constraint name allowed for the platform.
|
||||
*/
|
||||
public int getMaxConstraintNameLength() {
|
||||
return maxConstraintNameLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the platform specific DDL.
|
||||
*/
|
||||
public PlatformDdl getPlatformDdl() {
|
||||
return platformDdl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return a DDL handler for generating DDL scripts.
|
||||
*/
|
||||
public DdlHandler createDdlHandler(ServerConfig serverConfig) {
|
||||
return platformDdl.createDdlHandler(serverConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the JDBC driver does not allow additional queries to execute
|
||||
* when a resultSet is being 'streamed' as is the case with findEach() etc.
|
||||
@@ -177,16 +222,12 @@ public class DatabasePlatform {
|
||||
|
||||
/**
|
||||
* Return a DB Sequence based IdGenerator.
|
||||
*
|
||||
* @param be
|
||||
* the BackgroundExecutor that can be used to load the sequence if
|
||||
* desired
|
||||
* @param ds
|
||||
* the DataSource
|
||||
* @param seqName
|
||||
* the name of the sequence
|
||||
* @param batchSize
|
||||
* the number of sequences that should be loaded
|
||||
*
|
||||
* @param be the BackgroundExecutor that can be used to load the sequence if
|
||||
* desired
|
||||
* @param ds the DataSource
|
||||
* @param seqName the name of the sequence
|
||||
* @param batchSize the number of sequences that should be loaded
|
||||
*/
|
||||
public IdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds, String seqName, int batchSize) {
|
||||
return null;
|
||||
@@ -234,24 +275,22 @@ public class DatabasePlatform {
|
||||
this.historySupport = historySupport;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the DB supports native UUID.
|
||||
*/
|
||||
public boolean isNativeUuidType() {
|
||||
return nativeUuidType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the mapping of JDBC to DB types.
|
||||
*
|
||||
*
|
||||
* @return the db type map
|
||||
*/
|
||||
public DbTypeMap getDbTypeMap() {
|
||||
return dbTypeMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DDL syntax for this platform.
|
||||
*
|
||||
* @return the db ddl syntax
|
||||
*/
|
||||
public DbDdlSyntax getDbDdlSyntax() {
|
||||
return dbDdlSyntax;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the column alias prefix.
|
||||
*/
|
||||
@@ -282,7 +321,7 @@ public class DatabasePlatform {
|
||||
|
||||
/**
|
||||
* Return the close quote for quoted identifiers.
|
||||
*
|
||||
*
|
||||
* @return the close quote
|
||||
*/
|
||||
public String getCloseQuote() {
|
||||
@@ -291,7 +330,7 @@ public class DatabasePlatform {
|
||||
|
||||
/**
|
||||
* Return the open quote for quoted identifiers.
|
||||
*
|
||||
*
|
||||
* @return the open quote
|
||||
*/
|
||||
public String getOpenQuote() {
|
||||
@@ -300,7 +339,7 @@ public class DatabasePlatform {
|
||||
|
||||
/**
|
||||
* Return the JDBC type used to store booleans.
|
||||
*
|
||||
*
|
||||
* @return the boolean db type
|
||||
*/
|
||||
public int getBooleanDbType() {
|
||||
@@ -330,7 +369,7 @@ public class DatabasePlatform {
|
||||
|
||||
/**
|
||||
* Return true if empty strings should be treated as null.
|
||||
*
|
||||
*
|
||||
* @return true, if checks if is treat empty strings as null
|
||||
*/
|
||||
public boolean isTreatEmptyStringsAsNull() {
|
||||
@@ -366,7 +405,7 @@ public class DatabasePlatform {
|
||||
|
||||
/**
|
||||
* Return the DB identity/sequence features for this platform.
|
||||
*
|
||||
*
|
||||
* @return the db identity
|
||||
*/
|
||||
public DbIdentity getDbIdentity() {
|
||||
@@ -379,7 +418,7 @@ public class DatabasePlatform {
|
||||
* <p>
|
||||
* Basically add the clauses for limit/offset, rownum, row_number().
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @return the sql limiter
|
||||
*/
|
||||
public SqlLimiter getSqlLimiter() {
|
||||
@@ -388,15 +427,12 @@ public class DatabasePlatform {
|
||||
|
||||
/**
|
||||
* Convert backticks to the platform specific open quote and close quote
|
||||
*
|
||||
* <p>
|
||||
* Specific plugins may implement this method to cater for platform specific
|
||||
* naming rules.
|
||||
* </p>
|
||||
*
|
||||
* @param dbName
|
||||
* the db name
|
||||
*
|
||||
*
|
||||
* @param dbName the db name
|
||||
* @return the string
|
||||
*/
|
||||
public String convertQuotedIdentifiers(String dbName) {
|
||||
@@ -461,22 +497,4 @@ public class DatabasePlatform {
|
||||
return disallowBatchOnCascade;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate and return the create sequence DDL.
|
||||
*/
|
||||
public String ddlCreateSequence(String sequenceName, int initialValue, int allocationSize) {
|
||||
|
||||
StringBuilder sb = new StringBuilder("create sequence ");
|
||||
sb.append(sequenceName);
|
||||
if (initialValue > 1) {
|
||||
sb.append(" start with ").append(initialValue);
|
||||
}
|
||||
if (allocationSize > 0 && allocationSize != 50) {
|
||||
// at this stage ignoring allocationSize 50 as this is the 'default' and
|
||||
// not consistent with the way Ebean batch fetches sequence values
|
||||
sb.append(" increment by ").append(allocationSize);
|
||||
}
|
||||
sb.append(";");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,333 +0,0 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import com.avaje.ebean.config.TableName;
|
||||
|
||||
/**
|
||||
* Used to support DB specific syntax for DDL generation.
|
||||
*/
|
||||
public class DbDdlSyntax {
|
||||
|
||||
protected boolean renderIndexForFkey = true;
|
||||
|
||||
protected boolean inlinePrimaryKeyConstraint = false;
|
||||
|
||||
protected boolean addOneToOneUniqueContraint = true;
|
||||
|
||||
protected int maxConstraintNameLength = 32;
|
||||
|
||||
protected int columnNameWidth = 25;
|
||||
|
||||
/**
|
||||
* Flag set when we want to disable constraints on each table (rather than globally).
|
||||
*/
|
||||
protected boolean dropKeyConstraints;
|
||||
|
||||
protected String dropTableCascade;
|
||||
protected String dropIfExists;
|
||||
|
||||
protected String newLine = "\n";
|
||||
|
||||
protected String identity = "auto_increment";
|
||||
protected String identitySuffix = "";
|
||||
|
||||
protected String pkPrefix = "pk_";
|
||||
|
||||
protected String disableReferentialIntegrity;
|
||||
protected String enableReferentialIntegrity;
|
||||
|
||||
protected String foreignKeySuffix;
|
||||
|
||||
/**
|
||||
* Return the primary key name for a given bean descriptor.
|
||||
*/
|
||||
public String getPrimaryKeyName(String tableName) {
|
||||
|
||||
String pk = pkPrefix + tableName;
|
||||
if (pk.length() > maxConstraintNameLength) {
|
||||
// need to trim the primary key name
|
||||
pk = pk.substring(0, maxConstraintNameLength);
|
||||
}
|
||||
return pk;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the column definition for an identity column.
|
||||
*/
|
||||
public String getIdentityColumnDefn(String columnDefn) {
|
||||
String identity = getIdentity();
|
||||
if (identity != null && identity.length() > 0) {
|
||||
return columnDefn+" "+identity;
|
||||
}
|
||||
return columnDefn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the identity clause for DB's that have identities.
|
||||
*/
|
||||
public String getIdentity() {
|
||||
return identity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the identity clause.
|
||||
*/
|
||||
public void setIdentity(String identity) {
|
||||
this.identity = identity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Typically returns empty string but for SQLite and perhaps others
|
||||
* the Identity/AutoIncrement clause comes after the primary key clause.
|
||||
*/
|
||||
public String getIdentitySuffix() {
|
||||
return identitySuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the identity clause that would appear after the primary key clause.
|
||||
* <p>
|
||||
* Only used for SQLite at this stage.
|
||||
* </p>
|
||||
*/
|
||||
public void setIdentitySuffix(String identitySuffix) {
|
||||
this.identitySuffix = identitySuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the width for padding whitespace after column names.
|
||||
*/
|
||||
public int getColumnNameWidth() {
|
||||
return columnNameWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the amount of padding to write after the column name.
|
||||
*/
|
||||
public void setColumnNameWidth(int columnNameWidth) {
|
||||
this.columnNameWidth = columnNameWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the new line character.
|
||||
*/
|
||||
public String getNewLine() {
|
||||
return newLine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the new line character.
|
||||
*/
|
||||
public void setNewLine(String newLine) {
|
||||
this.newLine = newLine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the prefix used in naming primary keys.
|
||||
*/
|
||||
public String getPkPrefix() {
|
||||
return pkPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the prefix used in naming primary keys.
|
||||
*/
|
||||
public void setPkPrefix(String pkPrefix) {
|
||||
this.pkPrefix = pkPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DB specific command to disable referential integrity
|
||||
*/
|
||||
public String getDisableReferentialIntegrity() {
|
||||
return disableReferentialIntegrity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the DB specific command to disable referential integrity
|
||||
*/
|
||||
public void setDisableReferentialIntegrity(String disableReferentialIntegrity) {
|
||||
this.disableReferentialIntegrity = disableReferentialIntegrity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DB specific command to enable referential integrity
|
||||
*/
|
||||
public String getEnableReferentialIntegrity() {
|
||||
return enableReferentialIntegrity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the DB specific command to enable referential integrity
|
||||
*/
|
||||
public void setEnableReferentialIntegrity(String enableReferentialIntegrity) {
|
||||
this.enableReferentialIntegrity = enableReferentialIntegrity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true to is constraints are disabled on each table.
|
||||
*/
|
||||
public boolean isDropKeyConstraints() {
|
||||
return dropKeyConstraints;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return some DDL to disable constraints on the given table.
|
||||
*/
|
||||
public String dropKeyConstraintPrefix(String tableName, String fkName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if indexes should be created for the foreign keys.
|
||||
*/
|
||||
public boolean isRenderIndexForFkey() {
|
||||
return renderIndexForFkey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether indexes should be created for the foreign keys.
|
||||
*/
|
||||
public void setRenderIndexForFkey(boolean renderIndexForFkey) {
|
||||
this.renderIndexForFkey = renderIndexForFkey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Typically returns IF EXISTS (if that is supported by the database platform)
|
||||
* or null.
|
||||
*/
|
||||
public String getDropIfExists() {
|
||||
return dropIfExists;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the IF EXISTS clause for dropping tables if that is supported by the
|
||||
* database platform.
|
||||
*/
|
||||
public void setDropIfExists(String dropIfExists) {
|
||||
this.dropIfExists = dropIfExists;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return prefix text that goes before drop table.
|
||||
*/
|
||||
public String dropTablePrefix(String tableName) {
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the cascade option for the drop table command.
|
||||
*/
|
||||
public String getDropTableCascade() {
|
||||
return dropTableCascade;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the cascade option for the drop table command.
|
||||
*/
|
||||
public void setDropTableCascade(String dropTableCascade) {
|
||||
this.dropTableCascade = dropTableCascade;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the foreign key suffix.
|
||||
*/
|
||||
public String getForeignKeySuffix() {
|
||||
return foreignKeySuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the foreign key suffix.
|
||||
*/
|
||||
public void setForeignKeySuffix(String foreignKeySuffix) {
|
||||
this.foreignKeySuffix = foreignKeySuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum length that constraint names can be for this database.
|
||||
*/
|
||||
public int getMaxConstraintNameLength() {
|
||||
return maxConstraintNameLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum length that constraint names can be for this database.
|
||||
*/
|
||||
public void setMaxConstraintNameLength(int maxFkeyLength) {
|
||||
this.maxConstraintNameLength = maxFkeyLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if imported side of OneToOne's should have unique constraints
|
||||
* generated.
|
||||
*/
|
||||
public boolean isAddOneToOneUniqueContraint() {
|
||||
return addOneToOneUniqueContraint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to false for DB's that don't want both a unique and index on the
|
||||
* imported OneToOne.
|
||||
*/
|
||||
public void setAddOneToOneUniqueContraint(boolean addOneToOneUniqueContraint) {
|
||||
this.addOneToOneUniqueContraint = addOneToOneUniqueContraint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if primary key constraints should be inlined when they are a
|
||||
* single column.
|
||||
*/
|
||||
public boolean isInlinePrimaryKeyConstraint() {
|
||||
return inlinePrimaryKeyConstraint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to inline primary key constraints.
|
||||
*/
|
||||
public void setInlinePrimaryKeyConstraint(boolean inlinePrimaryKeyConstraint) {
|
||||
this.inlinePrimaryKeyConstraint = inlinePrimaryKeyConstraint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds and returns a fully index name.
|
||||
*/
|
||||
public String getIndexName(String table, String propName, int ixCount) {
|
||||
|
||||
|
||||
StringBuilder buffer = new StringBuilder(30);
|
||||
buffer.append("ix_").append(TableName.parse(table));
|
||||
buffer.append("_").append(propName);
|
||||
|
||||
addSuffix(buffer, ixCount);
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds and returns a fully qualified foreign key constraint name.
|
||||
*/
|
||||
public String getForeignKeyName(String table, String propName, int fkCount) {
|
||||
|
||||
StringBuilder buffer = new StringBuilder(30);
|
||||
buffer.append("fk_").append(TableName.parse(table));
|
||||
buffer.append("_").append(propName);
|
||||
|
||||
addSuffix(buffer, fkCount);
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the suffix.
|
||||
*/
|
||||
protected void addSuffix(StringBuilder buffer, int count) {
|
||||
String suffixNr = Integer.toString(count);
|
||||
int suffixLen = suffixNr.length() + 1;
|
||||
|
||||
if (buffer.length() + suffixLen > maxConstraintNameLength) {
|
||||
buffer.setLength(maxConstraintNameLength - suffixLen);
|
||||
}
|
||||
buffer.append("_");
|
||||
buffer.append(suffixNr);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,6 +5,37 @@ package com.avaje.ebean.config.dbplatform;
|
||||
*/
|
||||
public interface DbHistorySupport {
|
||||
|
||||
/**
|
||||
* Return true if the 'As of' predicate is part of the from clause
|
||||
* (more standard sql2011). So true for Oracle total recall and false
|
||||
* for Postgres and MySql (where we use views and history tables).
|
||||
*/
|
||||
boolean isBindWithFromClause();
|
||||
|
||||
/**
|
||||
* Return the number of columns bound in a 'As Of' predicate.
|
||||
* <p>
|
||||
* This is 1 for more standard sql2011 style and Postgres which has the
|
||||
* special range type and 2 for view based solutions with 2 columns such as
|
||||
* MySql.
|
||||
* </p>
|
||||
*/
|
||||
int getBindCount();
|
||||
|
||||
/**
|
||||
* For sql2011 style this ignores the passed in view suffix and returns something
|
||||
* like the ' as of timestamp ?' clause to be appended after the base table name.
|
||||
*
|
||||
* @param asOfViewSuffix the configured view suffix (typically "_with_history").
|
||||
* @return The suffix appended after the base table name in the from and join clauses.
|
||||
*/
|
||||
String getAsOfViewSuffix(String asOfViewSuffix);
|
||||
|
||||
/**
|
||||
* Return the 'versions between timestamp' suffix.
|
||||
*/
|
||||
String getVersionsBetweenSuffix(String asOfViewSuffix);
|
||||
|
||||
/**
|
||||
* Return the 'as of' predicate added for the given table alias.
|
||||
*
|
||||
@@ -18,7 +49,7 @@ public interface DbHistorySupport {
|
||||
* Return the column for the system period lower bound that will be included in findVersions() queries.
|
||||
*
|
||||
* @param tableAlias the table alias which will typically be 't0'
|
||||
* @param sysPeriod the name of the sys_period column
|
||||
* @param sysPeriod the name of the sys_period column
|
||||
*/
|
||||
String getSysPeriodLower(String tableAlias, String sysPeriod);
|
||||
|
||||
@@ -26,7 +57,7 @@ public interface DbHistorySupport {
|
||||
* Return the column for the system period upper bound that will be included in findVersions() queries.
|
||||
*
|
||||
* @param tableAlias the table alias which will typically be 't0'
|
||||
* @param sysPeriod the name of the sys_period column
|
||||
* @param sysPeriod the name of the sys_period column
|
||||
*/
|
||||
String getSysPeriodUpper(String tableAlias, String sysPeriod);
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import com.avaje.ebean.dbmigration.migration.IdentityType;
|
||||
|
||||
/**
|
||||
* Defines the identity/sequence behaviour for the database.
|
||||
*/
|
||||
@@ -114,4 +116,28 @@ public class DbIdentity {
|
||||
this.idType = idType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the id type to use based on requested identityType and
|
||||
* the support for that in the database platform.
|
||||
*/
|
||||
public IdType useIdentityType(IdentityType identityType) {
|
||||
|
||||
if (identityType == null) {
|
||||
// use the default
|
||||
return idType;
|
||||
}
|
||||
switch (identityType) {
|
||||
case GENERATOR:
|
||||
return IdType.GENERATOR;
|
||||
case EXTERNAL:
|
||||
return IdType.EXTERNAL;
|
||||
case SEQUENCE:
|
||||
return supportsSequence ? IdType.SEQUENCE : idType;
|
||||
case IDENTITY:
|
||||
return supportsIdentity ? IdType.IDENTITY : idType;
|
||||
}
|
||||
|
||||
// use the default
|
||||
return idType;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
/**
|
||||
* Built in supported platforms.
|
||||
*/
|
||||
public enum DbPlatformName {
|
||||
|
||||
/**
|
||||
* Generic base platform configured via properties or code.
|
||||
*/
|
||||
GENERIC,
|
||||
|
||||
/**
|
||||
* H2.
|
||||
*/
|
||||
H2,
|
||||
|
||||
/**
|
||||
* Postgres.
|
||||
*/
|
||||
POSTGRES,
|
||||
|
||||
/**
|
||||
* MySql.
|
||||
*/
|
||||
MYSQL,
|
||||
|
||||
/**
|
||||
* Oracle.
|
||||
*/
|
||||
ORACLE,
|
||||
|
||||
/**
|
||||
* Microsoft SQL Server.
|
||||
*/
|
||||
SQLSERVER,
|
||||
|
||||
/**
|
||||
* DB2.
|
||||
*/
|
||||
DB2,
|
||||
|
||||
/**
|
||||
* SQLite.
|
||||
*/
|
||||
SQLITE
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
/**
|
||||
* SQL2011 based history support using 'as of timestamp' type clause appended as part of the the from or join clause.
|
||||
*/
|
||||
public abstract class DbStandardHistorySupport implements DbHistorySupport {
|
||||
|
||||
/**
|
||||
* Return true as with sql2011 the 'as of timestamp' clause included in from or join clause.
|
||||
*/
|
||||
@Override
|
||||
public boolean isBindWithFromClause() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return 1 as the bind count (not 2 for effective start and effective end columns).
|
||||
*/
|
||||
@Override
|
||||
public int getBindCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return null - not used for sql2011 based history.
|
||||
*/
|
||||
@Override
|
||||
public String getAsOfPredicate(String tableAlias, String sysPeriod) {
|
||||
// not used for sql2011 based history
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,11 @@ package com.avaje.ebean.config.dbplatform;
|
||||
*/
|
||||
public class DbType {
|
||||
|
||||
/**
|
||||
* DB native UUID type (H2 and Postgres).
|
||||
*/
|
||||
public static final int UUID = 5010;
|
||||
|
||||
/**
|
||||
* Type to map Map content to Postgres HSTORE.
|
||||
*/
|
||||
|
||||
@@ -9,16 +9,82 @@ import java.util.Map;
|
||||
*/
|
||||
public class DbTypeMap {
|
||||
|
||||
private static final DbType JSON_CLOB_PLACEHOLDER = new DbType("jsonClobPlaceholder");
|
||||
private static final DbType JSON_BLOB_PLACEHOLDER = new DbType("jsonBlobPlaceholder");
|
||||
private static final DbType JSON_VARCHAR_PLACEHOLDER = new DbType("jsonVarcharPlaceholder");
|
||||
|
||||
/**
|
||||
* A map to reverse lookup the type by name.
|
||||
* <p>
|
||||
* Used when converting from logical types to platform types which we
|
||||
* want to do with 2 phase DDL generation.
|
||||
*/
|
||||
static Map<String, Integer> lookup = new HashMap<String, Integer>();
|
||||
|
||||
static {
|
||||
lookup.put("BOOLEAN", Types.BOOLEAN);
|
||||
lookup.put("BIT", Types.BIT);
|
||||
lookup.put("INTEGER", Types.INTEGER);
|
||||
lookup.put("BIGINT", Types.BIGINT);
|
||||
lookup.put("REAL", Types.REAL);
|
||||
// Float is most common REAL mapping to have that as well
|
||||
lookup.put("FLOAT", Types.REAL);
|
||||
|
||||
lookup.put("DOUBLE", Types.DOUBLE);
|
||||
lookup.put("SMALLINT", Types.SMALLINT);
|
||||
lookup.put("TINYINT", Types.TINYINT);
|
||||
lookup.put("DECIMAL", Types.DECIMAL);
|
||||
lookup.put("VARCHAR", Types.VARCHAR);
|
||||
// VARCHAR2 - extra for Oracle specific column definition
|
||||
lookup.put("VARCHAR2", Types.VARCHAR);
|
||||
lookup.put("CHAR", Types.CHAR);
|
||||
lookup.put("BLOB", Types.BLOB);
|
||||
lookup.put("CLOB", Types.CLOB);
|
||||
|
||||
lookup.put("LONGVARBINARY", Types.LONGVARBINARY);
|
||||
lookup.put("LONGVARCHAR", Types.LONGVARCHAR);
|
||||
lookup.put("VARBINARY", Types.VARBINARY);
|
||||
lookup.put("BINARY", Types.BINARY);
|
||||
lookup.put("DATE", Types.DATE);
|
||||
lookup.put("TIME", Types.TIME);
|
||||
lookup.put("TIMESTAMP", Types.TIMESTAMP);
|
||||
|
||||
lookup.put("UUID", DbType.UUID);
|
||||
|
||||
// Not standard java.sql.Types
|
||||
// logical JSON storage types
|
||||
lookup.put("JSON", DbType.JSON);
|
||||
lookup.put("JSONB", DbType.JSONB);
|
||||
lookup.put("JSONCLOB", DbType.JSONClob);
|
||||
lookup.put("JSONBLOB", DbType.JSONBlob);
|
||||
lookup.put("JSONVARCHAR", DbType.JSONVarchar);
|
||||
}
|
||||
|
||||
|
||||
private final Map<Integer, DbType> typeMap = new HashMap<Integer, DbType>();
|
||||
|
||||
/**
|
||||
* Return the DbTypeMap with standard (not platform specific) types.
|
||||
*
|
||||
* This has some extended JSON types (JSON, JSONB, JSONVarchar, JSONClob, JSONBlob).
|
||||
* These types get translated to specific database platform types during DDL generation.
|
||||
*/
|
||||
public static DbTypeMap logicalTypes() {
|
||||
return new DbTypeMap(true);
|
||||
}
|
||||
|
||||
public DbTypeMap() {
|
||||
loadDefaults();
|
||||
loadDefaults(false);
|
||||
}
|
||||
|
||||
private DbTypeMap(boolean logicalTypes) {
|
||||
loadDefaults(logicalTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the standard types. These can be overridden by DB specific platform.
|
||||
*/
|
||||
private void loadDefaults() {
|
||||
private void loadDefaults(boolean logicalTypes) {
|
||||
|
||||
put(Types.BOOLEAN, new DbType("boolean"));
|
||||
put(Types.BIT, new DbType("bit"));
|
||||
@@ -37,11 +103,25 @@ public class DbTypeMap {
|
||||
put(Types.BLOB, new DbType("blob"));
|
||||
put(Types.CLOB, new DbType("clob"));
|
||||
|
||||
put(DbType.JSON, new DbType("clob")); // Postgres maps this to JSON
|
||||
put(DbType.JSONB, new DbType("clob")); // Postgres maps this to JSONB
|
||||
put(DbType.JSONClob, new DbType("clob"));
|
||||
put(DbType.JSONBlob, new DbType("blob"));
|
||||
put(DbType.JSONVarchar, new DbType("varchar", 1000));
|
||||
// DB native UUID support (H2 and Postgres)
|
||||
put(DbType.UUID, new DbType("uuid"));
|
||||
|
||||
if (logicalTypes) {
|
||||
// keep it logical for 2 layer DDL generation
|
||||
put(DbType.HSTORE, new DbType("hstore"));
|
||||
put(DbType.JSON, new DbType("json"));
|
||||
put(DbType.JSONB, new DbType("jsonb"));
|
||||
put(DbType.JSONClob, new DbType("jsonclob"));
|
||||
put(DbType.JSONBlob, new DbType("jsonblob"));
|
||||
put(DbType.JSONVarchar, new DbType("jsonvarchar", 1000));
|
||||
|
||||
} else {
|
||||
put(DbType.JSON, JSON_CLOB_PLACEHOLDER); // Postgres maps this to JSON
|
||||
put(DbType.JSONB, JSON_CLOB_PLACEHOLDER); // Postgres maps this to JSONB
|
||||
put(DbType.JSONClob, JSON_CLOB_PLACEHOLDER);
|
||||
put(DbType.JSONBlob, JSON_BLOB_PLACEHOLDER);
|
||||
put(DbType.JSONVarchar, JSON_VARCHAR_PLACEHOLDER);
|
||||
}
|
||||
|
||||
put(Types.LONGVARBINARY, new DbType("longvarbinary"));
|
||||
put(Types.LONGVARCHAR, new DbType("lonvarchar"));
|
||||
@@ -54,24 +134,58 @@ public class DbTypeMap {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup the platform specific DbType given the standard sql type name.
|
||||
*/
|
||||
public DbType lookup(String name) {
|
||||
name = name.trim().toUpperCase();
|
||||
Integer typeKey = lookup.get(name);
|
||||
if (typeKey == null) {
|
||||
throw new IllegalArgumentException("Unknown type [" + name + "] - not standard sql type");
|
||||
}
|
||||
// handle JSON types mapped to clob, blob and varchar
|
||||
switch (typeKey) {
|
||||
case DbType.JSONBlob:
|
||||
return get(Types.BLOB);
|
||||
case DbType.JSONClob:
|
||||
return get(Types.CLOB);
|
||||
case DbType.JSONVarchar:
|
||||
return get(Types.VARCHAR);
|
||||
case DbType.JSON:
|
||||
return getJsonType(DbType.JSON);
|
||||
case DbType.JSONB:
|
||||
return getJsonType(DbType.JSONB);
|
||||
default:
|
||||
return get(typeKey);
|
||||
}
|
||||
}
|
||||
|
||||
private DbType getJsonType(int type) {
|
||||
DbType dbType = get(type);
|
||||
if (dbType == JSON_CLOB_PLACEHOLDER) {
|
||||
return get(Types.CLOB);
|
||||
}
|
||||
if (dbType == JSON_BLOB_PLACEHOLDER) {
|
||||
return get(Types.BLOB);
|
||||
}
|
||||
if (dbType == JSON_VARCHAR_PLACEHOLDER) {
|
||||
return get(Types.VARCHAR);
|
||||
}
|
||||
// Postgres has specific type
|
||||
return get(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the type for a given JDBC type.
|
||||
*/
|
||||
public void put(int jdbcType, DbType dbType) {
|
||||
typeMap.put(Integer.valueOf(jdbcType), dbType);
|
||||
typeMap.put(jdbcType, dbType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type for a given jdbc type.
|
||||
*/
|
||||
public DbType get(int jdbcType) {
|
||||
|
||||
DbType dbType = typeMap.get(Integer.valueOf(jdbcType));
|
||||
if (dbType == null) {
|
||||
String m = "No DB type for JDBC type " + jdbcType;
|
||||
throw new RuntimeException(m);
|
||||
}
|
||||
|
||||
return dbType;
|
||||
return typeMap.get(jdbcType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
/**
|
||||
* Database view based implementation of DbHistorySupport.
|
||||
* <p>
|
||||
* These implementations have explicit history tables, a view to union the
|
||||
* base table and history table and triggers to maintain the history.
|
||||
* </p>
|
||||
*/
|
||||
public abstract class DbViewHistorySupport implements DbHistorySupport {
|
||||
|
||||
/**
|
||||
* Return false for view based implementations where we append extra 'as of' predicates to the end.
|
||||
*/
|
||||
@Override
|
||||
public boolean isBindWithFromClause() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the configured view suffix.
|
||||
*
|
||||
* @param asOfViewSuffix the configured view suffix (typically "_with_history").
|
||||
*/
|
||||
@Override
|
||||
public String getAsOfViewSuffix(String asOfViewSuffix) {
|
||||
// just return the configured suffix
|
||||
return asOfViewSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the configured view suffix (same as getAsOfViewSuffix()).
|
||||
*
|
||||
* @param asOfViewSuffix the configured view suffix (typically "_with_history").
|
||||
*/
|
||||
@Override
|
||||
public String getVersionsBetweenSuffix(String asOfViewSuffix) {
|
||||
// just return the configured asOfViewSuffix (using the view for versions between query)
|
||||
return asOfViewSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return 2 if we have effective start and effective end as 2 columns.
|
||||
* Note that for postgres we can use a single range type so that returns 1.
|
||||
*/
|
||||
@Override
|
||||
public int getBindCount() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the 'as of' predicate clause appended to the end of the normal query predicates.
|
||||
*/
|
||||
@Override
|
||||
public String getAsOfPredicate(String asOfTableAlias, String asOfSysPeriod) {
|
||||
|
||||
// (sys_period_start < ? and (sys_period_end is null or sys_period_end > ?));
|
||||
return "(" + asOfTableAlias + "." + asOfSysPeriod + "_start" + " <= ? and (" + asOfTableAlias + "." + asOfSysPeriod + "_end" + " is null or " + asOfTableAlias + "." + asOfSysPeriod + "_end" + " > ?))";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the lower bound column prepended with the table alias.
|
||||
*
|
||||
* @param tableAlias the table alias
|
||||
* @param sysPeriod the name of the sys_period column
|
||||
*/
|
||||
@Override
|
||||
public String getSysPeriodLower(String tableAlias, String sysPeriod) {
|
||||
return tableAlias + "." + sysPeriod + "_start";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the upper bound column prepended with the table alias.
|
||||
*
|
||||
* @param tableAlias the table alias
|
||||
* @param sysPeriod the name of the sys_period column
|
||||
*/
|
||||
@Override
|
||||
public String getSysPeriodUpper(String tableAlias, String sysPeriod) {
|
||||
return tableAlias + "." + sysPeriod + "_end";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
/**
|
||||
* Runtime support for @History with H2.
|
||||
*/
|
||||
public class H2HistorySupport extends DbViewHistorySupport {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import org.h2.api.Trigger;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* H2 database trigger used to populate history tables to support the @History feature.
|
||||
*/
|
||||
public class H2HistoryTrigger implements Trigger {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(H2HistoryTrigger.class);
|
||||
|
||||
/**
|
||||
* Hardcoding the column and history table suffix for now. Not sure how to get that
|
||||
* configuration into the trigger instance nicely as it is instantiated by H2.
|
||||
*/
|
||||
private static final String SYS_PERIOD_START = "SYS_PERIOD_START";
|
||||
private static final String SYS_PERIOD_END = "SYS_PERIOD_END";
|
||||
private static final String HISTORY_SUFFIX = "_history";
|
||||
|
||||
/**
|
||||
* SQL to insert into the history table.
|
||||
*/
|
||||
private String insertHistorySql;
|
||||
|
||||
/**
|
||||
* Position of SYS_PERIOD_START column in the Object[].
|
||||
*/
|
||||
private int effectStartPosition;
|
||||
|
||||
/**
|
||||
* Position of SYS_PERIOD_END column in the Object[].
|
||||
*/
|
||||
private int effectEndPosition;
|
||||
|
||||
@Override
|
||||
public void init(Connection conn, String schemaName, String triggerName, String tableName, boolean before, int type) throws SQLException {
|
||||
|
||||
// get the columns for the table
|
||||
ResultSet rs = conn.getMetaData().getColumns(null, schemaName, tableName, null);
|
||||
|
||||
// build the insert into history table SQL
|
||||
StringBuilder insertSql = new StringBuilder(150);
|
||||
insertSql.append("insert into ").append(tableName).append(HISTORY_SUFFIX).append(" (");
|
||||
|
||||
int count = 0;
|
||||
List<String> columns = new ArrayList<String>();
|
||||
while (rs.next()) {
|
||||
if (++count > 1) {
|
||||
insertSql.append(",");
|
||||
}
|
||||
String columnName = rs.getString("COLUMN_NAME");
|
||||
if (columnName.equalsIgnoreCase(SYS_PERIOD_START)) {
|
||||
this.effectStartPosition = count - 1;
|
||||
} else if (columnName.equalsIgnoreCase(SYS_PERIOD_END)) {
|
||||
this.effectEndPosition = count - 1;
|
||||
}
|
||||
insertSql.append(columnName);
|
||||
columns.add(columnName);
|
||||
}
|
||||
insertSql.append(") values (");
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (i > 0) {
|
||||
insertSql.append(",");
|
||||
}
|
||||
insertSql.append("?");
|
||||
}
|
||||
insertSql.append(");");
|
||||
|
||||
this.insertHistorySql = insertSql.toString();
|
||||
logger.debug("History table insert sql: {}", insertHistorySql);
|
||||
}
|
||||
|
||||
@Override
|
||||
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());
|
||||
oldRow[effectEndPosition] = now;
|
||||
if (newRow != null) {
|
||||
// update event. Set the effective start timestamp to now.
|
||||
newRow[effectStartPosition] = now;
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("History insert: {}", Arrays.toString(oldRow));
|
||||
}
|
||||
insertIntoHistory(connection, oldRow);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert the data into the history table.
|
||||
*/
|
||||
private void insertIntoHistory(Connection connection, Object[] oldRow) throws SQLException {
|
||||
|
||||
PreparedStatement stmt = connection.prepareStatement(insertHistorySql);
|
||||
try {
|
||||
for (int i = 0; i < oldRow.length; i++) {
|
||||
stmt.setObject(i + 1, oldRow[i]);
|
||||
}
|
||||
stmt.executeUpdate();
|
||||
} finally {
|
||||
stmt.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws SQLException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() throws SQLException {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import com.avaje.ebean.BackgroundExecutor;
|
||||
import com.avaje.ebean.dbmigration.ddlgeneration.platform.H2Ddl;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
@@ -13,9 +14,9 @@ public class H2Platform extends DatabasePlatform {
|
||||
super();
|
||||
this.name = "h2";
|
||||
this.dbEncrypt = new H2DbEncrypt();
|
||||
// like ? escape'' not working in the latest version H2 so just using no
|
||||
// escape clause for now noting that backslash is an escape char for like in H2
|
||||
this.likeClause = "like ?";
|
||||
this.platformDdl = new H2Ddl(this.dbTypeMap, dbIdentity);
|
||||
this.historySupport = new H2HistorySupport();
|
||||
this.nativeUuidType = true;
|
||||
|
||||
// only support getGeneratedKeys with non-batch JDBC
|
||||
// so generally use SEQUENCE instead of IDENTITY for H2
|
||||
@@ -24,16 +25,12 @@ public class H2Platform extends DatabasePlatform {
|
||||
this.dbIdentity.setSupportsSequence(true);
|
||||
this.dbIdentity.setSupportsIdentity(true);
|
||||
|
||||
this.openQuote = "\"";
|
||||
this.closeQuote = "\"";
|
||||
// like ? escape'' not working in the latest version H2 so just using no
|
||||
// escape clause for now noting that backslash is an escape char for like in H2
|
||||
this.likeClause = "like ?";
|
||||
|
||||
// H2 data types match default JDBC types
|
||||
// so no changes to dbTypeMap required
|
||||
|
||||
this.dbDdlSyntax.setDropIfExists("if exists");
|
||||
this.dbDdlSyntax.setDisableReferentialIntegrity("SET REFERENTIAL_INTEGRITY FALSE");
|
||||
this.dbDdlSyntax.setEnableReferentialIntegrity("SET REFERENTIAL_INTEGRITY TRUE");
|
||||
this.dbDdlSyntax.setForeignKeySuffix("on delete restrict on update restrict");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import com.avaje.ebean.BackgroundExecutor;
|
||||
import com.avaje.ebean.dbmigration.ddlgeneration.platform.HsqldbDdl;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.Types;
|
||||
@@ -14,32 +15,18 @@ public class HsqldbPlatform extends DatabasePlatform {
|
||||
super();
|
||||
this.name = "hsqldb";
|
||||
this.dbEncrypt = new H2DbEncrypt();
|
||||
this.platformDdl = new HsqldbDdl(dbTypeMap, dbIdentity);
|
||||
|
||||
this.dbIdentity.setIdType(IdType.IDENTITY);
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(true);
|
||||
this.dbIdentity.setSupportsSequence(true);
|
||||
this.dbIdentity.setSupportsIdentity(true);
|
||||
|
||||
this.openQuote = "\"";
|
||||
this.closeQuote = "\"";
|
||||
|
||||
// H2 data types match default JDBC types
|
||||
// so no changes to dbTypeMap required
|
||||
dbTypeMap.put(Types.INTEGER, new DbType("integer", false));
|
||||
|
||||
this.dbDdlSyntax.setDropIfExists("if exists");
|
||||
this.dbDdlSyntax.setDisableReferentialIntegrity("SET DATABASE REFERENTIAL INTEGRITY FALSE");
|
||||
this.dbDdlSyntax.setEnableReferentialIntegrity("SET DATABASE REFERENTIAL INTEGRITY TRUE");
|
||||
this.dbDdlSyntax.setForeignKeySuffix("on delete restrict on update restrict");
|
||||
this.dbDdlSyntax.setIdentity("GENERATED BY DEFAULT AS IDENTITY (START WITH 1) ");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a H2 specific sequence IdGenerator that supports batch fetching
|
||||
* sequence values.
|
||||
*/
|
||||
@Override
|
||||
public IdGenerator createSequenceIdGenerator(BackgroundExecutor be,
|
||||
DataSource ds, String seqName, int batchSize) {
|
||||
public IdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds, String seqName, int batchSize) {
|
||||
|
||||
return new H2SequenceIdGenerator(be, ds, seqName, batchSize);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ public interface IdGenerator {
|
||||
/**
|
||||
* The name of the default UUID generator.
|
||||
*/
|
||||
static final String AUTO_UUID = "auto.uuid";
|
||||
String AUTO_UUID = "auto.uuid";
|
||||
|
||||
/**
|
||||
* Return the name of the IdGenerator. For sequences this is the sequence
|
||||
|
||||
@@ -26,6 +26,15 @@ public enum IdType {
|
||||
* id properties of type UUID.
|
||||
* </p>
|
||||
*/
|
||||
GENERATOR;
|
||||
GENERATOR,
|
||||
|
||||
/**
|
||||
* Expected that the identity is externally set (for example a ISO code for
|
||||
* country or currency or a user defined code for lookup tables).
|
||||
* <p>
|
||||
* Used when the key is a compound key or lookup table code.
|
||||
* </p>
|
||||
*/
|
||||
EXTERNAL
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import com.avaje.ebean.dbmigration.ddlgeneration.platform.MsSqlServerDdl;
|
||||
|
||||
import java.sql.Types;
|
||||
|
||||
/**
|
||||
@@ -21,8 +23,9 @@ public class MsSqlServer2005Platform extends DatabasePlatform {
|
||||
// due to lack of support for getGeneratedKeys in batch mode
|
||||
this.disallowBatchOnCascade = true;
|
||||
this.idInExpandedForm = true;
|
||||
this.selectCountWithAlias = true;
|
||||
this.sqlLimiter = new MsSqlServer2005SqlLimiter();
|
||||
this.dbDdlSyntax = new MsDdlSyntax();
|
||||
this.platformDdl = new MsSqlServerDdl(dbTypeMap, dbIdentity);
|
||||
this.dbIdentity.setIdType(IdType.IDENTITY);
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(true);
|
||||
this.dbIdentity.setSupportsIdentity(true);
|
||||
@@ -44,35 +47,9 @@ public class MsSqlServer2005Platform extends DatabasePlatform {
|
||||
dbTypeMap.put(Types.LONGVARBINARY, new DbType("image"));
|
||||
dbTypeMap.put(Types.LONGVARCHAR, new DbType("text"));
|
||||
|
||||
dbTypeMap.put(Types.DATE, new DbType("datetime"));
|
||||
dbTypeMap.put(Types.TIME, new DbType("datetime"));
|
||||
dbTypeMap.put(Types.TIMESTAMP, new DbType("datetime"));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* MS SQL Server specific DDL Syntax.
|
||||
*/
|
||||
public class MsDdlSyntax extends DbDdlSyntax {
|
||||
|
||||
MsDdlSyntax() {
|
||||
this.identity = "identity(1,1)";
|
||||
this.dropKeyConstraints = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return some DDL to disable constraints on the given table.
|
||||
*/
|
||||
public String dropKeyConstraintPrefix(String tableName, String fkName) {
|
||||
return "IF OBJECT_ID('"+fkName+"', 'F') IS NOT NULL";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return prefix text that goes before drop table.
|
||||
*/
|
||||
public String dropTablePrefix(String tableName) {
|
||||
return "IF OBJECT_ID('"+tableName+"', 'U') IS NOT NULL ";
|
||||
}
|
||||
dbTypeMap.put(Types.DATE, new DbType("date"));
|
||||
dbTypeMap.put(Types.TIME, new DbType("time"));
|
||||
dbTypeMap.put(Types.TIMESTAMP, new DbType("datetime2"));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -31,10 +31,11 @@ public class MsSqlServer2005SqlLimiter implements SqlLimiter {
|
||||
|
||||
if (firstRow < 1) {
|
||||
// just use top n
|
||||
sb.append(" select top ").append(lastRow).append(" ");
|
||||
sb.append(" select ");
|
||||
if (request.isDistinct()) {
|
||||
sb.append("distinct ");
|
||||
}
|
||||
sb.append(" top ").append(lastRow).append(" ");
|
||||
sb.append(request.getDbSql());
|
||||
return new SqlLimitResponse(sb.toString(), false);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
/**
|
||||
* Runtime support for @History with MySql.
|
||||
*/
|
||||
public class MySqlHistorySupport extends DbViewHistorySupport {
|
||||
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import com.avaje.ebean.BackgroundExecutor;
|
||||
import com.avaje.ebean.dbmigration.ddlgeneration.platform.MySqlDdl;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.Types;
|
||||
@@ -24,6 +25,8 @@ public class MySqlPlatform extends DatabasePlatform {
|
||||
this.likeClause = "like ? escape''";
|
||||
this.selectCountWithAlias = true;
|
||||
this.dbEncrypt = new MySqlDbEncrypt();
|
||||
this.platformDdl = new MySqlDdl(this.dbTypeMap, this.dbIdentity);
|
||||
this.historySupport = new MySqlHistorySupport();
|
||||
|
||||
this.dbIdentity.setIdType(IdType.IDENTITY);
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(true);
|
||||
@@ -43,12 +46,6 @@ public class MySqlPlatform extends DatabasePlatform {
|
||||
dbTypeMap.put(Types.BLOB, new MySqlBlob());
|
||||
dbTypeMap.put(Types.BINARY, new DbType("binary", 255));
|
||||
dbTypeMap.put(Types.VARBINARY, new DbType("varbinary", 255));
|
||||
|
||||
dbDdlSyntax.setMaxConstraintNameLength(64);
|
||||
dbDdlSyntax.setDisableReferentialIntegrity("SET FOREIGN_KEY_CHECKS=0");
|
||||
dbDdlSyntax.setEnableReferentialIntegrity("SET FOREIGN_KEY_CHECKS=1");
|
||||
dbDdlSyntax.setForeignKeySuffix("on delete restrict on update restrict");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
/**
|
||||
* Since Ebean v2.2.0 Oracle9 is no different from Oracle10.
|
||||
* <p>
|
||||
* This will be removed in the future.
|
||||
* </p>
|
||||
*/
|
||||
public class Oracle9Platform extends Oracle10Platform {
|
||||
|
||||
public Oracle9Platform() {
|
||||
super();
|
||||
}
|
||||
|
||||
}
|
||||
+7
-7
@@ -43,25 +43,25 @@ package com.avaje.ebean.config.dbplatform;
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class Oracle10DbEncrypt extends AbstractDbEncrypt {
|
||||
public class OracleDbEncrypt extends AbstractDbEncrypt {
|
||||
|
||||
/**
|
||||
* Constructs the Oracle10DbEncrypt with default encrypt and decrypt stored procedures.
|
||||
*/
|
||||
public Oracle10DbEncrypt() {
|
||||
public OracleDbEncrypt() {
|
||||
this("eb_encrypt", "eb_decrypt");
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the Oracle10DbEncrypt specifying encrypt and decrypt stored procedures.
|
||||
*
|
||||
* @param encryptfunction the encrypt stored procedure
|
||||
* @param decryptfunction the decrypt stored procedure
|
||||
* @param encryptFunction the encrypt stored procedure
|
||||
* @param decryptFunction the decrypt stored procedure
|
||||
*/
|
||||
public Oracle10DbEncrypt(String encryptfunction, String decryptfunction) {
|
||||
public OracleDbEncrypt(String encryptFunction, String decryptFunction) {
|
||||
|
||||
this.varcharEncryptFunction = new OraVarcharFunction(encryptfunction, decryptfunction);
|
||||
this.dateEncryptFunction = new OraDateFunction(encryptfunction, decryptfunction);
|
||||
this.varcharEncryptFunction = new OraVarcharFunction(encryptFunction, decryptFunction);
|
||||
this.dateEncryptFunction = new OraDateFunction(encryptFunction, decryptFunction);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
/**
|
||||
* Oracle Total recall based history support.
|
||||
*/
|
||||
public class OracleDbHistorySupport extends DbStandardHistorySupport {
|
||||
|
||||
/**
|
||||
* Return the ' as of timestamp ?' clause appended after the table name.
|
||||
*/
|
||||
@Override
|
||||
public String getAsOfViewSuffix(String asOfViewSuffix) {
|
||||
return " as of TIMESTAMP ?";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersionsBetweenSuffix(String asOfViewSuffix) {
|
||||
return " versions between timestamp ? and ?";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Oracle specific effective start column.
|
||||
*/
|
||||
@Override
|
||||
public String getSysPeriodLower(String tableAlias, String sysPeriod) {
|
||||
return "versions_starttime";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Oracle specific effective end column.
|
||||
*/
|
||||
@Override
|
||||
public String getSysPeriodUpper(String tableAlias, String sysPeriod) {
|
||||
return "versions_endtime";
|
||||
}
|
||||
|
||||
}
|
||||
+9
-9
@@ -1,6 +1,7 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import com.avaje.ebean.BackgroundExecutor;
|
||||
import com.avaje.ebean.dbmigration.ddlgeneration.platform.Oracle10Ddl;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.Types;
|
||||
@@ -8,15 +9,19 @@ import java.sql.Types;
|
||||
/**
|
||||
* Oracle10 and greater specific platform.
|
||||
*/
|
||||
public class Oracle10Platform extends DatabasePlatform {
|
||||
public class OraclePlatform extends DatabasePlatform {
|
||||
|
||||
public Oracle10Platform() {
|
||||
public OraclePlatform() {
|
||||
super();
|
||||
this.name = "oracle";
|
||||
this.maxTableNameLength = 30;
|
||||
this.maxConstraintNameLength = 30;
|
||||
// OnQueryOnly.CLOSE as a performance optimisation on Oracle
|
||||
this.onQueryOnly = OnQueryOnly.CLOSE;
|
||||
this.dbEncrypt = new Oracle10DbEncrypt();
|
||||
this.dbEncrypt = new OracleDbEncrypt();
|
||||
this.sqlLimiter = new RownumSqlLimiter();
|
||||
this.platformDdl = new Oracle10Ddl(this.dbTypeMap, this.dbIdentity);
|
||||
this.historySupport = new OracleDbHistorySupport();
|
||||
|
||||
// Not using getGeneratedKeys as instead we will
|
||||
// batch load sequences which enables JDBC batch execution
|
||||
@@ -48,15 +53,10 @@ public class Oracle10Platform extends DatabasePlatform {
|
||||
dbTypeMap.put(Types.BINARY, new DbType("raw", 255));
|
||||
|
||||
dbTypeMap.put(Types.TIME, new DbType("timestamp"));
|
||||
|
||||
dbDdlSyntax.setDropTableCascade("cascade constraints purge");
|
||||
dbDdlSyntax.setIdentity(null);
|
||||
dbDdlSyntax.setMaxConstraintNameLength(30);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds,
|
||||
String seqName, int batchSize) {
|
||||
public IdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds, String seqName, int batchSize) {
|
||||
|
||||
return new OracleSequenceIdGenerator(be, ds, seqName, batchSize);
|
||||
}
|
||||
@@ -1,66 +1,20 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import com.avaje.ebean.BackgroundExecutor;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.Types;
|
||||
|
||||
/**
|
||||
* Postgres v8.3 specific platform.
|
||||
* <p>
|
||||
* No support for getGeneratedKeys.
|
||||
* </p>
|
||||
*/
|
||||
public class Postgres8Platform extends DatabasePlatform {
|
||||
public class Postgres8Platform extends PostgresPlatform {
|
||||
|
||||
public Postgres8Platform() {
|
||||
super();
|
||||
this.name = "postgres";
|
||||
this.selectCountWithAlias = true;
|
||||
this.blobDbType = Types.LONGVARBINARY;
|
||||
this.clobDbType = Types.VARCHAR;
|
||||
|
||||
this.dbEncrypt = new PostgresDbEncrypt();
|
||||
this.historySupport = new PostgresHistorySupport();
|
||||
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(false);
|
||||
this.dbIdentity.setIdType(IdType.SEQUENCE);
|
||||
this.dbIdentity.setSupportsSequence(true);
|
||||
|
||||
this.dbIdentity.setSupportsIdentity(true);
|
||||
this.columnAliasPrefix = "as c";
|
||||
this.openQuote = "\"";
|
||||
this.closeQuote = "\"";
|
||||
|
||||
// dbTypeMap.put(Types.BOOLEAN, new DbType("bit default 0"));
|
||||
|
||||
dbTypeMap.put(Types.INTEGER, new DbType("integer", false));
|
||||
dbTypeMap.put(Types.DOUBLE, new DbType("float"));
|
||||
dbTypeMap.put(Types.TINYINT, new DbType("smallint"));
|
||||
dbTypeMap.put(Types.DECIMAL, new DbType("decimal", 38));
|
||||
|
||||
dbTypeMap.put(Types.BINARY, new DbType("bytea", false));
|
||||
dbTypeMap.put(Types.VARBINARY, new DbType("bytea", false));
|
||||
|
||||
dbTypeMap.put(Types.BLOB, new DbType("bytea", false));
|
||||
dbTypeMap.put(Types.CLOB, new DbType("text"));
|
||||
dbTypeMap.put(Types.LONGVARBINARY, new DbType("bytea", false));
|
||||
dbTypeMap.put(Types.LONGVARCHAR, new DbType("text"));
|
||||
|
||||
dbDdlSyntax.setDropTableCascade("cascade");
|
||||
dbDdlSyntax.setDropIfExists("if exists");
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Postgres specific sequence IdGenerator.
|
||||
*/
|
||||
@Override
|
||||
public IdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds, String seqName, int batchSize) {
|
||||
|
||||
return new PostgresSequenceIdGenerator(be, ds, seqName, batchSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String withForUpdate(String sql) {
|
||||
return sql + " for update";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
public class PostgresDdlSyntax extends DbDdlSyntax {
|
||||
|
||||
/**
|
||||
* Map bigint, integer and smallint into their equivilent serial types.
|
||||
*/
|
||||
@Override
|
||||
public String getIdentityColumnDefn(String columnDefn) {
|
||||
|
||||
//smallserial, serial and bigserial
|
||||
if ("bigint".equalsIgnoreCase(columnDefn)) {
|
||||
return "bigserial";
|
||||
}
|
||||
if ("integer".equalsIgnoreCase(columnDefn)) {
|
||||
return "serial";
|
||||
}
|
||||
if ("smallint".equalsIgnoreCase(columnDefn)) {
|
||||
return "smallserial";
|
||||
}
|
||||
|
||||
return columnDefn;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,7 +3,15 @@ package com.avaje.ebean.config.dbplatform;
|
||||
/**
|
||||
* Postgres support for history features.
|
||||
*/
|
||||
public class PostgresHistorySupport implements DbHistorySupport {
|
||||
public class PostgresHistorySupport extends DbViewHistorySupport {
|
||||
|
||||
/**
|
||||
* Return 1 as we are using the postgres range type and hence don't need 2 bind variables.
|
||||
*/
|
||||
@Override
|
||||
public int getBindCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build and return the 'as of' predicate for a given table alias.
|
||||
@@ -16,18 +24,16 @@ public class PostgresHistorySupport implements DbHistorySupport {
|
||||
|
||||
// for Postgres we are using the 'timestamp with timezone range' data type
|
||||
// as our sys_period column so hence the predicate below
|
||||
StringBuilder sb = new StringBuilder(40);
|
||||
sb.append(asOfTableAlias).append(".").append(asOfSysPeriod).append(" @> ?::timestamptz");
|
||||
return sb.toString();
|
||||
return asOfTableAlias + "." + asOfSysPeriod + " @> ?::timestamptz";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSysPeriodLower(String tableAlias, String sysPeriod) {
|
||||
return "lower("+tableAlias+"."+sysPeriod+")";
|
||||
return "lower(" + tableAlias + "." + sysPeriod + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSysPeriodUpper(String tableAlias, String sysPeriod) {
|
||||
return "upper("+tableAlias+"."+sysPeriod+")";
|
||||
return "upper(" + tableAlias + "." + sysPeriod + ")";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import com.avaje.ebean.BackgroundExecutor;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.dbmigration.ddlgeneration.DdlHandler;
|
||||
import com.avaje.ebean.dbmigration.ddlgeneration.platform.PostgresDdl;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.Types;
|
||||
@@ -16,29 +19,32 @@ public class PostgresPlatform extends DatabasePlatform {
|
||||
public PostgresPlatform() {
|
||||
super();
|
||||
this.name = "postgres";
|
||||
|
||||
// OnQueryOnly.CLOSE as a performance optimisation on Postgres
|
||||
this.onQueryOnly = OnQueryOnly.CLOSE;
|
||||
this.likeClause = "like ? escape''";
|
||||
|
||||
this.dbDdlSyntax = new PostgresDdlSyntax();
|
||||
|
||||
|
||||
this.selectCountWithAlias = true;
|
||||
this.blobDbType = Types.LONGVARBINARY;
|
||||
this.clobDbType = Types.VARCHAR;
|
||||
|
||||
this.dbEncrypt = new PostgresDbEncrypt();
|
||||
this.historySupport = new PostgresHistorySupport();
|
||||
this.platformDdl = new PostgresDdl(this.dbTypeMap, this.dbIdentity);
|
||||
|
||||
// Use Identity and getGeneratedKeys
|
||||
this.dbIdentity.setIdType(IdType.IDENTITY);
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(true);
|
||||
this.dbIdentity.setSupportsSequence(true);
|
||||
|
||||
this.columnAliasPrefix = "as c";
|
||||
//this.columnAliasPrefix = "as c";
|
||||
|
||||
this.openQuote = "\"";
|
||||
this.closeQuote = "\"";
|
||||
|
||||
DbType dbTypeText = new DbType("text");
|
||||
DbType dbBytea = new DbType("bytea", false);
|
||||
|
||||
dbTypeMap.put(DbType.HSTORE, new DbType("hstore"));
|
||||
dbTypeMap.put(DbType.JSON, new DbType("json"));
|
||||
dbTypeMap.put(DbType.JSONB, new DbType("jsonb"));
|
||||
@@ -48,18 +54,22 @@ public class PostgresPlatform extends DatabasePlatform {
|
||||
dbTypeMap.put(Types.TINYINT, new DbType("smallint"));
|
||||
dbTypeMap.put(Types.DECIMAL, new DbType("decimal", 38));
|
||||
|
||||
dbTypeMap.put(Types.BINARY, new DbType("bytea", false));
|
||||
dbTypeMap.put(Types.VARBINARY, new DbType("bytea", false));
|
||||
dbTypeMap.put(Types.BINARY, dbBytea);
|
||||
dbTypeMap.put(Types.VARBINARY, dbBytea);
|
||||
|
||||
dbTypeMap.put(Types.BLOB, new DbType("bytea", false));
|
||||
dbTypeMap.put(Types.CLOB, new DbType("text"));
|
||||
dbTypeMap.put(Types.LONGVARBINARY, new DbType("bytea", false));
|
||||
dbTypeMap.put(Types.LONGVARCHAR, new DbType("text"));
|
||||
dbTypeMap.put(Types.BLOB, dbBytea);
|
||||
dbTypeMap.put(Types.CLOB, dbTypeText);
|
||||
dbTypeMap.put(Types.LONGVARBINARY, dbBytea);
|
||||
dbTypeMap.put(Types.LONGVARCHAR, dbTypeText);
|
||||
|
||||
dbDdlSyntax.setDropTableCascade("cascade");
|
||||
dbDdlSyntax.setDropIfExists("if exists");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a DdlHandler instance for generating DDL for the specific platform.
|
||||
*/
|
||||
public DdlHandler createDdlHandler(ServerConfig serverConfig) {
|
||||
return this.platformDdl.createDdlHandler(serverConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Postgres specific sequence IdGenerator.
|
||||
|
||||
@@ -1,22 +1,20 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import com.avaje.ebean.dbmigration.ddlgeneration.platform.SQLiteDdl;
|
||||
|
||||
import java.sql.Types;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import com.avaje.ebean.BackgroundExecutor;
|
||||
|
||||
public class SQLitePlatform extends DatabasePlatform {
|
||||
|
||||
public SQLitePlatform() {
|
||||
super();
|
||||
this.name = "sqlite";
|
||||
this.platformDdl = new SQLiteDdl(dbTypeMap, dbIdentity);
|
||||
|
||||
this.dbIdentity.setIdType(IdType.IDENTITY);
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(false);
|
||||
this.dbIdentity.setSupportsSequence(false);
|
||||
this.dbIdentity.setSelectLastInsertedIdTemplate("select last_insert_rowid()");
|
||||
this.openQuote = "\"";
|
||||
this.closeQuote = "\"";
|
||||
|
||||
this.booleanDbType = Types.INTEGER;
|
||||
|
||||
@@ -24,25 +22,7 @@ public class SQLitePlatform extends DatabasePlatform {
|
||||
dbTypeMap.put(Types.BOOLEAN, new DbType("int default 0"));
|
||||
dbTypeMap.put(Types.BIGINT, new DbType("integer"));
|
||||
dbTypeMap.put(Types.SMALLINT, new DbType("integer"));
|
||||
|
||||
dbDdlSyntax.setInlinePrimaryKeyConstraint(true);
|
||||
|
||||
// AutoIncrement goes the primary key declaration
|
||||
dbDdlSyntax.setIdentity("");
|
||||
dbDdlSyntax.setIdentitySuffix("AUTOINCREMENT");
|
||||
|
||||
dbDdlSyntax.setDisableReferentialIntegrity("PRAGMA foreign_keys = OFF");
|
||||
dbDdlSyntax.setEnableReferentialIntegrity("PRAGMA foreign_keys = ON");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return null in case there is a sequence annotation.
|
||||
*/
|
||||
@Override
|
||||
public IdGenerator createSequenceIdGenerator(BackgroundExecutor be,
|
||||
DataSource ds, String seqName, int batchSize) {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ public abstract class SequenceIdGenerator implements IdGenerator {
|
||||
|
||||
protected final ArrayList<Long> idList = new ArrayList<Long>(50);
|
||||
|
||||
protected int batchSize;
|
||||
protected final int batchSize;
|
||||
|
||||
protected int currentlyBackgroundLoading;
|
||||
|
||||
|
||||
@@ -61,8 +61,7 @@ public class SimpleSequenceIdGenerator implements IdGenerator {
|
||||
pstmt = c.prepareStatement(sql);
|
||||
rset = pstmt.executeQuery();
|
||||
if (rset.next()) {
|
||||
int val = rset.getInt(1);
|
||||
return Integer.valueOf(val);
|
||||
return rset.getInt(1);
|
||||
} else {
|
||||
String m = "Always expecting 1 row from " + sql;
|
||||
throw new PersistenceException(m);
|
||||
|
||||
@@ -11,7 +11,6 @@ import java.sql.Types;
|
||||
* </ul>
|
||||
* </p>
|
||||
*/
|
||||
|
||||
public class SqlAnywherePlatform extends DatabasePlatform {
|
||||
|
||||
public SqlAnywherePlatform() {
|
||||
|
||||
@@ -11,12 +11,7 @@ public interface SqlLimiter {
|
||||
* Note that this is removed for logging sql to the transaction log.
|
||||
* </p>
|
||||
*/
|
||||
static final char NEW_LINE = '\n';
|
||||
|
||||
/**
|
||||
* The carriage return character.
|
||||
*/
|
||||
static final char CARRIAGE_RETURN = '\r';
|
||||
char NEW_LINE = '\n';
|
||||
|
||||
/**
|
||||
* Add the SQL limiting statements around the query.
|
||||
|
||||
@@ -0,0 +1,327 @@
|
||||
package com.avaje.ebean.dbmigration;
|
||||
|
||||
import com.avaje.ebean.Ebean;
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.config.DbConstraintNaming;
|
||||
import com.avaje.ebean.config.DbMigrationConfig;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.config.dbplatform.DB2Platform;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebean.config.dbplatform.DbPlatformName;
|
||||
import com.avaje.ebean.config.dbplatform.H2Platform;
|
||||
import com.avaje.ebean.config.dbplatform.MsSqlServer2005Platform;
|
||||
import com.avaje.ebean.config.dbplatform.MySqlPlatform;
|
||||
import com.avaje.ebean.config.dbplatform.OraclePlatform;
|
||||
import com.avaje.ebean.config.dbplatform.PostgresPlatform;
|
||||
import com.avaje.ebean.config.dbplatform.SQLitePlatform;
|
||||
import com.avaje.ebean.dbmigration.ddlgeneration.DdlWrite;
|
||||
import com.avaje.ebean.dbmigration.migration.Migration;
|
||||
import com.avaje.ebean.dbmigration.migrationreader.MigrationXmlWriter;
|
||||
import com.avaje.ebean.dbmigration.model.CurrentModel;
|
||||
import com.avaje.ebean.dbmigration.model.MConfiguration;
|
||||
import com.avaje.ebean.dbmigration.model.MigrationModel;
|
||||
import com.avaje.ebean.dbmigration.model.ModelContainer;
|
||||
import com.avaje.ebean.dbmigration.model.PlatformDdlWriter;
|
||||
import com.avaje.ebean.dbmigration.model.ModelDiff;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Generates DB Migration xml and sql scripts.
|
||||
* <p>
|
||||
* Reads the prior migrations and compares with the current model of the EbeanServer
|
||||
* and generates a migration 'diff' in the form of xml document with the logical schema
|
||||
* changes and a series of sql scripts to apply, rollback the applied changes if necessary
|
||||
* and drop objects (drop tables, drop columns).
|
||||
* </p>
|
||||
* <p>
|
||||
* This does not run the migration or ddl scripts but just generates them.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* DbMigration migration = new DbMigration();
|
||||
* migration.setPathToResources("src/main/resources");
|
||||
* migration.setPlatform(DbPlatformName.ORACLE);
|
||||
*
|
||||
* migration.generateMigration();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public class DbMigration {
|
||||
|
||||
protected static final Logger logger = LoggerFactory.getLogger(DbMigration.class);
|
||||
|
||||
protected SpiEbeanServer server;
|
||||
|
||||
protected DbMigrationConfig migrationConfig;
|
||||
|
||||
protected String pathToResources = "src/main/resources";
|
||||
|
||||
protected DatabasePlatform databasePlatform;
|
||||
|
||||
protected List<Pair> platforms = new ArrayList<Pair>();
|
||||
|
||||
protected ServerConfig serverConfig;
|
||||
|
||||
protected DbConstraintNaming constraintNaming;
|
||||
|
||||
public DbMigration() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the path from the current working directory to the application resources.
|
||||
*
|
||||
* This defaults to maven style 'src/main/resources'.
|
||||
*/
|
||||
public void setPathToResources(String pathToResources) {
|
||||
this.pathToResources = pathToResources;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the server to use to determine the current model.
|
||||
* Typically this is not called explicitly.
|
||||
*/
|
||||
public void setServer(EbeanServer ebeanServer) {
|
||||
this.server = (SpiEbeanServer) ebeanServer;
|
||||
setServerConfig(server.getServerConfig());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the serverConfig to use. Typically this is not called explicitly.
|
||||
*/
|
||||
public void setServerConfig(ServerConfig config) {
|
||||
if (this.serverConfig == null) {
|
||||
this.serverConfig = config;
|
||||
}
|
||||
if (migrationConfig == null) {
|
||||
this.migrationConfig = serverConfig.getMigrationConfig();
|
||||
}
|
||||
if (constraintNaming == null) {
|
||||
this.constraintNaming = serverConfig.getConstraintNaming();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the specific platform to generate DDL for.
|
||||
* <p>
|
||||
* If not set this defaults to the platform of the default server.
|
||||
* </p>
|
||||
*/
|
||||
public void setPlatform(DbPlatformName platform) {
|
||||
setPlatform(getPlatform(platform));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the specific platform to generate DDL for.
|
||||
* <p>
|
||||
* If not set this defaults to the platform of the default server.
|
||||
* </p>
|
||||
*/
|
||||
public void setPlatform(DatabasePlatform databasePlatform) {
|
||||
this.databasePlatform = databasePlatform;
|
||||
DbOffline.setPlatform(databasePlatform.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an additional platform to write the migration DDL.
|
||||
* <p>
|
||||
* Use this when you want to generate sql scripts for multiple database platforms
|
||||
* from the migration (e.g. generate migration sql for MySql, Postgres and Oracle).
|
||||
* </p>
|
||||
*/
|
||||
public void addPlatform(DbPlatformName platform, String prefix) {
|
||||
if (!prefix.endsWith("-")) {
|
||||
prefix += "-";
|
||||
}
|
||||
platforms.add(new Pair(getPlatform(platform), prefix));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the next migration xml file and associated apply and rollback sql scripts.
|
||||
* <p>
|
||||
* This does not run the migration or ddl scripts but just generates them.
|
||||
* </p>
|
||||
* <h3>Example: Run for a single specific platform</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* DbMigration migration = new DbMigration();
|
||||
* migration.setPathToResources("src/main/resources");
|
||||
* migration.setPlatform(DbPlatformName.ORACLE);
|
||||
*
|
||||
* migration.generateMigration();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Example: Run migration generating DDL for multiple platforms</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* DbMigration migration = new DbMigration();
|
||||
* migration.setPathToResources("src/main/resources");
|
||||
*
|
||||
* migration.addPlatform(DbPlatformName.POSTGRES, "pg");
|
||||
* migration.addPlatform(DbPlatformName.MYSQL, "mysql");
|
||||
* migration.addPlatform(DbPlatformName.ORACLE, "mysql");
|
||||
*
|
||||
* migration.generateMigration();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public void generateMigration() throws IOException {
|
||||
|
||||
// use this flag to stop other plugins like full DDL generation
|
||||
DbOffline.setRunningMigration();
|
||||
|
||||
setDefaults();
|
||||
|
||||
try {
|
||||
MigrationModel migrationModel = new MigrationModel(migrationConfig.getResourcePath());
|
||||
ModelContainer migrated = migrationModel.read();
|
||||
int nextMajorVersion = migrationModel.getNextMajorVersion();
|
||||
|
||||
logger.info("next migration version {}", nextMajorVersion);
|
||||
|
||||
CurrentModel currentModel = new CurrentModel(server, constraintNaming);
|
||||
ModelContainer current = currentModel.read();
|
||||
|
||||
ModelDiff diff = new ModelDiff(migrated);
|
||||
diff.compareTo(current);
|
||||
|
||||
if (diff.isEmpty()) {
|
||||
logger.info("no changes detected - no migration written");
|
||||
return;
|
||||
}
|
||||
|
||||
// there were actually changes to write
|
||||
Migration dbMigration = diff.getMigration();
|
||||
|
||||
File writePath = getWritePath();
|
||||
logger.info("migration writing version {} to {}", nextMajorVersion, writePath.getAbsolutePath());
|
||||
writeMigrationXml(dbMigration, writePath, nextMajorVersion);
|
||||
|
||||
if (databasePlatform != null) {
|
||||
// writer needs the current model to provide table/column details for
|
||||
// history ddl generation (triggers, history tables etc)
|
||||
DdlWrite write = new DdlWrite(new MConfiguration(), currentModel.read());
|
||||
PlatformDdlWriter writer = new PlatformDdlWriter(databasePlatform, serverConfig);
|
||||
writer.processMigration(dbMigration, write, writePath, nextMajorVersion);
|
||||
}
|
||||
|
||||
writeExtraPlatformDdl(nextMajorVersion, currentModel, dbMigration, writePath);
|
||||
|
||||
} finally {
|
||||
DbOffline.reset();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write any extra platform ddl.
|
||||
*/
|
||||
protected void writeExtraPlatformDdl(int nextMajorVersion, CurrentModel currentModel, Migration dbMigration, File writePath) throws IOException {
|
||||
|
||||
for (Pair pair : platforms) {
|
||||
DdlWrite platformBuffer = new DdlWrite(new MConfiguration(), currentModel.read());
|
||||
|
||||
PlatformDdlWriter platformWriter = new PlatformDdlWriter(pair.platform, serverConfig, pair.prefix);
|
||||
platformWriter.processMigration(dbMigration, platformBuffer, writePath, nextMajorVersion);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the migration xml.
|
||||
*/
|
||||
protected void writeMigrationXml(Migration dbMigration, File resourcePath, int migrationVersion) {
|
||||
|
||||
File file = new File(resourcePath, "v"+migrationVersion+".0.xml");
|
||||
MigrationXmlWriter xmlWriter = new MigrationXmlWriter();
|
||||
xmlWriter.write(dbMigration, file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set default server and platform if necessary.
|
||||
*/
|
||||
protected void setDefaults() {
|
||||
if (server == null) {
|
||||
setServer(Ebean.getDefaultServer());
|
||||
}
|
||||
if (databasePlatform == null && platforms.isEmpty()) {
|
||||
// not explicitly set not set a list of platforms so
|
||||
// default to the platform of the default server
|
||||
databasePlatform = server.getDatabasePlatform();
|
||||
logger.debug("set platform to {}", databasePlatform.getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the file path to write the xml and sql to.
|
||||
*/
|
||||
protected File getWritePath() {
|
||||
|
||||
// path to src/main/resources in typical maven project
|
||||
File resourceRootDir = new File(pathToResources);
|
||||
|
||||
String resourcePath = migrationConfig.getResourcePath();
|
||||
|
||||
// expect to be a path to something like - src/main/resources/dbmigration/myapp
|
||||
File path = new File(resourceRootDir, resourcePath);
|
||||
if (!path.exists()) {
|
||||
if (!path.mkdirs()) {
|
||||
logger.debug("Unable to ensure migration directory exists at {}", path.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DatabasePlatform given the platform key.
|
||||
*/
|
||||
protected DatabasePlatform getPlatform(DbPlatformName platform) {
|
||||
switch (platform) {
|
||||
case H2:
|
||||
return new H2Platform();
|
||||
case POSTGRES:
|
||||
return new PostgresPlatform();
|
||||
case MYSQL:
|
||||
return new MySqlPlatform();
|
||||
case ORACLE:
|
||||
return new OraclePlatform();
|
||||
case SQLSERVER:
|
||||
return new MsSqlServer2005Platform();
|
||||
case DB2:
|
||||
return new DB2Platform();
|
||||
case SQLITE:
|
||||
return new SQLitePlatform();
|
||||
|
||||
default:
|
||||
throw new IllegalArgumentException("Platform missing? " + platform);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds a platform and prefix. Used to generate multiple platform specific DDL
|
||||
* for a single migration.
|
||||
*/
|
||||
public static class Pair {
|
||||
|
||||
/**
|
||||
* The platform to generate the DDL for.
|
||||
*/
|
||||
public final DatabasePlatform platform;
|
||||
|
||||
/**
|
||||
* A prefix included into the file/resource names indicating the platform.
|
||||
*/
|
||||
public final String prefix;
|
||||
|
||||
public Pair(DatabasePlatform platform, String prefix) {
|
||||
this.platform = platform;
|
||||
this.prefix = prefix;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package com.avaje.ebean.dbmigration;
|
||||
|
||||
import com.avaje.ebean.config.dbplatform.DbPlatformName;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Helper to indicate that an EbeanServer should come up offline
|
||||
* typically for DDL generation purposes.
|
||||
*/
|
||||
public class DbOffline {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DbOffline.class);
|
||||
|
||||
private static final String KEY = "ebean.dboffline";
|
||||
|
||||
private static boolean runningMigration;
|
||||
|
||||
/**
|
||||
* Set the platform to use when creating the next EbeanServer instance.
|
||||
*/
|
||||
public static void setPlatform(DbPlatformName dbPlatform) {
|
||||
System.setProperty(KEY, dbPlatform.name());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the platform to use when creating the next EbeanServer instance.
|
||||
*/
|
||||
public static void setPlatform(String platformName) {
|
||||
System.setProperty(KEY, platformName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the platform to use when creating the next EbeanServer instance.
|
||||
*/
|
||||
public static String getPlatform() {
|
||||
return System.getProperty(KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bring up the next EbeanServer instance using the H2 platform.
|
||||
*/
|
||||
public static void asH2() {
|
||||
setPlatform(DbPlatformName.H2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the offline platform has been set.
|
||||
*/
|
||||
public static boolean isSet() {
|
||||
return getPlatform() != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the migration is running. This typically means don't run the
|
||||
* plugins like full DDL generation.
|
||||
*/
|
||||
public static boolean isRunningMigration() {
|
||||
return runningMigration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the migration is running is order to stop other plugins
|
||||
* like the full DDL generation from executing.
|
||||
*/
|
||||
public static void setRunningMigration() {
|
||||
runningMigration = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the offline platform and runningMigration flag.
|
||||
*/
|
||||
public static void reset() {
|
||||
runningMigration = false;
|
||||
System.clearProperty(KEY);
|
||||
logger.debug("reset");
|
||||
}
|
||||
|
||||
}
|
||||
+109
-94
@@ -1,5 +1,14 @@
|
||||
package com.avaje.ebeaninternal.server.ddl;
|
||||
package com.avaje.ebean.dbmigration;
|
||||
|
||||
import com.avaje.ebean.Transaction;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.dbmigration.model.CurrentModel;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanPlugin;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
@@ -13,18 +22,6 @@ import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.avaje.ebean.Transaction;
|
||||
import com.avaje.ebean.config.NamingConvention;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanPlugin;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
|
||||
/**
|
||||
* Controls the generation of DDL and potentially runs the resulting scripts.
|
||||
*/
|
||||
@@ -34,24 +31,17 @@ public class DdlGenerator implements SpiEbeanPlugin {
|
||||
|
||||
private SpiEbeanServer server;
|
||||
|
||||
private DatabasePlatform dbPlatform;
|
||||
|
||||
private int summaryLength = 80;
|
||||
|
||||
private boolean generateDdl;
|
||||
private boolean runDdl;
|
||||
|
||||
private CurrentModel currentModel;
|
||||
private String dropContent;
|
||||
private String createContent;
|
||||
|
||||
private NamingConvention namingConvention;
|
||||
|
||||
public void setup(SpiEbeanServer server, DatabasePlatform dbPlatform, ServerConfig serverConfig) {
|
||||
public void setup(SpiEbeanServer server, ServerConfig serverConfig) {
|
||||
this.server = server;
|
||||
this.dbPlatform = dbPlatform;
|
||||
this.generateDdl = serverConfig.isDdlGenerate();
|
||||
this.runDdl = serverConfig.isDdlRun();
|
||||
this.namingConvention = serverConfig.getNamingConvention();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -103,10 +93,8 @@ public class DdlGenerator implements SpiEbeanPlugin {
|
||||
try {
|
||||
String c = generateDropDdl();
|
||||
writeFile(dropFile, c);
|
||||
|
||||
} catch (IOException e) {
|
||||
String msg = "Error generating Drop DDL";
|
||||
throw new PersistenceException(msg, e);
|
||||
throw new PersistenceException("Error generating Drop DDL", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,65 +103,44 @@ public class DdlGenerator implements SpiEbeanPlugin {
|
||||
try {
|
||||
String c = generateCreateDdl();
|
||||
writeFile(createFile, c);
|
||||
|
||||
} catch (IOException e) {
|
||||
String msg = "Error generating Create DDL";
|
||||
throw new PersistenceException(msg, e);
|
||||
throw new PersistenceException("Error generating Create DDL", e);
|
||||
}
|
||||
}
|
||||
|
||||
public String generateDropDdl() {
|
||||
|
||||
DdlGenContext ctx = createContext();
|
||||
|
||||
if (ctx.getDdlSyntax().isDropKeyConstraints()) {
|
||||
// generate drop foreign key constraint statements (sql server joy)
|
||||
AddForeignKeysVisitor fkeys = new AddForeignKeysVisitor(false, ctx);
|
||||
VisitorUtil.visit(server, fkeys);
|
||||
ctx.writeNewLine();
|
||||
try {
|
||||
dropContent = currentModel().getDropDdl();
|
||||
return dropContent;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
DropTableVisitor drop = new DropTableVisitor(ctx);
|
||||
VisitorUtil.visit(server, drop);
|
||||
|
||||
DropSequenceVisitor dropSequence = new DropSequenceVisitor(ctx);
|
||||
VisitorUtil.visit(server, dropSequence);
|
||||
|
||||
ctx.flush();
|
||||
dropContent = ctx.getContent();
|
||||
return dropContent;
|
||||
}
|
||||
|
||||
public String generateCreateDdl() {
|
||||
|
||||
DdlGenContext ctx = createContext();
|
||||
CreateTableVisitor create = new CreateTableVisitor(ctx);
|
||||
VisitorUtil.visit(server, create);
|
||||
|
||||
CreateSequenceVisitor createSequence = new CreateSequenceVisitor(ctx);
|
||||
VisitorUtil.visit(server, createSequence);
|
||||
|
||||
AddForeignKeysVisitor fkeys = new AddForeignKeysVisitor(true, ctx);
|
||||
VisitorUtil.visit(server, fkeys);
|
||||
|
||||
CreateIndexVisitor indexes = new CreateIndexVisitor(ctx);
|
||||
VisitorUtil.visit(server, indexes);
|
||||
|
||||
ctx.flush();
|
||||
createContent = ctx.getContent();
|
||||
return createContent;
|
||||
try {
|
||||
createContent = currentModel().getCreateDdl();
|
||||
return createContent;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected String getDropFileName() {
|
||||
return server.getName() + "-drop.sql";
|
||||
return server.getName() + "-drop-all.sql";
|
||||
}
|
||||
|
||||
protected String getCreateFileName() {
|
||||
return server.getName() + "-create.sql";
|
||||
return server.getName() + "-create-all.sql";
|
||||
}
|
||||
|
||||
protected DdlGenContext createContext() {
|
||||
return new DdlGenContext(dbPlatform, namingConvention);
|
||||
protected CurrentModel currentModel() {
|
||||
if (currentModel == null) {
|
||||
currentModel = new CurrentModel(server);
|
||||
}
|
||||
return currentModel;
|
||||
}
|
||||
|
||||
protected void writeFile(String fileName, String fileContent) throws IOException {
|
||||
@@ -201,7 +168,7 @@ public class DdlGenerator implements SpiEbeanPlugin {
|
||||
FileReader fr = new FileReader(f);
|
||||
LineNumberReader lr = new LineNumberReader(fr);
|
||||
try {
|
||||
String s = null;
|
||||
String s;
|
||||
while ((s = lr.readLine()) != null) {
|
||||
buf.append(s).append("\n");
|
||||
}
|
||||
@@ -233,8 +200,7 @@ public class DdlGenerator implements SpiEbeanPlugin {
|
||||
t.commit();
|
||||
|
||||
} catch (Exception e) {
|
||||
String msg = "Error: " + e.getMessage();
|
||||
throw new PersistenceException(msg, e);
|
||||
throw new PersistenceException("Error: " + e.getMessage(), e);
|
||||
} finally {
|
||||
t.end();
|
||||
}
|
||||
@@ -274,7 +240,7 @@ public class DdlGenerator implements SpiEbeanPlugin {
|
||||
stmt = stmt.substring(0, stmt.length() - 1);
|
||||
}
|
||||
|
||||
logger.trace("executing " + oneOf + " " + getSummary(stmt));
|
||||
logger.info("executing " + oneOf + " " + getSummary(stmt));
|
||||
|
||||
pstmt = c.prepareStatement(stmt);
|
||||
pstmt.execute();
|
||||
@@ -297,6 +263,74 @@ public class DdlGenerator implements SpiEbeanPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Local utility used to detect the end of statements / separate statements.
|
||||
* This is often just the semicolon character but for trigger/procedures this
|
||||
* detects the $$ demarcation used in the history DDL generation for MySql and
|
||||
* Postgres.
|
||||
*/
|
||||
static class StatementsSeparator {
|
||||
|
||||
ArrayList<String> statements = new ArrayList<String>();
|
||||
|
||||
boolean trimDelimiter;
|
||||
|
||||
boolean inDbProcedure;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
void lineContainsDollars(String line) {
|
||||
if (inDbProcedure) {
|
||||
if (trimDelimiter) {
|
||||
line = line.replace("$$","");
|
||||
}
|
||||
endOfStatement(line);
|
||||
} else {
|
||||
// MySql style delimiter needs to be trimmed/removed
|
||||
trimDelimiter = line.equals("delimiter $$");
|
||||
if (!trimDelimiter) {
|
||||
sb.append(line).append(" ");
|
||||
}
|
||||
}
|
||||
inDbProcedure = !inDbProcedure;
|
||||
}
|
||||
|
||||
void endOfStatement(String line) {
|
||||
// end of Db procedure
|
||||
sb.append(line);
|
||||
statements.add(sb.toString().trim());
|
||||
sb = new StringBuilder();
|
||||
}
|
||||
|
||||
void nextLine(String line) {
|
||||
|
||||
if (line.contains("$$")) {
|
||||
lineContainsDollars(line);
|
||||
return;
|
||||
}
|
||||
|
||||
if (inDbProcedure) {
|
||||
sb.append(line).append(" ");
|
||||
return;
|
||||
}
|
||||
|
||||
int semiPos = line.indexOf(';');
|
||||
if (semiPos == -1) {
|
||||
sb.append(line).append(" ");
|
||||
|
||||
} else if (semiPos == line.length() - 1) {
|
||||
// semicolon at end of line
|
||||
endOfStatement(line);
|
||||
|
||||
} else {
|
||||
// semicolon in middle of line
|
||||
String preSemi = line.substring(0, semiPos);
|
||||
endOfStatement(preSemi);
|
||||
sb.append(line.substring(semiPos + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Break up the sql in reader into a list of statements using the semi-colon
|
||||
* character;
|
||||
@@ -305,43 +339,24 @@ public class DdlGenerator implements SpiEbeanPlugin {
|
||||
|
||||
try {
|
||||
BufferedReader br = new BufferedReader(reader);
|
||||
StatementsSeparator statements = new StatementsSeparator();
|
||||
|
||||
ArrayList<String> statements = new ArrayList<String>();
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String s;
|
||||
while ((s = br.readLine()) != null) {
|
||||
s = s.trim();
|
||||
int semiPos = s.indexOf(';');
|
||||
if (semiPos == -1) {
|
||||
sb.append(s).append(" ");
|
||||
|
||||
} else if (semiPos == s.length() - 1) {
|
||||
// semicolon at end of line
|
||||
sb.append(s);
|
||||
statements.add(sb.toString().trim());
|
||||
sb = new StringBuilder();
|
||||
|
||||
} else {
|
||||
// semicolon in middle of line
|
||||
String preSemi = s.substring(0, semiPos);
|
||||
sb.append(preSemi);
|
||||
statements.add(sb.toString().trim());
|
||||
sb = new StringBuilder();
|
||||
sb.append(s.substring(semiPos + 1));
|
||||
|
||||
}
|
||||
statements.nextLine(s);
|
||||
}
|
||||
|
||||
return statements;
|
||||
return statements.statements;
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new PersistenceException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private String getSummary(String s) {
|
||||
if (s.length() > summaryLength) {
|
||||
return s.substring(0, summaryLength).trim() + "...";
|
||||
if (s.length() > 80) {
|
||||
return s.substring(0, 80).trim() + "...";
|
||||
}
|
||||
return s;
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package com.avaje.ebean.dbmigration.ddlgeneration;
|
||||
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.dbmigration.ddlgeneration.platform.BaseTableDdl;
|
||||
import com.avaje.ebean.dbmigration.ddlgeneration.platform.PlatformDdl;
|
||||
import com.avaje.ebean.dbmigration.migration.AddColumn;
|
||||
import com.avaje.ebean.dbmigration.migration.AddHistoryTable;
|
||||
import com.avaje.ebean.dbmigration.migration.AlterColumn;
|
||||
import com.avaje.ebean.dbmigration.migration.ChangeSet;
|
||||
import com.avaje.ebean.dbmigration.migration.CreateIndex;
|
||||
import com.avaje.ebean.dbmigration.migration.CreateTable;
|
||||
import com.avaje.ebean.dbmigration.migration.DropColumn;
|
||||
import com.avaje.ebean.dbmigration.migration.DropHistoryTable;
|
||||
import com.avaje.ebean.dbmigration.migration.DropIndex;
|
||||
import com.avaje.ebean.dbmigration.migration.DropTable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class BaseDdlHandler implements DdlHandler {
|
||||
|
||||
protected final TableDdl tableDdl;
|
||||
|
||||
public BaseDdlHandler(ServerConfig serverConfig, PlatformDdl platformDdl) {
|
||||
this.tableDdl = new BaseTableDdl(serverConfig, platformDdl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generate(DdlWrite writer, ChangeSet changeSet) throws IOException {
|
||||
|
||||
List<Object> changeSetChildren = changeSet.getChangeSetChildren();
|
||||
for (Object change : changeSetChildren) {
|
||||
if (change instanceof CreateTable) {
|
||||
generate(writer, (CreateTable) change);
|
||||
} else if (change instanceof DropTable) {
|
||||
generate(writer, (DropTable) change);
|
||||
} else if (change instanceof CreateIndex) {
|
||||
generate(writer, (CreateIndex) change);
|
||||
} else if (change instanceof DropIndex) {
|
||||
generate(writer, (DropIndex) change);
|
||||
} else if (change instanceof AddColumn) {
|
||||
generate(writer, (AddColumn) change);
|
||||
} else if (change instanceof DropColumn) {
|
||||
generate(writer, (DropColumn) change);
|
||||
} else if (change instanceof AlterColumn) {
|
||||
generate(writer, (AlterColumn) change);
|
||||
} else if (change instanceof AddHistoryTable) {
|
||||
generate(writer, (AddHistoryTable) change);
|
||||
} else if (change instanceof DropHistoryTable) {
|
||||
generate(writer, (DropHistoryTable) change);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateExtra(DdlWrite write) throws IOException {
|
||||
tableDdl.generateExtra(write);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generate(DdlWrite writer, CreateTable createTable) throws IOException {
|
||||
tableDdl.generate(writer, createTable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generate(DdlWrite writer, DropTable dropTable) throws IOException {
|
||||
tableDdl.generate(writer, dropTable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generate(DdlWrite writer, AddColumn addColumn) throws IOException {
|
||||
tableDdl.generate(writer, addColumn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generate(DdlWrite writer, DropColumn dropColumn) throws IOException {
|
||||
tableDdl.generate(writer, dropColumn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generate(DdlWrite writer, AlterColumn alterColumn) throws IOException {
|
||||
tableDdl.generate(writer, alterColumn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generate(DdlWrite writer, AddHistoryTable addHistoryTable) throws IOException {
|
||||
tableDdl.generate(writer, addHistoryTable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generate(DdlWrite writer, DropHistoryTable dropHistoryTable) throws IOException {
|
||||
tableDdl.generate(writer, dropHistoryTable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generate(DdlWrite writer, CreateIndex createIndex) throws IOException {
|
||||
tableDdl.generate(writer, createIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generate(DdlWrite writer, DropIndex dropIndex) throws IOException {
|
||||
tableDdl.generate(writer, dropIndex);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.avaje.ebean.dbmigration.ddlgeneration;
|
||||
|
||||
import com.avaje.ebean.dbmigration.migration.AddColumn;
|
||||
import com.avaje.ebean.dbmigration.migration.AlterColumn;
|
||||
import com.avaje.ebean.dbmigration.migration.DropColumn;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Write DDL for AddColumn , DropColumn or AlterColumn.
|
||||
*/
|
||||
public interface ColumnDdl {
|
||||
|
||||
/**
|
||||
* Write the add column change.
|
||||
*/
|
||||
void generate(DdlWrite writer, AddColumn addColumn) throws IOException;
|
||||
|
||||
/**
|
||||
* Write the drop column change.
|
||||
*/
|
||||
void generate(DdlWrite writer, DropColumn dropColumn) throws IOException;
|
||||
|
||||
/**
|
||||
* Write the alter column changes.
|
||||
*/
|
||||
void generate(DdlWrite writer, AlterColumn alterColumn) throws IOException;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.avaje.ebean.dbmigration.ddlgeneration;
|
||||
|
||||
import com.avaje.ebean.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.
|
||||
*/
|
||||
boolean isEmpty();
|
||||
|
||||
/**
|
||||
* Append DDL content to the buffer.
|
||||
*/
|
||||
DdlBuffer append(String content) throws IOException;
|
||||
|
||||
/**
|
||||
* Append DDL content to the buffer with space padding.
|
||||
*/
|
||||
DdlBuffer append(String type, int space) throws IOException;
|
||||
|
||||
/**
|
||||
* Append a value that is potentially null or empty and proceed it with a space if so.
|
||||
*/
|
||||
DdlBuffer appendWithSpace(String foreignKeyRestrict) throws IOException;
|
||||
|
||||
/**
|
||||
* Append new line character to the buffer.
|
||||
*/
|
||||
DdlBuffer newLine() throws IOException;
|
||||
|
||||
/**
|
||||
* Append the end of statement content.
|
||||
*/
|
||||
DdlBuffer endOfStatement() throws IOException;
|
||||
|
||||
/**
|
||||
* End of a change - add some whitespace.
|
||||
*/
|
||||
DdlBuffer end() throws IOException;
|
||||
|
||||
/**
|
||||
* Return the buffer content.
|
||||
*/
|
||||
String getBuffer();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.avaje.ebean.dbmigration.ddlgeneration;
|
||||
|
||||
import com.avaje.ebean.dbmigration.migration.AddColumn;
|
||||
import com.avaje.ebean.dbmigration.migration.AddHistoryTable;
|
||||
import com.avaje.ebean.dbmigration.migration.AlterColumn;
|
||||
import com.avaje.ebean.dbmigration.migration.ChangeSet;
|
||||
import com.avaje.ebean.dbmigration.migration.CreateIndex;
|
||||
import com.avaje.ebean.dbmigration.migration.CreateTable;
|
||||
import com.avaje.ebean.dbmigration.migration.DropColumn;
|
||||
import com.avaje.ebean.dbmigration.migration.DropHistoryTable;
|
||||
import com.avaje.ebean.dbmigration.migration.DropIndex;
|
||||
import com.avaje.ebean.dbmigration.migration.DropTable;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
*/
|
||||
public interface DdlHandler {
|
||||
|
||||
void generate(DdlWrite writer, ChangeSet changeSet) throws IOException;
|
||||
|
||||
void generate(DdlWrite writer, CreateTable createTable) throws IOException;
|
||||
|
||||
void generate(DdlWrite writer, DropTable dropTable) throws IOException;
|
||||
|
||||
void generate(DdlWrite writer, AddColumn addColumn) throws IOException;
|
||||
|
||||
void generate(DdlWrite writer, DropColumn dropColumn) throws IOException;
|
||||
|
||||
void generate(DdlWrite writer, AlterColumn alterColumn) throws IOException;
|
||||
|
||||
void generate(DdlWrite writer, AddHistoryTable addHistoryTable) throws IOException;
|
||||
|
||||
void generate(DdlWrite writer, DropHistoryTable dropHistoryTable) throws IOException;
|
||||
|
||||
void generate(DdlWrite writer, CreateIndex createIndex) throws IOException;
|
||||
|
||||
void generate(DdlWrite writer, DropIndex dropIndex) throws IOException;
|
||||
|
||||
void generateExtra(DdlWrite write) throws IOException;
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
package com.avaje.ebean.dbmigration.ddlgeneration;
|
||||
|
||||
import com.avaje.ebean.dbmigration.ddlgeneration.platform.BaseDdlBuffer;
|
||||
import com.avaje.ebean.dbmigration.model.MConfiguration;
|
||||
import com.avaje.ebean.dbmigration.model.MTable;
|
||||
import com.avaje.ebean.dbmigration.model.ModelContainer;
|
||||
|
||||
/**
|
||||
* Write context holding the buffers for both apply and rollback DDL.
|
||||
*/
|
||||
public class DdlWrite {
|
||||
|
||||
private final ModelContainer currentModel;
|
||||
|
||||
private final DdlBuffer apply;
|
||||
|
||||
private final DdlBuffer applyForeignKeys;
|
||||
|
||||
private final DdlBuffer applyHistory;
|
||||
|
||||
private final DdlBuffer rollbackForeignKeys;
|
||||
|
||||
private final DdlBuffer rollback;
|
||||
|
||||
/**
|
||||
* For DDL that drops tables and columns etc.
|
||||
*
|
||||
* This DDL typically can not run automatically in production as there is most commonly
|
||||
* existing servers running the application using these tables and columns. Typically
|
||||
* these drop statements may be executed AFTER all the servers in the application have
|
||||
* migrated onto new code.
|
||||
*/
|
||||
private final DdlBuffer drop;
|
||||
|
||||
/**
|
||||
* For use when History is turned off for a base table or history is no longer
|
||||
* desired on specific columns. This DDL should typically execute manually after review
|
||||
* by DBA's.
|
||||
*/
|
||||
private final DdlBuffer dropHistory;
|
||||
|
||||
/**
|
||||
* Create without any configuration or current model (no history support).
|
||||
*/
|
||||
public DdlWrite() {
|
||||
this(new MConfiguration(), new ModelContainer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create with a configuration.
|
||||
*/
|
||||
public DdlWrite(MConfiguration configuration, ModelContainer currentModel) {
|
||||
this.currentModel = currentModel;
|
||||
this.apply = new BaseDdlBuffer(configuration);
|
||||
this.applyForeignKeys = new BaseDdlBuffer(configuration);
|
||||
this.applyHistory = new BaseDdlBuffer(configuration);
|
||||
this.rollbackForeignKeys = new BaseDdlBuffer(configuration);
|
||||
this.rollback = new BaseDdlBuffer(configuration);
|
||||
this.drop = new BaseDdlBuffer(configuration);
|
||||
this.dropHistory = new BaseDdlBuffer(configuration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Table information from the current model.
|
||||
* <p>
|
||||
* This is typically required for the history support (used to determine the list of columns
|
||||
* included in the history when creating or recreating the associated trigger/stored procedure).
|
||||
* </p>
|
||||
*/
|
||||
public MTable getTable(String tableName) {
|
||||
return currentModel.getTable(tableName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the apply buffers are all empty.
|
||||
*/
|
||||
public boolean isApplyEmpty() {
|
||||
return apply.getBuffer().isEmpty()
|
||||
&& applyForeignKeys.getBuffer().isEmpty()
|
||||
&& applyHistory.getBuffer().isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the apply rollback buffers are all empty.
|
||||
*/
|
||||
public boolean isApplyRollbackEmpty() {
|
||||
return rollback.getBuffer().isEmpty()
|
||||
&& rollbackForeignKeys.getBuffer().isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true the drop buffers are empty.
|
||||
*/
|
||||
public boolean isDropEmpty() {
|
||||
return drop.getBuffer().isEmpty() && dropHistory.getBuffer().isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the buffer that APPLY DDL is written to.
|
||||
*/
|
||||
public DdlBuffer apply() {
|
||||
return apply;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the buffer that APPLY DDL is written to for foreign keys and their associated indexes.
|
||||
* <p>
|
||||
* Statements added to this buffer are executed after all the normal apply statements and
|
||||
* typically 'add foreign key' is added to this buffer.
|
||||
*/
|
||||
public DdlBuffer applyForeignKeys() {
|
||||
return applyForeignKeys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the buffer that apply history DDL is written to.
|
||||
*/
|
||||
public DdlBuffer applyHistory() {
|
||||
return applyHistory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the buffer that ROLLBACK DDL is written to for foreign keys and associated indexes.
|
||||
*/
|
||||
public DdlBuffer rollbackForeignKeys() {
|
||||
return rollbackForeignKeys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the buffer that ROLLBACK DDL is written to which is considered safe to run when
|
||||
* apply changes fail to execute. This will reverse the apply changes typically dropping
|
||||
* newly created tables, foreign keys etc.
|
||||
* <p>
|
||||
* When apply changes are made against DB's that support transactional DDL you could argue
|
||||
* that these rollback statements are not necessary.
|
||||
* <p>
|
||||
* Note that statements added to this rollback buffer are executed after foreign key rollback
|
||||
* has been executed.
|
||||
*/
|
||||
public DdlBuffer rollback() {
|
||||
return rollback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the buffer that destructive changes are written to. This is typically drop table and
|
||||
* drop column.
|
||||
*/
|
||||
public DdlBuffer drop() {
|
||||
return drop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the buffer that is used when history is no longer required on a table or specific columns.
|
||||
*/
|
||||
public DdlBuffer dropHistory() {
|
||||
return dropHistory;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user