Compare commits

..
Author SHA1 Message Date
rob bygrave 23a9cf9bb3 [maven-release-plugin] prepare release ebean-11.19.3 2018-08-08 12:05:50 +12:00
rob bygrave 75395a8481 #1464 - NPE in PropertiesWrapper.internalGet(PropertiesWrapper.java:74) running multi-platform DB migration generation with ServerConfig that has no properties
Note that newPlatformConfig() is only used for multi-platform DB migration generation.
2018-08-07 11:55:06 +12:00
rob bygrave a161d0c01b #1463 - NPE in MigrationModel.readMigrations() when running using File resources with no migration directory 2018-08-07 11:36:26 +12:00
rob bygrave 1dd7720605 #1462 - DB Migration generation with Postgis types gives us non-strict geometry column DDL 2018-08-07 11:19:09 +12:00
rob bygrave 3d2f885e87 [maven-release-plugin] prepare for next development iteration 2018-08-06 21:42:56 +12:00
rob bygrave 2b3e485beb [maven-release-plugin] prepare release ebean-11.19.2 2018-08-06 21:42:41 +12:00
rob bygrave d4be0718a8 #1460 - ENH: Add FetchGroup ... as a mechanism to specify select() + fetch() separately from Query
Change to add generics for FetchGroup
2018-08-06 21:30:36 +12:00
rob bygrave 6d0556a120 #1460 - ENH: Add FetchGroup ... as a mechanism to specify select() + fetch() separately from Query
Change to add generics for FetchGroup
2018-08-02 23:18:44 +12:00
rob bygrave ec7e4e4935 #1461 - @OneToMany with @JoinTable without table name does not default join table name 2018-08-02 22:25:48 +12:00
rob bygrave 471605619a #1460 - ENH: Add FetchGroup ... as a mechanism to specify select() + fetch() separately from Query 2018-07-30 23:51:52 +12:00
rob bygrave 02fe956056 #1459 - findNative with join to a @OneToMany ... does not map properly 2018-07-27 12:31:56 +12:00
rob bygrave db13034fec No effective change - update code style in test 2018-07-27 12:31:27 +12:00
rob bygrave c2489beb82 [maven-release-plugin] prepare for next development iteration 2018-07-18 22:25:00 +12:00
rob bygrave 9a424d7d6d [maven-release-plugin] prepare release ebean-11.19.1 2018-07-18 22:24:45 +12:00
rob bygrave 9b74602617 Bump pom to 11.19.1-SNAPSHOT 2018-07-18 22:22:48 +12:00
Roland PramlandRob Bygrave 5c99986476 Migration with procedures (#1451)
DB Migration with helper stored procedures (for MySql and SQL Server)
2018-07-18 22:21:47 +12:00
rob bygrave 7d38933e9d Refactor remove dead code - BindableRequest registerGeneratedVersion()
No effective change
2018-07-18 22:16:15 +12:00
rob bygrave 7668fb11a9 [maven-release-plugin] prepare for next development iteration 2018-07-18 22:05:02 +12:00
rob bygrave eac68166d9 [maven-release-plugin] prepare release ebean-11.18.6 2018-07-18 22:04:48 +12:00
rob bygrave cb0023345f Refactor scalar types for Varchar, LongVarchar and Clob - ScalarTypeStringBase 2018-07-18 21:59:11 +12:00
rob bygrave f0f7feb125 No effective change - code format 2018-07-18 21:49:19 +12:00
Roland PramlandRob Bygrave c8e32253a5 FIX: support for ScalarTypeConverter and @Lob (#1454) 2018-07-18 21:41:46 +12:00
rob bygrave 01541bb208 #1457 - Issue with @ManyToOne with @EmbeddedId where only some columns are insertable or updatable 2018-07-18 21:29:08 +12:00
rob bygrave 2d44d06f36 #1456 - io.ebean.annotation.NotNull not honored by @ManyToOne property 2018-07-18 19:36:41 +12:00
rob bygrave fda930a162 No effective change - fix javadoc title to Ebean 11 2018-07-18 17:01:14 +12:00
Roland PramlandRob Bygrave 5a6cdb9a86 FIX: null handling in ScalarType.toBeanType (#1455) 2018-07-18 16:33:36 +12:00
rob bygrave 5ef7fe8504 [maven-release-plugin] prepare for next development iteration 2018-07-15 16:09:15 +12:00
120 changed files with 2210 additions and 656 deletions
+3 -3
View File
@@ -9,7 +9,7 @@
<groupId>io.ebean</groupId>
<artifactId>ebean</artifactId>
<version>11.18.5</version>
<version>11.19.3</version>
<packaging>jar</packaging>
<name>ebean</name>
@@ -22,7 +22,7 @@
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-11.18.5</tag>
<tag>ebean-11.19.3</tag>
</scm>
<profiles>
@@ -360,7 +360,7 @@
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9.1</version>
<configuration>
<doctitle>Ebean 10</doctitle>
<doctitle>Ebean 11</doctitle>
<overview>src/main/java/io/ebean/overview.html</overview>
<source>1.8</source>
<doclet>org.avaje.doclet.PygmentsDoclet</doclet>
@@ -412,6 +412,11 @@ public interface ExpressionList<T> {
*/
Query<T> select(String properties);
/**
* Apply the fetchGroup which defines what part of the object graph to load.
*/
Query<T> select(FetchGroup<T> fetchGroup);
/**
* Set whether this query uses DISTINCT.
* <p>
+114
View File
@@ -0,0 +1,114 @@
package io.ebean;
import javax.annotation.Nonnull;
/**
* Defines what part of the object graph to load (select and fetch clauses).
* <p>
* Using a FetchGroup effectively sets the select() and fetch() clauses for a query. It is alternative
* to specifying the select() and fetch() clauses on the query allowing for more re-use of "what to load"
* that can be defined separately from the query and combined with other FetchGroups.
* </p>
*
* <h3>Select example</h3>*
* <pre>{@code
*
* FetchGroup<Customer> fetchGroup = FetchGroup.of(Customer.class, "name, status");
*
* Customer.query()
* .select(fetchGroup)
* .findList();
*
* }</pre>
*
* <h3>Select and fetch example</h3>
* <pre>{@code
*
* FetchGroup<Customer> fetchGroup = FetchGroup.of(Customer.class)
* .select("name, status")
* .fetch("contacts", "firstName, lastName, email")
* .build();
*
* Customer.query()
* .select(fetchGroup)
* .findList();
*
* }</pre>
*
* <h3>Combining FetchGroups</h3>
* <p>
* FetchGroups can be combined together to form another FetchGroup.
* </p>
* <pre>{@code
*
* FetchGroup<Address> FG_ADDRESS = FetchGroup.of(Address.class)
* .select("line1, line2, city")
* .fetch("country", "name")
* .build();
*
* FetchGroup<Customer> FG_CUSTOMER = FetchGroup.of(Customer.class)
* .select("name, version")
* .fetch("billingAddress", FG_ADDRESS)
* .build();
*
*
* Customer.query()
* .select(FG_CUSTOMER)
* .findList();
*
* }</pre>
*
* @param <T> The bean type the Fetch group can be applied to
*/
public interface FetchGroup<T> {
/**
* Return the FetchGroup with the given select clause.
* <p>
* We use this for simple FetchGroup that only select() properties and do not have additional fetch() clause.
* </p>
* <pre>{@code
*
* FetchGroup<Customer> fetchGroup = FetchGroup.of(Customer.class, "name, status");
*
* Customer.query()
* .select(fetchGroup)
* .findList();
*
* }</pre>
*
* @param select The select clause of the FetchGroup
*
* @return The FetchGroup with the given select clause
*/
@Nonnull
static <T> FetchGroup<T> of(Class<T> cls, String select) {
return XServiceProvider.fetchGroupOf(cls, select);
}
/**
* Return the FetchGroupBuilder with the given select clause that we can add fetch clauses to.
* <p>
* We chain select() with one or more fetch() clauses to define the object graph to load.
* </p>
* <pre>{@code
*
* FetchGroup<Customer> fetchGroup = FetchGroup.of(Customer.class)
* .select("name, status")
* .fetch("contacts", "firstName, lastName, email")
* .build();
*
* Customer.query()
* .select(fetchGroup)
* .findList();
*
* }</pre>
*
* @return The FetchGroupBuilder with the given select clause which we will add fetch clauses to
*/
@Nonnull
static <T> FetchGroupBuilder<T> of(Class<T> cls) {
return XServiceProvider.fetchGroupOf(cls);
}
}
@@ -0,0 +1,93 @@
package io.ebean;
import javax.annotation.Nonnull;
/**
* Builds a FetchGroup by adding fetch clauses.
* <p>
* We add select() and fetch() clauses to define the object graph we want to load.
* </p>
*
* <pre>{@code
*
* FetchGroup fetchGroup = FetchGroup
* .select("name, status")
* .fetch("contacts", "firstName, lastName, email")
* .build();
*
* Customer.query()
* .select(fetchGroup)
* .where()
* ...
* .findList();
*
* }</pre>
*/
public interface FetchGroupBuilder<T> {
/**
* Specify specific properties to select (top level properties).
*/
@Nonnull
FetchGroupBuilder<T> select(String select);
/**
* Fetch all the properties at the given path.
*/
@Nonnull
FetchGroupBuilder<T> fetch(String path);
/**
* Fetch the path with the nested fetch group.
*/
@Nonnull
FetchGroupBuilder<T> fetch(String path, FetchGroup<?> nestedGroup);
/**
* Fetch the path using a query join with the nested fetch group.
*/
@Nonnull
FetchGroupBuilder<T> fetchQuery(String path, FetchGroup<?> nestedGroup);
/**
* Fetch the path lazily with the nested fetch group.
*/
@Nonnull
FetchGroupBuilder<T> fetchLazy(String path, FetchGroup<?> nestedGroup);
/**
* Fetch the path including specified properties.
*/
@Nonnull
FetchGroupBuilder<T> fetch(String path, String properties);
/**
* Fetch the path including all its properties using a query join.
*/
@Nonnull
FetchGroupBuilder<T> fetchQuery(String path);
/**
* Fetch the path including specified properties using a query join.
*/
@Nonnull
FetchGroupBuilder<T> fetchQuery(String path, String properties);
/**
* Fetch the path including all its properties lazily.
*/
@Nonnull
FetchGroupBuilder<T> fetchLazy(String path);
/**
* Fetch the path including specified properties lazily.
*/
@Nonnull
FetchGroupBuilder<T> fetchLazy(String path, String properties);
/**
* Build and return the FetchGroup.
*/
@Nonnull
FetchGroup<T> build();
}
+5
View File
@@ -397,6 +397,11 @@ public interface Query<T> {
*/
Query<T> select(String fetchProperties);
/**
* Apply the fetchGroup which defines what part of the object graph to load.
*/
Query<T> select(FetchGroup<T> fetchGroup);
/**
* Specify a path to fetch eagerly including specific properties.
* <p>
@@ -1,5 +1,6 @@
package io.ebean;
import io.ebean.service.SpiFetchGroupService;
import io.ebean.service.SpiProfileLocationFactory;
import io.ebean.service.SpiRawSqlService;
@@ -15,6 +16,16 @@ class XServiceProvider {
private static SpiProfileLocationFactory profileLocationFactory = initProfileLocation();
private static SpiFetchGroupService fetchGroupService = initSpiFetchGroupService();
private static SpiFetchGroupService initSpiFetchGroupService() {
Iterator<SpiFetchGroupService> loader = ServiceLoader.load(SpiFetchGroupService.class).iterator();
if (loader.hasNext()) {
return loader.next();
}
throw new IllegalStateException("No service implementation found for SpiFetchGroupService?");
}
private static SpiRawSqlService initRawSql() {
Iterator<SpiRawSqlService> loader = ServiceLoader.load(SpiRawSqlService.class).iterator();
@@ -47,4 +58,17 @@ class XServiceProvider {
return profileLocationFactory;
}
/**
* Return the FetchGroup with the given select clause.
*/
static <T> FetchGroup<T> fetchGroupOf(Class<T> cls, String select) {
return fetchGroupService.of(cls, select);
}
/**
* Return the FetchGroupBuilder with the given select clause.
*/
static <T> FetchGroupBuilder<T> fetchGroupOf(Class<T> cls) {
return fetchGroupService.of(cls);
}
}
@@ -3130,9 +3130,10 @@ public class ServerConfig {
* @return A copy of the PlatformConfig with overridden properties
*/
public PlatformConfig newPlatformConfig(String propertiesPath, String platformPrefix) {
if (properties == null) {
properties = new Properties();
}
PropertiesWrapper p = new PropertiesWrapper(propertiesPath, platformPrefix, properties, classLoadConfig);
PlatformConfig config = new PlatformConfig(platformConfig);
config.loadSettings(p);
return config;
@@ -0,0 +1,26 @@
package io.ebean.service;
import io.ebean.FetchGroup;
import io.ebean.FetchGroupBuilder;
/**
* Service that parses FetchGroup expressions.
*/
public interface SpiFetchGroupService {
/**
* Return the FetchGroup with the given select clause.
*
* @param beanType The type of entity bean the fetch group is for
* @param select The properties to select (top level properties)
*/
<T> FetchGroup<T> of(Class<T> beanType, String select);
/**
* Create and return a FetchGroupBuilder starting with a select() clause.
*
* @param beanType The type of entity bean the fetch group is for
* @return The FetchGroupBuilder to add additional select and fetch clauses
*/
<T> FetchGroupBuilder<T> of(Class<T> beanType);
}
@@ -84,6 +84,8 @@ public class DefaultDbMigration implements DbMigration {
protected DatabasePlatform databasePlatform;
private boolean vanillaPlatform;
protected List<Pair> platforms = new ArrayList<>();
protected ServerConfig serverConfig;
@@ -192,6 +194,7 @@ public class DefaultDbMigration implements DbMigration {
*/
@Override
public void setPlatform(Platform platform) {
vanillaPlatform = true;
setPlatform(getPlatform(platform));
}
@@ -314,24 +317,28 @@ public class DefaultDbMigration implements DbMigration {
private void generateExtraDdl(File migrationDir, DatabasePlatform dbPlatform) throws IOException {
if (dbPlatform != null) {
ExtraDdl extraDdl = ExtraDdlXmlReader.read("/extra-ddl.xml");
if (extraDdl != null) {
List<DdlScript> ddlScript = extraDdl.getDdlScript();
for (DdlScript script : ddlScript) {
if (!script.isDrop() && ExtraDdlXmlReader.matchPlatform(dbPlatform.getName(), script.getPlatforms())) {
generateExtraDdl(migrationDir, dbPlatform, ExtraDdlXmlReader.readBuiltin());
generateExtraDdl(migrationDir, dbPlatform, ExtraDdlXmlReader.read());
}
}
private void generateExtraDdl(File migrationDir, DatabasePlatform dbPlatform, ExtraDdl extraDdl) throws IOException {
if (extraDdl != null) {
List<DdlScript> ddlScript = extraDdl.getDdlScript();
for (DdlScript script : ddlScript) {
if (!script.isDrop() && ExtraDdlXmlReader.matchPlatform(dbPlatform.getName(), script.getPlatforms())) {
writeExtraDdl(migrationDir, script);
}
}
}
}
}
/**
* Write (or override) the "repeatable" migration script.
*/
private void writeExtraDdl(File migrationDir, DdlScript script) throws IOException {
String fullName = repeatableMigrationName(script.getName());
String fullName = repeatableMigrationName(script.isInit(), script.getName());
logger.info("writing repeatable script {}", fullName);
@@ -342,8 +349,18 @@ public class DefaultDbMigration implements DbMigration {
}
}
private String repeatableMigrationName(String scriptName) {
return "R__" + scriptName.replace(' ', '_') + migrationConfig.getApplySuffix();
private String repeatableMigrationName(boolean init, String scriptName) {
StringBuilder sb = new StringBuilder();
if (init) {
sb.append("I__");
} else {
sb.append("R__");
}
sb.append(scriptName.replace(' ', '_'));
sb.append(migrationConfig.getApplySuffix());
return sb.toString();
}
/**
@@ -542,11 +559,10 @@ public class DefaultDbMigration implements DbMigration {
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
if (vanillaPlatform || databasePlatform == null) {
// not explicitly set so use the platform of the server
databasePlatform = server.getDatabasePlatform();
logger.debug("set platform to {}", databasePlatform.getName());
logger.trace("set platform to {}", databasePlatform.getName());
}
if (migrationConfig != null) {
if (strictMode != null) {
@@ -38,6 +38,16 @@ public class MySqlDdl extends PlatformDdl {
return "alter table " + tableName + " drop foreign key " + maxConstraintName(fkName);
}
/**
* It is rather complex to delete a column on MySql as there must not exist any foreign keys.
* That's why we call a user stored procedure here
*/
@Override
public void alterTableDropColumn(DdlBuffer buffer, String tableName, String columnName) throws IOException {
buffer.append("CALL usp_ebean_drop_column('").append(tableName).append("', '").append(columnName).append("')").endOfStatement();
}
@Override
public String alterTableDropConstraint(String tableName, String constraintName) {
// drop constraint not supported in MySQL 5.7 and 8.0 but starting with MariaDB 10.2.1 CHECK is evaluated
@@ -61,7 +71,7 @@ public class MySqlDdl extends PlatformDdl {
@Override
public String alterColumnDefaultValue(String tableName, String columnName, String defaultValue) {
String suffix = DdlHelp.isDropDefault(defaultValue) ? columnDropDefault : columnSetDefault + " " + defaultValue;
String suffix = DdlHelp.isDropDefault(defaultValue) ? columnDropDefault : columnSetDefault + " " + convertDefaultValue(defaultValue);
// use alter
return "alter table " + tableName + " alter " + columnName + " " + suffix;
@@ -246,6 +246,9 @@ public class PlatformDdl {
* Convert the standard type to the platform specific type.
*/
public String convert(String type, boolean identity) {
if (type == null) {
return null;
}
if (type.contains("[]")) {
return convertArrayType(type);
}
@@ -3,7 +3,9 @@ package io.ebeaninternal.dbmigration.ddlgeneration.platform;
import io.ebean.annotation.ConstraintMode;
import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite;
import io.ebeaninternal.dbmigration.migration.AlterColumn;
import io.ebeaninternal.server.persist.platform.MultiValueBind;
import java.io.IOException;
@@ -137,13 +139,7 @@ public class SqlServerDdl extends PlatformDdl {
// a rather complex statement.
StringBuilder sb = new StringBuilder();
if (DdlHelp.isDropDefault(defaultValue)) {
sb.append("delimiter $$\n");
sb.append("DECLARE @Tmp nvarchar(200);");
sb.append("select @Tmp = t1.name from sys.default_constraints t1\n");
sb.append(" join sys.columns t2 on t1.object_id = t2.default_object_id\n");
sb.append(" where t1.parent_object_id = OBJECT_ID('").append(tableName)
.append("') and t2.name = '").append(columnName).append("';\n");
sb.append("if @Tmp is not null EXEC('alter table ").append(tableName).append(" drop constraint ' + @Tmp)$$");
sb.append("EXEC usp_ebean_drop_default_constraint ").append(tableName).append(", ").append(columnName);
} else {
sb.append("alter table ").append(tableName);
sb.append(" add default ").append(convertDefaultValue(defaultValue)).append(" for ").append(columnName);
@@ -200,25 +196,50 @@ public class SqlServerDdl extends PlatformDdl {
/**
* It is rather complex to delete a column on SqlServer as there must not exist any references
* (constraints, default values, indices and foreign keys). The list is not yet complete, as
* indices over multiple columns will not yet deleted.
* (This may be changed to delete all refering objects by using the sys.* tables later)
* (constraints, default values, indices and foreign keys). That's why we call a user stored procedure here
*/
@Override
public void alterTableDropColumn(DdlBuffer buffer, String tableName, String columnName) throws IOException {
buffer.append("-- drop column ").append(tableName).append(".").append(columnName).endOfStatement();
buffer.append(alterTableDropUniqueConstraint(tableName, naming.uniqueConstraintName(tableName, columnName)));
buffer.endOfStatement();
buffer.append(alterColumnDefaultValue(tableName, columnName, DdlHelp.DROP_DEFAULT));
buffer.endOfStatement();
buffer.append(alterTableDropConstraint(tableName, naming.checkConstraintName(tableName, columnName)));
buffer.endOfStatement();
buffer.append(dropIndex(naming.indexName(tableName, columnName), tableName));
buffer.endOfStatement();
buffer.append(alterTableDropForeignKey(tableName, naming.foreignKeyConstraintName(tableName, columnName)));
buffer.endOfStatement();
super.alterTableDropColumn(buffer, tableName, columnName);
buffer.append("EXEC usp_ebean_drop_column ").append(tableName).append(", ").append(columnName).endOfStatement();
}
/**
* This writes the multi value datatypes needed for {@link MultiValueBind}
*/
@Override
public void generateProlog(DdlWrite write) throws IOException {
super.generateProlog(write);
generateTVPDefinitions(write, "bigint");
generateTVPDefinitions(write, "float");
generateTVPDefinitions(write, "bit");
generateTVPDefinitions(write, "date");
generateTVPDefinitions(write, "time");
//generateTVPDefinitions(write, "datetime2");
generateTVPDefinitions(write, "uniqueidentifier");
generateTVPDefinitions(write, "nvarchar(max)");
}
private void generateTVPDefinitions(DdlWrite write, String definition) throws IOException {
int pos = definition.indexOf('(');
String name = pos == -1 ? definition : definition.substring(0, pos);
dropTVP(write.dropAll(), name);
//TVPs are included in "I__create_procs.sql"
//createTVP(write.apply(), name, definition);
}
private void dropTVP(DdlBuffer ddl, String name) throws IOException {
ddl.append("if exists (select name from sys.types where name = 'ebean_").append(name)
.append("_tvp') drop type ebean_").append(name).append("_tvp").endOfStatement();
}
private void createTVP(DdlBuffer ddl, String name, String definition) throws IOException {
ddl.append("if not exists (select name from sys.types where name = 'ebean_").append(name)
.append("_tvp') create type ebean_").append(name).append("_tvp as table (c1 ").append(definition).append(")")
.endOfStatement();
}
}
@@ -9,8 +9,12 @@ import io.ebeaninternal.dbmigration.migration.ChangeSet;
import io.ebeaninternal.dbmigration.model.build.ModelBuildBeanVisitor;
import io.ebeaninternal.dbmigration.model.build.ModelBuildContext;
import io.ebeaninternal.dbmigration.model.visitor.VisitAllUsing;
import io.ebeaninternal.extraddl.model.DdlScript;
import io.ebeaninternal.extraddl.model.ExtraDdl;
import io.ebeaninternal.extraddl.model.ExtraDdlXmlReader;
import java.io.IOException;
import java.util.List;
/**
* Reads EbeanServer bean descriptors to build the current model.
@@ -111,6 +115,19 @@ public class CurrentModel {
if (header != null && !header.isEmpty()) {
ddl.append(header).append('\n');
}
ExtraDdl extraDdl = ExtraDdlXmlReader.readBuiltin();
if (extraDdl != null) {
List<DdlScript> ddlScript = extraDdl.getDdlScript();
for (DdlScript script : ddlScript) {
if (script.isInit() && ExtraDdlXmlReader.matchPlatform(server.getDatabasePlatform().getName(), script.getPlatforms())) {
ddl.append("-- init script " + script.getName()).append('\n');
ddl.append(script.getValue());
}
}
}
ddl.append(write.apply().getBuffer());
ddl.append(write.applyForeignKeys().getBuffer());
ddl.append(write.applyHistoryView().getBuffer());
@@ -42,9 +42,10 @@ public class MigrationModel {
// find all the migration xml files
File[] xmlFiles = modelDirectory.listFiles(pathname -> pathname.getName().toLowerCase().endsWith(modelSuffix));
if (xmlFiles == null || xmlFiles.length == 0) {
return;
}
List<MigrationResource> resources = new ArrayList<>(xmlFiles.length);
for (File xmlFile : xmlFiles) {
resources.add(new MigrationResource(xmlFile, createVersion(xmlFile)));
}
@@ -258,12 +258,13 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
}
} else {
col.setDefaultValue(p.getDbColumnDefault());
col.setDbMigrationInfos(p.getDbMigrationInfos());
if (!p.isNullable() || p.isDDLNotNull()) {
col.setNotnull(true);
}
}
col.setDbMigrationInfos(p.getDbMigrationInfos());
if (p.isUnique() && !p.isId()) {
col.setUnique(determineUniqueConstraintName(col.getName()));
indexSetAdd(col.getName());
@@ -39,7 +39,8 @@ public class DdlScript {
protected String platforms;
@XmlAttribute(name = "drop")
protected boolean drop;
@XmlAttribute(name = "init")
protected boolean init;
/**
* Gets the value of the value property.
*
@@ -114,4 +115,17 @@ public class DdlScript {
this.drop = drop;
}
/**
* Return if this a init script.
*/
public boolean isInit() {
return init;
}
/**
* Sets that this is a init script.
*/
public void setInit(boolean init) {
this.init = init;
}
}
@@ -83,10 +83,24 @@ public class ExtraDdlXmlReader {
}
}
/**
* Read the builtin extra ddl. (Stored procedures, tvp types etc)
*/
public static ExtraDdl readBuiltin() {
return read("/io/ebeaninternal/dbmigration/builtin-extra-ddl.xml");
}
/**
* Read the extra ddl.
*/
public static ExtraDdl read() {
return read("/extra-ddl.xml");
}
/**
* Read and return a ExtraDdl from an xml document at the given resource path.
*/
public static ExtraDdl read(String resourcePath) {
private static ExtraDdl read(String resourcePath) {
try (InputStream is = ExtraDdlXmlReader.class.getResourceAsStream(resourcePath)) {
if (is == null) {
@@ -1202,7 +1202,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
/**
* Set the value of the Version property on the bean.
*/
public void setVersionValue(Object versionValue) {
private void setVersionValue(Object versionValue) {
version = beanDescriptor.setVersion(entityBean, versionValue);
}
@@ -357,14 +357,34 @@ public abstract class BeanPropertyAssoc<T> extends BeanProperty implements STree
* Return true if this association is updateable.
*/
public boolean isUpdateable() {
return tableJoin.columns().length <= 0 || tableJoin.columns()[0].isUpdateable();
TableJoinColumn[] columns = tableJoin.columns();
if (columns.length <= 0) {
return true;
}
for (TableJoinColumn column : columns) {
if (column.isUpdateable()) {
// at least 1 is updatable
return true;
}
}
return false;
}
/**
* Return true if this association is insertable.
*/
public boolean isInsertable() {
return tableJoin.columns().length <= 0 || tableJoin.columns()[0].isInsertable();
TableJoinColumn[] columns = tableJoin.columns();
if (columns.length <= 0) {
return true;
}
for (TableJoinColumn column : columns) {
if (column.isInsertable()) {
// at least 1 is insertable
return true;
}
}
return false;
}
/**
@@ -443,16 +463,18 @@ public abstract class BeanPropertyAssoc<T> extends BeanProperty implements STree
String matchColumn = col.getForeignDbColumn();
String localColumn = col.getLocalDbColumn();
String localSqlFormula = col.getLocalSqlFormula();
boolean insertable = col.isInsertable();
boolean updateable = col.isUpdateable();
for (int j = 0; j < props.length; j++) {
if (props[j].getDbColumn().equalsIgnoreCase(matchColumn)) {
return new ImportedIdSimple(owner, localColumn, localSqlFormula, props[j], j);
return new ImportedIdSimple(owner, localColumn, localSqlFormula, props[j], j, insertable, updateable);
}
}
for (int j = 0; j < others.length; j++) {
if (others[j].getDbColumn().equalsIgnoreCase(matchColumn)) {
return new ImportedIdSimple(owner, localColumn, localSqlFormula, others[j], j + props.length);
return new ImportedIdSimple(owner, localColumn, localSqlFormula, others[j], j + props.length, insertable, updateable);
}
}
@@ -213,6 +213,12 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> implements ST
// by default not including "Many" properties in document store
}
@Override
public void registerColumn(BeanDescriptor<?> desc, String prefix) {
if (targetDescriptor != null) {
desc.registerTable(targetDescriptor.getBaseTable(), this);
}
}
/**
* Return the underlying collection of beans.
*/
@@ -64,8 +64,11 @@ public class ImportedIdEmbedded implements ImportedId {
@Override
public void dmlAppend(GenerateDmlRequest request) {
boolean update = request.isUpdate();
for (ImportedIdSimple anImported : imported) {
request.appendColumn(anImported.localDbColumn);
if (anImported.isInclude(update)) {
request.appendColumn(anImported.localDbColumn);
}
}
}
@@ -100,30 +103,28 @@ public class ImportedIdEmbedded implements ImportedId {
@Override
public Object bind(BindableRequest request, EntityBean bean) throws SQLException {
Object embeddedId = null;
if (bean != null) {
embeddedId = foreignAssocOne.getValue(bean);
}
Object embeddedId = (bean == null) ? null : foreignAssocOne.getValue(bean);
boolean update = request.isUpdate();
if (embeddedId == null) {
for (ImportedIdSimple anImported : imported) {
if (anImported.owner.isUpdateable()) {
if (anImported.isInclude(update)) {
request.bind(null, anImported.foreignProperty);
}
}
// return anything non-null to skip a derived relationship update
return Object.class;
} else {
EntityBean embedded = (EntityBean) embeddedId;
for (ImportedIdSimple anImported : imported) {
if (anImported.owner.isUpdateable()) {
if (anImported.isInclude(update)) {
Object scalarValue = anImported.foreignProperty.getValue(embedded);
request.bind(scalarValue, anImported.foreignProperty);
}
}
return embedded;
}
// hmmm, not worrying about this just yet
return null;
}
@Override
@@ -47,15 +47,32 @@ public final class ImportedIdSimple implements ImportedId, Comparable<ImportedId
protected final int position;
public ImportedIdSimple(BeanPropertyAssoc<?> owner, String localDbColumn, String localSqlFormula, BeanProperty foreignProperty, int position) {
/**
* If true include in insert.
*/
private final boolean insertable;
/**
* If true include in update.
*/
private final boolean updateable;
public ImportedIdSimple(BeanPropertyAssoc<?> owner, String localDbColumn, String localSqlFormula, BeanProperty foreignProperty, int position,
boolean insertable, boolean updateable) {
this.owner = owner;
this.localDbColumn = InternString.intern(localDbColumn);
this.localSqlFormula = InternString.intern(localSqlFormula);
this.foreignProperty = foreignProperty;
this.position = position;
this.insertable = insertable;
this.updateable = updateable;
this.logicalName = InternString.intern(owner.getName() + "." + foreignProperty.getName());
}
public ImportedIdSimple(BeanPropertyAssoc<?> owner, String localDbColumn, String localSqlFormula, BeanProperty foreignProperty, int position) {
this(owner, localDbColumn, localSqlFormula, foreignProperty, position, true, true);
}
/**
* Return the list as an array sorted into the same order as the Bean Properties.
*/
@@ -68,6 +85,13 @@ public final class ImportedIdSimple implements ImportedId, Comparable<ImportedId
return importedIds;
}
/**
* Return true if it should be included in the update (or insert).
*/
public boolean isInclude(boolean update) {
return (update) ? updateable : insertable;
}
@Override
public boolean equals(Object obj) {
// remove FindBugs warning
@@ -304,6 +304,12 @@ class AnnotationAssocManys extends AnnotationParser {
private void readJoinTable(JoinTable joinTable, DeployBeanPropertyAssocMany<?> prop) {
String intTableName = getFullTableName(joinTable);
if (intTableName.isEmpty()) {
BeanTable localTable = factory.getBeanTable(descriptor.getBeanType());
BeanTable otherTable = factory.getBeanTable(prop.getTargetType());
intTableName = getM2MJoinTableName(localTable, otherTable);
}
// set the intersection table
DeployTableJoin intJoin = new DeployTableJoin();
intJoin.setTable(intTableName);
@@ -116,6 +116,10 @@ public class AnnotationAssocOnes extends AnnotationParser {
prop.setFetchPreference(fetchPreference.value());
}
io.ebean.annotation.NotNull nonNull = get(prop, io.ebean.annotation.NotNull.class);
if (nonNull != null) {
prop.setNullable(false);
}
if (validationAnnotations) {
NotNull notNull = get(prop, NotNull.class);
if (notNull != null && isEbeanValidationGroups(notNull.groups())) {
@@ -18,6 +18,7 @@ import io.ebeaninternal.server.deploy.meta.DeployBeanProperty;
import io.ebeaninternal.server.type.DataEncryptSupport;
import io.ebeaninternal.server.type.ScalarType;
import io.ebeaninternal.server.type.ScalarTypeArray;
import io.ebeaninternal.server.type.ScalarTypeWrapper;
import io.ebeaninternal.server.type.SimpleAesEncryptor;
import io.ebeaninternal.server.type.TypeManager;
import org.slf4j.Logger;
@@ -116,8 +117,8 @@ public class DeployUtil {
throw new IllegalArgumentException("Class [" + enumType + "] is Not a Enum?");
}
try {
Class<? extends Enum<?>> enumClass = (Class<? extends Enum<?>>) enumType;
EnumType type = enumerated != null ? enumerated.value() : null;
Class<? extends Enum<?>> enumClass = (Class<? extends Enum<?>>) enumType;
EnumType type = enumerated != null ? enumerated.value() : null;
ScalarType<?> scalarType = typeManager.createEnumScalarType(enumClass, type);
prop.setScalarType(scalarType);
prop.setDbType(scalarType.getJdbcType());
@@ -278,19 +279,25 @@ public class DeployUtil {
*/
public void setLobType(DeployBeanProperty prop) {
// is String or byte[] ? used to determine if its a CLOB or BLOB
Class<?> type = prop.getPropertyType();
ScalarType<?> scalarType = prop.getScalarType();
// this also sets the lob flag on DeployBeanProperty
int lobType = isClobType(type) ? dbCLOBType : dbBLOBType;
if (scalarType instanceof ScalarTypeWrapper) {
int lobType = scalarType.getJdbcType() == Types.VARCHAR ? dbCLOBType : dbBLOBType;
prop.setDbType(lobType);
} else {
// is String or byte[] ? used to determine if its a CLOB or BLOB
Class<?> type = prop.getPropertyType();
// this also sets the lob flag on DeployBeanProperty
int lobType = isClobType(type) ? dbCLOBType : dbBLOBType;
ScalarType<?> scalarType = typeManager.getScalarType(type, lobType);
if (scalarType == null) {
// this should never occur actually
throw new RuntimeException("No ScalarType for LOB type [" + type + "] [" + lobType + "]");
scalarType = typeManager.getScalarType(type, lobType);
if (scalarType == null) {
// this should never occur actually
throw new RuntimeException("No ScalarType for LOB type [" + type + "] [" + lobType + "]");
}
prop.setDbType(lobType);
prop.setScalarType(scalarType);
}
prop.setDbType(lobType);
prop.setScalarType(scalarType);
}
private boolean isClobType(Class<?> type) {
@@ -6,6 +6,7 @@ import io.ebean.DtoQuery;
import io.ebean.Expression;
import io.ebean.ExpressionFactory;
import io.ebean.ExpressionList;
import io.ebean.FetchGroup;
import io.ebean.FetchPath;
import io.ebean.FutureIds;
import io.ebean.FutureList;
@@ -460,6 +461,11 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
return query.select(fetchProperties);
}
@Override
public Query<T> select(FetchGroup fetchGroup) {
return query.select(fetchGroup);
}
@Override
public Query<T> setDistinct(boolean distinct) {
return query.setDistinct(distinct);
@@ -5,6 +5,7 @@ import io.ebean.CountDistinctOrder;
import io.ebean.DtoQuery;
import io.ebean.Expression;
import io.ebean.ExpressionList;
import io.ebean.FetchGroup;
import io.ebean.FetchPath;
import io.ebean.FutureIds;
import io.ebean.FutureList;
@@ -759,6 +760,11 @@ class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expression
return exprList.select(properties);
}
@Override
public Query<T> select(FetchGroup fetchGroup) {
return exprList.select(fetchGroup);
}
@Override
public Query<T> setDistinct(boolean distinct) {
return exprList.setDistinct(distinct);
@@ -14,11 +14,16 @@ public class DeleteHandler extends DmlHandler {
private final DeleteMeta meta;
public DeleteHandler(PersistRequestBean<?> persist, DeleteMeta meta) {
DeleteHandler(PersistRequestBean<?> persist, DeleteMeta meta) {
super(persist, meta.isEmptyStringAsNull());
this.meta = meta;
}
@Override
public boolean isUpdate() {
return false;
}
/**
* Generate and bind the delete statement.
*/
@@ -50,11 +50,6 @@ public abstract class DmlHandler implements PersistHandler, BindableRequest {
protected String sql;
/**
* The generated value for the @Version property. Must be set after where clause is bound.
*/
protected Object versionValue;
protected DmlHandler(PersistRequestBean<?> persistRequest, boolean emptyStringToNull) {
this.now = System.currentTimeMillis();
this.persistRequest = persistRequest;
@@ -231,30 +226,6 @@ public abstract class DmlHandler implements PersistHandler, BindableRequest {
prop.bind(dataBind, value);
}
/**
* Register a generated value on a update. This can not be set to the bean
* until after the where clause has been bound for concurrency checking.
* <p>
* GeneratedProperty values are likely going to be used for optimistic
* concurrency checking. This includes 'counter' and 'update timestamp'
* generation.
* </p>
*/
@Override
public void registerGeneratedVersion(Object versionValue) {
this.versionValue = versionValue;
}
/**
* Set any update generated values to the bean. Must be called after where
* clause has been bound.
*/
public void setUpdateGenValues() {
if (versionValue != null) {
persistRequest.setVersionValue(versionValue);
}
}
/**
* Check with useGeneratedKeys to get appropriate PreparedStatement.
*/
@@ -29,10 +29,6 @@ public class GenerateDmlRequest {
return this;
}
public void appendColumnIsNull(String column) {
appendColumn(column, IS_NULL);
}
public void appendColumn(String column) {
//String bind = (insertMode > 0) ? "?" : "=?";
appendColumn(column, "?");
@@ -91,4 +87,7 @@ public class GenerateDmlRequest {
this.prefix2 = ", ";
}
public boolean isUpdate() {
return insertMode == 0;
}
}
@@ -50,6 +50,11 @@ public class InsertHandler extends DmlHandler {
this.concatinatedKey = meta.isConcatenatedKey();
}
@Override
public boolean isUpdate() {
return false;
}
/**
* Generate and bind the insert statement.
*/
@@ -17,11 +17,16 @@ public class UpdateHandler extends DmlHandler {
private boolean emptySetClause;
public UpdateHandler(PersistRequestBean<?> persist, UpdateMeta meta) {
UpdateHandler(PersistRequestBean<?> persist, UpdateMeta meta) {
super(persist, meta.isEmptyStringAsNull());
this.meta = meta;
}
@Override
public boolean isUpdate() {
return true;
}
/**
* Generate and bind the update statement.
*/
@@ -50,8 +55,6 @@ public class UpdateHandler extends DmlHandler {
if (persistRequest.isBatched()) {
batchedPstmt.registerInputStreams(dataBind.getInputStreams());
}
setUpdateGenValues();
logSql(sql);
}
@@ -42,12 +42,6 @@ public interface BindableRequest {
*/
void bindNoLog(Object value, BeanProperty prop) throws SQLException;
/**
* Register the value from a update GeneratedValue. This can only be set to
* the bean property after the where clause has bean built.
*/
void registerGeneratedVersion(Object value);
/**
* Return the original PersistRequest.
*/
@@ -59,4 +53,8 @@ public interface BindableRequest {
*/
long now();
/**
* Return true if this is an update request.
*/
boolean isUpdate();
}
@@ -19,9 +19,7 @@ public class FactoryAssocOnes {
*/
public void create(List<Bindable> list, BeanDescriptor<?> desc, DmlMode mode) {
BeanPropertyAssocOne<?>[] ones = desc.propertiesOneImported();
for (BeanPropertyAssocOne<?> one : ones) {
for (BeanPropertyAssocOne<?> one : desc.propertiesOneImported()) {
if (!one.isImportedPrimaryKey()) {
switch (mode) {
case INSERT:
@@ -0,0 +1,26 @@
package io.ebeaninternal.server.query;
import io.ebeaninternal.server.querydefn.OrmQueryDetail;
import io.ebeaninternal.server.querydefn.SpiFetchGroup;
/**
* Default FetchGroup implementation.
*/
class DFetchGroup<T> implements SpiFetchGroup<T> {
private final OrmQueryDetail detail;
DFetchGroup(OrmQueryDetail detail) {
this.detail = detail;
}
@Override
public OrmQueryDetail detail() {
return detail.copy();
}
@Override
public OrmQueryDetail underlying() {
return detail;
}
}
@@ -0,0 +1,92 @@
package io.ebeaninternal.server.query;
import io.ebean.FetchConfig;
import io.ebean.FetchGroup;
import io.ebean.FetchGroupBuilder;
import io.ebeaninternal.server.querydefn.OrmQueryDetail;
import io.ebeaninternal.server.querydefn.SpiFetchGroup;
/**
* Default implementation of the FetchGroupBuilder.
*/
class DFetchGroupBuilder<T> implements FetchGroupBuilder<T> {
private static final FetchConfig FETCH_QUERY = new FetchConfig().query();
private static final FetchConfig FETCH_LAZY = new FetchConfig().lazy();
private final OrmQueryDetail detail;
DFetchGroupBuilder() {
this.detail = new OrmQueryDetail();
}
@Override
public FetchGroupBuilder<T> select(String select) {
detail.select(select);
return this;
}
@Override
public FetchGroupBuilder<T> fetch(String path) {
detail.fetch(path, null, null);
return this;
}
@Override
public FetchGroupBuilder<T> fetch(String path, FetchGroup nestedGroup) {
return fetchNested(path, nestedGroup, null);
}
@Override
public FetchGroupBuilder<T> fetchQuery(String path, FetchGroup nestedGroup) {
return fetchNested(path, nestedGroup, FETCH_QUERY);
}
@Override
public FetchGroupBuilder<T> fetchLazy(String path, FetchGroup nestedGroup) {
return fetchNested(path, nestedGroup, FETCH_LAZY);
}
private FetchGroupBuilder<T> fetchNested(String path, FetchGroup nestedGroup, FetchConfig fetchConfig) {
OrmQueryDetail nestedDetail = ((SpiFetchGroup) nestedGroup).underlying();
detail.addNested(path, nestedDetail, fetchConfig);
return this;
}
@Override
public FetchGroupBuilder<T> fetchQuery(String path) {
detail.fetch(path, null, FETCH_QUERY);
return this;
}
@Override
public FetchGroupBuilder<T> fetchLazy(String path) {
detail.fetch(path, null, FETCH_LAZY);
return this;
}
@Override
public FetchGroupBuilder<T> fetch(String path, String properties) {
detail.fetch(path, properties, null);
return this;
}
@Override
public FetchGroupBuilder<T> fetchQuery(String path, String properties) {
detail.fetch(path, properties, FETCH_QUERY);
return this;
}
@Override
public FetchGroupBuilder<T> fetchLazy(String path, String properties) {
detail.fetch(path, properties, FETCH_LAZY);
return this;
}
@Override
public FetchGroup<T> build() {
return new DFetchGroup<>(detail);
}
}
@@ -0,0 +1,28 @@
package io.ebeaninternal.server.query;
import io.ebean.FetchGroup;
import io.ebean.FetchGroupBuilder;
import io.ebean.service.SpiFetchGroupService;
import io.ebeaninternal.server.querydefn.OrmQueryDetail;
/**
* Default implementation of SpiFetchGroupService.
*/
public final class DFetchGroupService implements SpiFetchGroupService {
@Override
public <T> FetchGroup<T> of(Class<T> cls, String select) {
return new DFetchGroup<>(detail(select));
}
@Override
public <T> FetchGroupBuilder<T> of(Class<T> cls) {
return new DFetchGroupBuilder<>();
}
private OrmQueryDetail detail(String select) {
OrmQueryDetail detail = new OrmQueryDetail();
detail.select(select);
return detail;
}
}
@@ -7,6 +7,7 @@ import io.ebean.Expression;
import io.ebean.ExpressionFactory;
import io.ebean.ExpressionList;
import io.ebean.FetchConfig;
import io.ebean.FetchGroup;
import io.ebean.FetchPath;
import io.ebean.FutureIds;
import io.ebean.FutureList;
@@ -1329,6 +1330,12 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
return this;
}
@Override
public DefaultOrmQuery<T> select(FetchGroup fetchGroup) {
this.detail = ((SpiFetchGroup)fetchGroup).detail();
return this;
}
@Override
public DefaultOrmQuery<T> fetch(String property) {
return fetch(property, null, null);
@@ -55,6 +55,16 @@ public class OrmQueryDetail implements Serializable {
return copy;
}
/**
* Add a nested OrmQueryDetail to this detail.
*/
public void addNested(String path, OrmQueryDetail other, FetchConfig config) {
fetch(path, other.baseProps.getProperties(), config);
for (Map.Entry<String, OrmQueryProperties> entry : other.fetchPaths.entrySet()) {
fetch(path + "." + entry.getKey(), entry.getValue().getProperties(), entry.getValue().getFetchConfig());
}
}
/**
* Calculate the hash for the query plan.
*/
@@ -148,27 +148,30 @@ public class OrmQueryProperties implements Serializable {
/**
* Copy constructor.
*/
private OrmQueryProperties(OrmQueryProperties source) {
private OrmQueryProperties(OrmQueryProperties source, FetchConfig sourceFetchConfig) {
this.fetchConfig = sourceFetchConfig;
this.parentPath = source.parentPath;
this.path = source.path;
this.rawProperties = source.rawProperties;
this.trimmedProperties = source.trimmedProperties;
this.cache = source.cache;
this.readOnly = source.readOnly;
this.fetchConfig = source.fetchConfig;
this.filterMany = source.filterMany;
this.included = (source.included == null) ? null : new LinkedHashSet<>(source.included);
if (includedBeanJoin != null) {
this.includedBeanJoin = new HashSet<>(source.includedBeanJoin);
}
}
/**
* Creates a copy of the OrmQueryProperties.
*/
public OrmQueryProperties copy() {
return new OrmQueryProperties(this);
return new OrmQueryProperties(this, this.fetchConfig);
}
/**
* Create a copy with the given fetch config.
*/
public OrmQueryProperties copy(FetchConfig fetchConfig) {
return new OrmQueryProperties(this, fetchConfig);
}
/**
@@ -0,0 +1,19 @@
package io.ebeaninternal.server.querydefn;
import io.ebean.FetchGroup;
/**
* Service API of FetchGroup.
*/
public interface SpiFetchGroup<T> extends FetchGroup<T> {
/**
* Return the detail to use for query execution.
*/
OrmQueryDetail detail();
/**
* Return the underlying detail for copy purposes.
*/
OrmQueryDetail underlying();
}
@@ -51,6 +51,7 @@ public class ScalarTypeChar extends ScalarTypeBaseVarchar<Character> {
@Override
public Character toBeanType(Object value) {
if (value == null) return null;
String s = BasicTypeConverter.toString(value);
return s.charAt(0);
}
@@ -54,6 +54,7 @@ public class ScalarTypeCharArray extends ScalarTypeBaseVarchar<char[]> {
@Override
public char[] toBeanType(Object value) {
if (value == null) return null;
String s = BasicTypeConverter.toString(value);
return s.toCharArray();
}
@@ -1,66 +1,24 @@
package io.ebeaninternal.server.type;
import io.ebeaninternal.server.core.BasicTypeConverter;
import java.sql.SQLException;
import java.sql.Types;
/**
* ScalarType for String.
*/
public class ScalarTypeClob extends ScalarTypeBaseVarchar<String> {
public class ScalarTypeClob extends ScalarTypeStringBase {
protected ScalarTypeClob(boolean jdbcNative, int jdbcType) {
super(String.class, jdbcNative, jdbcType);
ScalarTypeClob(boolean jdbcNative, int jdbcType) {
super(jdbcNative, jdbcType);
}
public ScalarTypeClob() {
super(String.class, true, Types.CLOB);
}
@Override
public String convertFromDbString(String dbValue) {
return dbValue;
}
@Override
public String convertToDbString(String beanValue) {
return beanValue;
}
@Override
public void bind(DataBind b, String value) throws SQLException {
if (value == null) {
b.setNull(Types.VARCHAR);
} else {
b.setString(value);
}
super(true, Types.CLOB);
}
@Override
public String read(DataReader dataReader) throws SQLException {
return dataReader.getStringFromStream();
}
@Override
public Object toJdbcType(Object value) {
return BasicTypeConverter.toString(value);
}
@Override
public String toBeanType(Object value) {
return BasicTypeConverter.toString(value);
}
@Override
public String formatValue(String t) {
return t;
}
@Override
public String parse(String value) {
return value;
}
}
@@ -59,6 +59,7 @@ public class ScalarTypeDuration extends ScalarTypeBase<Duration> {
@Override
public Duration toBeanType(Object value) {
if (value instanceof Duration) return (Duration) value;
if (value == null) return null;
return Duration.ofSeconds(BasicTypeConverter.toLong(value));
}
@@ -42,6 +42,7 @@ public class ScalarTypeDurationWithNanos extends ScalarTypeDuration {
@Override
public Duration toBeanType(Object value) {
if (value instanceof Duration) return (Duration) value;
if (value == null) return null;
return convertFromBigDecimal(BasicTypeConverter.toBigDecimal(value));
}
@@ -53,7 +53,7 @@ public class ScalarTypeInstant extends ScalarTypeBaseDateTime<Instant> {
@Override
public Instant toBeanType(Object value) {
if (value instanceof Instant) return (Instant) value;
return convertFromTimestamp((Timestamp) value);
if (value instanceof Timestamp) return convertFromTimestamp((Timestamp) value);
return (Instant) value;
}
}
@@ -54,7 +54,7 @@ public class ScalarTypeLocalDateTime extends ScalarTypeBaseDateTime<LocalDateTim
@Override
public LocalDateTime toBeanType(Object value) {
if (value instanceof LocalDateTime) return (LocalDateTime) value;
return convertFromTimestamp((Timestamp) value);
if (value instanceof Timestamp) return convertFromTimestamp((Timestamp) value);
return (LocalDateTime) value;
}
}
@@ -1,6 +1,5 @@
package io.ebeaninternal.server.type;
import java.sql.SQLException;
import java.sql.Types;
/**
@@ -12,8 +11,4 @@ public class ScalarTypeLongVarchar extends ScalarTypeClob {
super(true, Types.LONGVARCHAR);
}
@Override
public String read(DataReader dataReader) throws SQLException {
return dataReader.getStringFromStream();
}
}
@@ -55,7 +55,7 @@ public class ScalarTypeOffsetDateTime extends ScalarTypeBaseDateTime<OffsetDateT
@Override
public OffsetDateTime toBeanType(Object value) {
if (value instanceof OffsetDateTime) return (OffsetDateTime) value;
return convertFromTimestamp((Timestamp) value);
if (value instanceof Timestamp) return convertFromTimestamp((Timestamp) value);
return (OffsetDateTime) value;
}
}
@@ -1,103 +1,15 @@
package io.ebeaninternal.server.type;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import io.ebeaninternal.server.core.BasicTypeConverter;
import io.ebeanservice.docstore.api.mapping.DocPropertyType;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.sql.SQLException;
import java.sql.Types;
/**
* ScalarType for String.
*/
public class ScalarTypeString extends ScalarTypeBase<String> {
public class ScalarTypeString extends ScalarTypeStringBase {
public static final ScalarTypeString INSTANCE = new ScalarTypeString();
private ScalarTypeString() {
super(String.class, true, Types.VARCHAR);
}
@Override
public void bind(DataBind b, String value) throws SQLException {
if (value == null) {
b.setNull(Types.VARCHAR);
} else {
b.setString(value);
}
}
@Override
public String read(DataReader dataReader) throws SQLException {
return dataReader.getString();
}
@Override
public Object toJdbcType(Object value) {
return BasicTypeConverter.toString(value);
}
@Override
public String toBeanType(Object value) {
return BasicTypeConverter.toString(value);
}
@Override
public String formatValue(String value) {
return value;
}
@Override
public String parse(String value) {
return value;
}
@Override
public String convertFromMillis(long systemTimeMillis) {
return String.valueOf(systemTimeMillis);
}
@Override
public boolean isDateTimeCapable() {
return true;
}
@Override
public String readData(DataInput dataInput) throws IOException {
if (!dataInput.readBoolean()) {
return null;
} else {
return dataInput.readUTF();
}
}
@Override
public void writeData(DataOutput dataOutput, String value) throws IOException {
if (value == null) {
dataOutput.writeBoolean(false);
} else {
dataOutput.writeBoolean(true);
dataOutput.writeUTF(value);
}
}
@Override
public String jsonRead(JsonParser parser) throws IOException {
return parser.getValueAsString();
}
@Override
public void jsonWrite(JsonGenerator writer, String value) throws IOException {
writer.writeString(value);
}
@Override
public DocPropertyType getDocType() {
return DocPropertyType.TEXT;
super(true, Types.VARCHAR);
}
}
@@ -0,0 +1,101 @@
package io.ebeaninternal.server.type;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import io.ebeaninternal.server.core.BasicTypeConverter;
import io.ebeanservice.docstore.api.mapping.DocPropertyType;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.sql.SQLException;
import java.sql.Types;
/**
* Base ScalarType for String type using Varchar, Clob and LongVarchar.
*/
public abstract class ScalarTypeStringBase extends ScalarTypeBase<String> {
ScalarTypeStringBase(boolean jdbcNative, int jdbcType) {
super(String.class, jdbcNative, jdbcType);
}
@Override
public void bind(DataBind b, String value) throws SQLException {
if (value == null) {
b.setNull(Types.VARCHAR);
} else {
b.setString(value);
}
}
@Override
public String read(DataReader dataReader) throws SQLException {
return dataReader.getString();
}
@Override
public Object toJdbcType(Object value) {
return BasicTypeConverter.toString(value);
}
@Override
public String toBeanType(Object value) {
return BasicTypeConverter.toString(value);
}
@Override
public String formatValue(String value) {
return value;
}
@Override
public String parse(String value) {
return value;
}
@Override
public String convertFromMillis(long systemTimeMillis) {
return String.valueOf(systemTimeMillis);
}
@Override
public boolean isDateTimeCapable() {
return true;
}
@Override
public String readData(DataInput dataInput) throws IOException {
if (!dataInput.readBoolean()) {
return null;
} else {
return dataInput.readUTF();
}
}
@Override
public void writeData(DataOutput dataOutput, String value) throws IOException {
if (value == null) {
dataOutput.writeBoolean(false);
} else {
dataOutput.writeBoolean(true);
dataOutput.writeUTF(value);
}
}
@Override
public String jsonRead(JsonParser parser) throws IOException {
return parser.getValueAsString();
}
@Override
public void jsonWrite(JsonGenerator writer, String value) throws IOException {
writer.writeString(value);
}
@Override
public DocPropertyType getDocType() {
return DocPropertyType.TEXT;
}
}
@@ -65,6 +65,7 @@ public class ScalarTypeYear extends ScalarTypeBase<Year> {
@Override
public Year toBeanType(Object value) {
if (value instanceof Year) return (Year) value;
if (value == null) return null;
return Year.of(BasicTypeConverter.toInteger(value));
}
@@ -61,6 +61,7 @@ public class ScalarTypeYearMonthDate extends ScalarTypeBaseDate<YearMonth> {
public YearMonth toBeanType(Object value) {
if (value instanceof YearMonth) return (YearMonth) value;
if (value instanceof LocalDate) return fromLocalDate((LocalDate) value);
if (value == null) return null;
return fromLocalDate(BasicTypeConverter.toDate(value).toLocalDate());
}
@@ -55,7 +55,7 @@ public class ScalarTypeZonedDateTime extends ScalarTypeBaseDateTime<ZonedDateTim
@Override
public ZonedDateTime toBeanType(Object value) {
if (value instanceof ZonedDateTime) return (ZonedDateTime) value;
return convertFromTimestamp((Timestamp) value);
if (value instanceof Timestamp) return convertFromTimestamp((Timestamp) value);
return (ZonedDateTime) value;
}
}
@@ -0,0 +1 @@
io.ebeaninternal.server.query.DFetchGroupService
@@ -0,0 +1,162 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<extra-ddl xmlns="http://ebean-orm.github.io/xml/ns/extraddl">
<ddl-script name="create procs" platforms="sqlserver" init="true">-- Initial script to create stored procedures etc for sqlserver platform
-- create table-value-parameters
if not exists (select name from sys.types where name = 'ebean_bigint_tvp') create type ebean_bigint_tvp as table (c1 bigint);
if not exists (select name from sys.types where name = 'ebean_float_tvp') create type ebean_float_tvp as table (c1 float);
if not exists (select name from sys.types where name = 'ebean_bit_tvp') create type ebean_bit_tvp as table (c1 bit);
if not exists (select name from sys.types where name = 'ebean_date_tvp') create type ebean_date_tvp as table (c1 date);
if not exists (select name from sys.types where name = 'ebean_time_tvp') create type ebean_time_tvp as table (c1 time);
if not exists (select name from sys.types where name = 'ebean_uniqueidentifier_tvp') create type ebean_uniqueidentifier_tvp as table (c1 uniqueidentifier);
if not exists (select name from sys.types where name = 'ebean_nvarchar_tvp') create type ebean_nvarchar_tvp as table (c1 nvarchar(max));
delimiter $$
-----------------------------------------------------------
-- PROCEDURE: usp_ebean_drop_indices TABLE, COLUMN
-- deletes all indices referring to TABLE.COLUMN
-----------------------------------------------------------
CREATE OR ALTER PROCEDURE usp_ebean_drop_indices @tableName nvarchar(255), @columnName nvarchar(255)
AS SET NOCOUNT ON
declare @sql nvarchar(1000)
declare @indexName nvarchar(255)
BEGIN
DECLARE index_cursor CURSOR FOR SELECT i.name from sys.indexes i
join sys.index_columns ic on ic.object_id = i.object_id and ic.index_id = i.index_id
join sys.columns c on c.object_id = ic.object_id and c.column_id = ic.column_id
where i.object_id = OBJECT_ID(@tableName) AND c.name = @columnName;
OPEN index_cursor
FETCH NEXT FROM index_cursor INTO @indexName
WHILE @@FETCH_STATUS = 0
BEGIN
set @sql = 'drop index ' + @indexName + ' on ' + @tableName;
EXECUTE(@sql);
FETCH NEXT FROM index_cursor INTO @indexName
END;
CLOSE index_cursor;
DEALLOCATE index_cursor;
END
$$
delimiter $$
--------------------------------------------------------------------
-- PROCEDURE: usp_ebean_drop_default_constraint TABLE, COLUMN
-- deletes the default constraint, which has a random name
--------------------------------------------------------------------
CREATE OR ALTER PROCEDURE usp_ebean_drop_default_constraint @tableName nvarchar(255), @columnName nvarchar(255)
AS SET NOCOUNT ON
declare @tmp nvarchar(1000)
BEGIN
select @Tmp = t1.name from sys.default_constraints t1
join sys.columns t2 on t1.object_id = t2.default_object_id
where t1.parent_object_id = OBJECT_ID(@tableName) and t2.name = @columnName;
if @Tmp is not null EXEC('alter table ' + @tableName +' drop constraint ' + @tmp);
END
$$
delimiter $$
--------------------------------------------------------------------
-- PROCEDURE: usp_ebean_drop_constraints TABLE, COLUMN
-- deletes constraints and foreign keys refering to TABLE.COLUMN
--------------------------------------------------------------------
CREATE OR ALTER PROCEDURE usp_ebean_drop_constraints @tableName nvarchar(255), @columnName nvarchar(255)
AS SET NOCOUNT ON
declare @sql nvarchar(1000)
declare @constraintName nvarchar(255)
BEGIN
DECLARE name_cursor CURSOR FOR
SELECT cc.name from sys.check_constraints cc
join sys.columns c on c.object_id = cc.parent_object_id and c.column_id = cc.parent_column_id
where parent_object_id = OBJECT_ID(@tableName) AND c.name = @columnName
UNION SELECT fk.name from sys.foreign_keys fk
join sys.foreign_key_columns fkc on fkc.constraint_object_id = fk.object_id
and fkc.parent_object_id = fk.parent_object_id
join sys.columns c on c.object_id = fkc.parent_object_id and c.column_id = fkc.parent_column_id
where fkc.parent_object_id = OBJECT_ID(@tableName) AND c.name = @columnName;
OPEN name_cursor
FETCH NEXT FROM name_cursor INTO @constraintName
WHILE @@FETCH_STATUS = 0
BEGIN
set @sql = 'alter table ' + @tableName + ' drop constraint ' + @constraintName;
EXECUTE(@sql);
FETCH NEXT FROM name_cursor INTO @constraintName
END;
CLOSE name_cursor;
DEALLOCATE name_cursor;
END
$$
delimiter $$
-------------------------------------------------------------------------------------
-- PROCEDURE: usp_ebean_drop_column TABLE, COLUMN
-- deletes the column annd ensures that all indices and constraints are dropped first
-------------------------------------------------------------------------------------
CREATE OR ALTER PROCEDURE usp_ebean_drop_column @tableName nvarchar(255), @columnName nvarchar(255)
AS SET NOCOUNT ON
declare @sql nvarchar(1000)
BEGIN
EXEC usp_ebean_drop_indices @tableName, @columnName;
EXEC usp_ebean_drop_default_constraint @tableName, @columnName;
EXEC usp_ebean_drop_constraints @tableName, @columnName;
set @sql = 'alter table ' + @tableName + ' drop column ' + @columnName;
EXECUTE(@sql);
END
$$
</ddl-script>
<ddl-script name="create procs" platforms="mysql" init="true">-- Inital script to create stored procedures etc for mysql platform
DROP PROCEDURE IF EXISTS usp_ebean_drop_foreign_keys;
delimiter $$
------------------------------------------------------------------------------
-- PROCEDURE: usp_ebean_drop_foreign_keys TABLE, COLUMN
-- deletes all constraints and foreign keys referring to TABLE.COLUMN
------------------------------------------------------------------------------
CREATE PROCEDURE usp_ebean_drop_foreign_keys(IN p_table_name VARCHAR(255), IN p_column_name VARCHAR(255))
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE c_fk_name CHAR(255);
DECLARE curs CURSOR FOR SELECT CONSTRAINT_NAME from information_schema.KEY_COLUMN_USAGE
WHERE TABLE_SCHEMA = DATABASE() and TABLE_NAME = p_table_name and COLUMN_NAME = p_column_name
AND REFERENCED_TABLE_NAME IS NOT NULL;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN curs;
read_loop: LOOP
FETCH curs INTO c_fk_name;
IF done THEN
LEAVE read_loop;
END IF;
SET @sql = CONCAT('ALTER TABLE ', p_table_name, ' DROP FOREIGN KEY ', c_fk_name);
PREPARE stmt FROM @sql;
EXECUTE stmt;
END LOOP;
CLOSE curs;
END
$$
DROP PROCEDURE IF EXISTS usp_ebean_drop_column;
delimiter $$
-------------------------------------------------------------------------------------
-- PROCEDURE: usp_ebean_drop_column TABLE, COLUMN
-- deletes the column and ensures that all indices and constraints are dropped first
-------------------------------------------------------------------------------------
CREATE PROCEDURE usp_ebean_drop_column(IN p_table_name VARCHAR(255), IN p_column_name VARCHAR(255))
BEGIN
CALL usp_ebean_drop_foreign_keys(p_table_name, p_column_name);
SET @sql = CONCAT('ALTER TABLE ', p_table_name, ' DROP COLUMN ', p_column_name);
PREPARE stmt FROM @sql;
EXECUTE stmt;
END
$$
</ddl-script>
</extra-ddl>
+115
View File
@@ -0,0 +1,115 @@
package io.ebean;
import org.ebeantest.LoggedSqlCollector;
import org.junit.Test;
import org.tests.model.basic.Address;
import org.tests.model.basic.Contact;
import org.tests.model.basic.Customer;
import org.tests.model.basic.ResetBasicData;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
public class FetchGroupTest extends BaseTestCase {
@Test
public void simple() {
FetchGroup<Customer> fetch = FetchGroup.of(Customer.class, "name, status");
Query<Customer> query = Customer.find
.query()
.where()
.ilike("name", "rob")
.select(fetch);
query.findList();
assertThat(sqlOf(query)).contains("select t0.id, t0.name, t0.status from");
}
@Test
public void nestedWithQueryJoin() {
ResetBasicData.reset();
FetchGroup<Customer> fetch = FetchGroup.of(Customer.class)
.select("name, status")
.fetchQuery("contacts", "firstName, lastName, email")
.build();
Query<Customer> query = Customer.find
.query()
.where()
.ilike("name", "rob")
.select(fetch);
LoggedSqlCollector.start();
query.findList();
List<String> sql = LoggedSqlCollector.stop();
assertThat(sql).hasSize(2);
assertThat(sql.get(0)).contains("select t0.id, t0.name, t0.status from o_customer");
assertThat(sql.get(1)).contains("select t0.customer_id, t0.id, t0.first_name, t0.last_name, t0.email from contact");
}
@Test
public void nestedWithQueryJoin_asNestedFetchGroup() {
ResetBasicData.reset();
FetchGroup<Contact> CT_NAME = FetchGroup.of(Contact.class, "firstName, lastName, email");
FetchGroup<Customer> fetch = FetchGroup.of(Customer.class)
.select("name")
.fetchQuery("contacts", CT_NAME)
.build();
Query<Customer> query = Customer.find
.query()
.where()
.ilike("name", "rob")
.select(fetch);
LoggedSqlCollector.start();
query.findList();
List<String> sql = LoggedSqlCollector.stop();
assertThat(sql).hasSize(2);
assertThat(sql.get(0)).contains("select t0.id, t0.name from o_customer");
assertThat(sql.get(1)).contains(" from contact");
}
@Test
public void nested_withNestedFetchGroup() {
ResetBasicData.reset();
FetchGroup<Address> FGAddress = FetchGroup.of(Address.class)
.select("line1, line2, city")
.fetch("country", "name")
.build();
FetchGroup<Customer> FBCustomer = FetchGroup.of(Customer.class)
.select("name, version")
.fetch("billingAddress", FGAddress)
.build();
Query<Customer> query = Customer.find
.query()
.where()
.ilike("name", "rob")
.select(FBCustomer);
LoggedSqlCollector.start();
query.findList();
List<String> sql = LoggedSqlCollector.stop();
assertThat(sql).hasSize(1);
assertThat(sql.get(0)).contains("select t0.id, t0.name, t0.version, t1.id, t1.line_1, t1.line_2, t1.city, t2.code, t2.name from o_customer t0 left join o_address t1 on t1.id = t0.billing_address_id left join o_country t2 on t2.code = t1.country_code ");
}
}
@@ -7,6 +7,7 @@ import io.ebean.SqlUpdate;
import io.ebean.Transaction;
import io.ebean.annotation.IgnorePlatform;
import io.ebean.annotation.Platform;
import io.ebean.migration.MigrationConfig;
import io.ebean.migration.ddl.DdlRunner;
import io.ebeaninternal.dbmigration.ddlgeneration.Helper;
@@ -16,7 +17,6 @@ import javax.persistence.PersistenceException;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
@@ -84,6 +84,9 @@ public class DbMigrationTest extends BaseTestCase {
"migtest_oto_child",
"migtest_oto_master");
if (isSqlServer() || isMySql()) {
runScript(false, "I__create_procs.sql");
}
runScript(false, "1.0__initial.sql");
@@ -103,7 +106,6 @@ public class DbMigrationTest extends BaseTestCase {
assertThat(server().execute(update)).isEqualTo(2);
}
createHistoryEntities();
// Run migration
@@ -121,7 +123,7 @@ public class DbMigrationTest extends BaseTestCase {
assertThat(row.getString("new_string_field")).isEqualTo("foo'bar");
assertThat(row.getBoolean("new_boolean_field2")).isTrue();
assertThat(row.getTimestamp("some_date")).isEqualTo(new Timestamp(100, 0, 1, 0, 0, 0, 0)); // = 2000-01-01T00:00:00
//assertThat(row.getTimestamp("some_date")).isCloseTo(new Date(), 86_000); // allow 1 minute delta
row = result.get(1);
assertThat(row.getInteger("id")).isEqualTo(2);
@@ -130,15 +132,10 @@ public class DbMigrationTest extends BaseTestCase {
assertThat(row.getString("new_string_field")).isEqualTo("foo'bar");
assertThat(row.getBoolean("new_boolean_field2")).isTrue();
assertThat(row.getTimestamp("some_date")).isEqualTo(new Timestamp(100, 0, 1, 0, 0, 0, 0)); // = 2000-01-01T00:00:00
//assertThat(row.getTimestamp("some_date")).isCloseTo(new Date(), 60_000); // allow 1 minute delta
// Run migration & drops
if (isMySql()) {
return; // TODO: mysql cannot drop table (need stored procedure for drop column)
}
runScript(false, "1.2__dropsFor_1.1.sql");
// Oracle caches the statement and does not detect schema change. It fails with
// an ORA-01007
if (isOracle()) {
@@ -191,7 +188,7 @@ public class DbMigrationTest extends BaseTestCase {
update = server().createSqlUpdate("update migtest_e_history5 set test_number = 45 where id = 1");
assertThat(server().execute(update)).isEqualTo(1);
update = server().createSqlUpdate("insert into migtest_e_history6 (id, test_number2) values (1, 7)");
update = server().createSqlUpdate("insert into migtest_e_history6 (id, test_number1, test_number2) values (1, 2, 7)");
assertThat(server().execute(update)).isEqualTo(1);
update = server().createSqlUpdate("update migtest_e_history6 set test_number2 = 45 where id = 1");
assertThat(server().execute(update)).isEqualTo(1);
@@ -185,7 +185,7 @@ public class PlatformDdl_AlterColumnTest {
assertEquals("alter table mytab alter acol drop default", sql);
sql = sqlServerDdl.alterColumnDefaultValue("mytab", "acol", "DROP DEFAULT");
assertThat(sql).startsWith("delimiter $$").endsWith("$$");
assertEquals("EXEC usp_ebean_drop_default_constraint mytab, acol", sql);
}
@Test
@@ -12,7 +12,7 @@ public class ExtraDdlXmlReaderTest {
@Test
public void read(){
ExtraDdl read = ExtraDdlXmlReader.read("/extra-ddl.xml");
ExtraDdl read = ExtraDdlXmlReader.read();
assertNotNull(read);
}
@@ -6,7 +6,6 @@ import javax.validation.constraints.Size;
@Embeddable
public class CKeyParentId {
@Size(max=127)
Integer oneKey;
@Size(max=127)
@@ -6,7 +6,6 @@ import javax.validation.constraints.Size;
@Embeddable
public class CKeyParentId {
@Size(max=127)
Integer oneKey;
@Size(max=127)
@@ -62,8 +62,10 @@ public class EBasic {
@Size(max=127)
String description;
@NotNull
@DbDefault("2000-01-01T00:00:00")
//@NotNull
//@DbDefault("2000-01-01T00:00:00") //- date time literals do not work for each platform yet
//@DbDefault("now") //- now does not work for mariaDb
// MariaDb requires: ALTER TABLE `migtest_e_basic` CHANGE `some_date` `some_date` DATETIME(6) NULL DEFAULT CURRENT_TIMESTAMP;
Timestamp someDate;
@NotNull
@@ -108,7 +110,6 @@ public class EBasic {
@DbDefault("42")
int newInteger;
@NotNull
@ManyToOne
@DbMigration(preAlter= "insert into migtest_e_user (id) select distinct user_id from migtest_e_basic") // ensure all users exist
EUser user;
@@ -4,6 +4,7 @@ package misc.migration.v1_1;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.validation.constraints.Size;
import io.ebean.annotation.DbDefault;
import io.ebean.annotation.History;
@@ -14,18 +15,21 @@ import io.ebean.annotation.NotNull;
@Table(name = "migtest_e_history2")
@History
public class EHistory2 {
@Id
Integer id;
@NotNull
@DbDefault("unknown")
String testString;
@HistoryExclude
String testString2;
@NotNull
@DbDefault("unknown")
String testString3;
@Size(max = 20)
String newColumn;
}
@@ -6,7 +6,6 @@ import javax.validation.constraints.Size;
@Embeddable
public class CKeyParentId {
@Size(max=127)
Integer oneKey;
@Size(max=127)
@@ -3,15 +3,14 @@ package org.tests.batchload;
import io.ebean.Ebean;
import io.ebean.FetchConfig;
import io.ebean.Query;
import io.ebean.QueryIterator;
import io.ebean.TransactionalTestCase;
import org.ebeantest.LoggedSqlCollector;
import org.junit.Test;
import org.tests.model.basic.Customer;
import org.tests.model.basic.Order;
import org.tests.model.basic.ResetBasicData;
import org.ebeantest.LoggedSqlCollector;
import org.junit.Test;
import java.util.Iterator;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
@@ -78,13 +77,15 @@ public class TestSecondaryQueries extends TransactionalTestCase {
LoggedSqlCollector.start();
Iterator<Order> orders = Ebean.find(Order.class)
.select("status")
.setMaxRows(10)
.setUseCache(false)
.findIterate();
while (orders.hasNext()) {
orders.next(); // dummy read
try (QueryIterator<Order> orders =
Ebean.find(Order.class).select("status")
.setMaxRows(10)
.setUseCache(false)
.findIterate()) {
while (orders.hasNext()) {
orders.next(); // dummy read
}
}
List<String> sql = LoggedSqlCollector.stop();
@@ -1,5 +1,7 @@
package org.tests.merge;
import io.ebean.annotation.NotNull;
import javax.persistence.Entity;
import javax.persistence.ManyToOne;
@@ -12,7 +14,8 @@ public class MContactMessage extends MBase {
private String notes;
@ManyToOne(optional = false)
@NotNull
@ManyToOne
private MContact contact;
public MContactMessage(String title, String subject) {
@@ -0,0 +1,48 @@
package org.tests.model.composite;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.JoinColumns;
import javax.persistence.ManyToOne;
@Entity
public class CkeClient {
@EmbeddedId
private CkeClientKey clientPK;
@JoinColumns({
@JoinColumn(name = "username", referencedColumnName = "username"),
@JoinColumn(name = "cod_cpny", referencedColumnName = "cod_cpny", insertable = false, updatable = false)
})
@ManyToOne(optional = false, fetch = FetchType.LAZY)
private CkeUser user;
private String notes;
public CkeUser getUser() {
return user;
}
public void setUser(CkeUser user) {
this.user = user;
}
public CkeClientKey getClientPK() {
return clientPK;
}
public void setClientPK(CkeClientKey clientPK) {
this.clientPK = clientPK;
}
public String getNotes() {
return notes;
}
public void setNotes(String notes) {
this.notes = notes;
}
}
@@ -0,0 +1,53 @@
package org.tests.model.composite;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import java.util.Objects;
@Embeddable
public class CkeClientKey {
@Basic(optional = false)
@Column(name = "cod_cpny")
private int codCompany;
@Basic(optional = false)
@Column(name = "cod_client")
private String codClient;
public CkeClientKey(int codCompany, String codClient) {
this.codCompany = codCompany;
this.codClient = codClient;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
CkeClientKey that = (CkeClientKey) o;
return codCompany == that.codCompany &&
Objects.equals(codClient, that.codClient);
}
@Override
public int hashCode() {
return Objects.hash(codCompany, codClient);
}
public int getCodCompany() {
return codCompany;
}
public void setCodCompany(int codCompany) {
this.codCompany = codCompany;
}
public String getCodClient() {
return codClient;
}
public void setCodClient(String codClient) {
this.codClient = codClient;
}
}
@@ -0,0 +1,29 @@
package org.tests.model.composite;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
@Entity
public class CkeUser {
@EmbeddedId
private CkeUserKey userPK;
private String name;
public CkeUserKey getUserPK() {
return userPK;
}
public void setUserPK(CkeUserKey userPK) {
this.userPK = userPK;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@@ -0,0 +1,53 @@
package org.tests.model.composite;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import java.util.Objects;
@Embeddable
public class CkeUserKey {
@Basic(optional = false)
@Column(name = "cod_cpny")
private int codCompany;
@Basic(optional = false)
@Column(name = "username")
private String username;
public CkeUserKey(int codCompany, String username) {
this.codCompany = codCompany;
this.username = username;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
CkeUserKey that = (CkeUserKey) o;
return codCompany == that.codCompany &&
Objects.equals(username, that.username);
}
@Override
public int hashCode() {
return Objects.hash(codCompany, username);
}
public int getCodCompany() {
return codCompany;
}
public void setCodCompany(int codCompany) {
this.codCompany = codCompany;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
@@ -0,0 +1,50 @@
package org.tests.model.composite;
import io.ebean.BaseTestCase;
import io.ebean.Ebean;
import org.ebeantest.LoggedSqlCollector;
import org.junit.Test;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
public class TestCompositeKeyUserClient extends BaseTestCase {
@Test
public void test() {
CkeUser user0 = new CkeUser();
user0.setUserPK(new CkeUserKey(20, "sally"));
user0.setName("sally");
Ebean.save(user0);
CkeUser user1 = new CkeUser();
user1.setUserPK(new CkeUserKey(20, "frank"));
user1.setName("hello");
Ebean.save(user1);
CkeClient client = new CkeClient();
client.setNotes("try it");
client.setClientPK(new CkeClientKey(20, "susan"));
client.setUser(user1);
LoggedSqlCollector.start();
Ebean.save(client);
client.setNotes("update it");
client.setUser(user0);
Ebean.save(client);
List<String> sql = LoggedSqlCollector.stop();
assertThat(sql).hasSize(2);
assertThat(sql.get(0)).contains("insert into cke_client (cod_cpny, cod_client, notes, username) values (?,?,?,?)");
assertThat(sql.get(1)).contains("update cke_client set notes=?, username=? where cod_cpny=? and cod_client=?");
Ebean.delete(client);
}
}
@@ -0,0 +1,65 @@
package org.tests.o2m.jointable;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinTable;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Version;
import java.util.List;
@Entity
@Table(name="mkeygroup")
public class JtMonkeyGroup {
@Id
long pid;
String name;
/**
* No cascading over to Monkey but we do maintain the join table regardless.
*/
@OneToMany
@JoinTable
List<JtMonkey> monkeys;
@Version
long version;
public JtMonkeyGroup(String name) {
this.name = name;
}
public long getPid() {
return pid;
}
public void setPid(long pid) {
this.pid = pid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<JtMonkey> getMonkeys() {
return monkeys;
}
public void setMonkeys(List<JtMonkey> monkeys) {
this.monkeys = monkeys;
}
public long getVersion() {
return version;
}
public void setVersion(long version) {
this.version = version;
}
}
@@ -0,0 +1,72 @@
package org.tests.o2m.jointable;
import io.ebean.BaseTestCase;
import io.ebean.Ebean;
import org.ebeantest.LoggedSqlCollector;
import org.junit.Test;
import java.util.Arrays;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
public class TestOneToManyJoinTableNoTableName extends BaseTestCase {
private JtMonkeyGroup troop = new JtMonkeyGroup("Pink");
private JtMonkey m0 = new JtMonkey("Sim3");
private JtMonkey m1 = new JtMonkey("Tim3");
private JtMonkey m2 = new JtMonkey("Uim3");
private void initialInsert() {
Ebean.saveAll(Arrays.asList(troop, m0, m1, m2));
}
@Test
public void base() {
initialInsert();
LoggedSqlCollector.start();
// make m0 dirty ... but no cascade saved?
m0.setFoodPreference("camera");
troop.getMonkeys().add(m0);
troop.getMonkeys().add(m1);
Ebean.save(troop);
List<String> sql = LoggedSqlCollector.current();
assertThat(sql).hasSize(1);
assertThat(sql.get(0)).contains("insert into mkeygroup_monkey (mkeygroup_pid, monkey_mid) values (?, ?)");
int intersectionRows = Ebean.createSqlQuery("select count(*) as total from mkeygroup_monkey where mkeygroup_pid = ?")
.setParameter(1, troop.getPid())
.findOne()
.getInteger("total");
assertThat(intersectionRows).isEqualTo(2);
LoggedSqlCollector.current();
JtMonkeyGroup fetchTroop = Ebean.find(JtMonkeyGroup.class)
.fetch("monkeys")
.where().idEq(troop.getPid())
.findOne();
assertThat(fetchTroop.getMonkeys()).hasSize(2);
sql = LoggedSqlCollector.current();
assertThat(sql).hasSize(1);
assertThat(trimSql(sql.get(0))).contains("from mkeygroup t0 left join mkeygroup_monkey t1z_ on t1z_.mkeygroup_pid = t0.pid left join monkey t1 on t1.mid = t1z_.monkey_mid where t0.pid = ?");
assertThat(trimSql(sql.get(0))).contains("select t0.pid, t0.name, t0.version, t1.mid, t1.name, t1.food_preference, t1.version");
Ebean.delete(troop);
sql = LoggedSqlCollector.stop();
assertThat(sql).hasSize(2);
assertThat(sql.get(0)).contains("delete from mkeygroup_monkey where mkeygroup_pid = ?");
assertThat(sql.get(1)).contains("delete from mkeygroup where pid=? and version=?");
}
}
@@ -0,0 +1,64 @@
package org.tests.query;
import io.ebean.BaseTestCase;
import org.junit.Test;
import org.tests.model.basic.Contact;
import org.tests.model.basic.Customer;
import org.tests.model.basic.ResetBasicData;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
public class TestQueryFindNative extends BaseTestCase {
@Test
public void joinFromManyToOne() {
ResetBasicData.reset();
String sql =
"select c.id, c.first_name, c.last_name, t.id, t.name " +
" from contact c " +
" join o_customer t on t.id = c.customer_id " +
" where t.name like ? " +
" order by c.first_name, c.last_name";
List<Contact> contacts =
server()
.findNative(Contact.class, sql)
.setParameter(1, "Rob")
.findList();
assertThat(contacts).isNotEmpty();
Customer customer = contacts.get(0).getCustomer();
assertThat(customer).isNotNull();
}
@Test
public void joinFromOneToMany() {
ResetBasicData.reset();
String sql =
"select cu.id, cu.name, ct.id, ct.first_name " +
" from o_customer cu " +
" left join contact ct on cu.id = ct.customer_id " +
" where cu.name like ? " +
" order by name";
List<Customer> customers =
server()
.findNative(Customer.class, sql)
.setParameter(1, "Rob")
.findList();
assertThat(customers).isNotEmpty();
List<Contact> contacts = customers.get(0).getContacts();
assertThat(contacts).isNotEmpty();
}
}
@@ -0,0 +1,36 @@
package org.tests.types;
/**
* Encrypted string.
*
* @author Roland Praml, FOCONIS AG
*
*/
public class EncryptedBinary {
private final byte[] encryptedData;
EncryptedBinary(byte[] encryptedData) {
this.encryptedData = encryptedData;
}
public byte[] getEncryptedData() {
return encryptedData;
}
public byte[] decrypt() {
return xor(encryptedData);
}
public static EncryptedBinary encrypt(final byte[] s) {
return new EncryptedBinary(xor(s));
}
private static byte[] xor(byte[] s) {
byte[] ret = new byte[s.length];
for (int i = 0; i < s.length; i++) {
ret[i] = (byte) (s[i] ^ i);
}
return ret;
}
}
@@ -0,0 +1,41 @@
package org.tests.types;
/**
* Encrypted string.
*
* @author Roland Praml, FOCONIS AG
*
*/
public class EncryptedString {
private final String encryptedData;
EncryptedString(String encryptedData) {
this.encryptedData = encryptedData;
}
public String getEncryptedData() {
return encryptedData;
}
public String decrypt() {
return rot13(encryptedData);
}
public static EncryptedString encrypt(final String s) {
return new EncryptedString(rot13(s));
}
private static String rot13(String s) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c >= 'a' && c <= 'm') c += 13;
else if (c >= 'A' && c <= 'M') c += 13;
else if (c >= 'n' && c <= 'z') c -= 13;
else if (c >= 'N' && c <= 'Z') c -= 13;
sb.append(c);
}
return sb.toString();
}
}
@@ -0,0 +1,83 @@
package org.tests.types;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Lob;
import javax.validation.constraints.Size;
import org.tests.model.BaseModel;
@Entity
public class PasswordStoreModel extends BaseModel {
private static final long serialVersionUID = 1L;
// PasswordStoreModel should have the following column definitions in DDL
// enc1 varchar(30),
// enc2 varchar(40),
// enc3 clob,
// enc4 varbinary(30),
// enc5 varbinary(40),
// enc6 blob,
@Size(max = 30)
private EncryptedString enc1;
@Column(length = 40)
private EncryptedString enc2;
@Lob
private EncryptedString enc3;
@Size(max = 30)
private EncryptedBinary enc4;
@Column(length = 40)
private EncryptedBinary enc5;
@Lob
private EncryptedBinary enc6;
public EncryptedString getEnc1() {
return enc1;
}
public void setEnc1(EncryptedString enc1) {
this.enc1 = enc1;
}
public EncryptedString getEnc2() {
return enc2;
}
public void setEnc2(EncryptedString enc2) {
this.enc2 = enc2;
}
public EncryptedString getEnc3() {
return enc3;
}
public void setEnc3(EncryptedString enc3) {
this.enc3 = enc3;
}
public EncryptedBinary getEnc4() {
return enc4;
}
public void setEnc4(EncryptedBinary enc4) {
this.enc4 = enc4;
}
public EncryptedBinary getEnc5() {
return enc5;
}
public void setEnc5(EncryptedBinary enc5) {
this.enc5 = enc5;
}
public EncryptedBinary getEnc6() {
return enc6;
}
public void setEnc6(EncryptedBinary enc6) {
this.enc6 = enc6;
}
}
@@ -0,0 +1,23 @@
package org.tests.types;
import io.ebean.config.ScalarTypeConverter;
public class ScalarTypeEncryptedBinaryConverter implements ScalarTypeConverter<EncryptedBinary, byte[]> {
@Override
public EncryptedBinary getNullValue() {
return null;
}
@Override
public EncryptedBinary wrapValue(final byte[] scalarType) {
return new EncryptedBinary(scalarType);
}
@Override
public byte[] unwrapValue(final EncryptedBinary beanType) {
return beanType.getEncryptedData();
}
}
@@ -0,0 +1,22 @@
package org.tests.types;
import io.ebean.config.ScalarTypeConverter;
public class ScalarTypeEncryptedStringConverter implements ScalarTypeConverter<EncryptedString, String> {
@Override
public EncryptedString getNullValue() {
return null;
}
@Override
public EncryptedString wrapValue(final String scalarType) {
return new EncryptedString(scalarType);
}
@Override
public String unwrapValue(final EncryptedString beanType) {
return beanType.getEncryptedData();
}
}
@@ -0,0 +1,46 @@
package org.tests.types;
import io.ebean.BaseTestCase;
import io.ebean.Ebean;
import org.junit.Test;
import java.nio.charset.StandardCharsets;
import static org.assertj.core.api.Assertions.assertThat;
public class TestEncryptedString extends BaseTestCase {
@Test
public void testName() {
PasswordStoreModel model = new PasswordStoreModel();
model.setEnc1(EncryptedString.encrypt("Hello"));
model.setEnc2(EncryptedString.encrypt("World"));
model.setEnc3(EncryptedString.encrypt("Test"));
model.setEnc4(EncryptedBinary.encrypt("Hello".getBytes(StandardCharsets.UTF_8)));
model.setEnc5(EncryptedBinary.encrypt("World".getBytes(StandardCharsets.UTF_8)));
model.setEnc6(EncryptedBinary.encrypt("Test".getBytes(StandardCharsets.UTF_8)));
model.save();
model = Ebean.find(PasswordStoreModel.class, model.getId());
assertThat(model.getEnc1().getEncryptedData()).isNotEqualTo("Hello");
assertThat(model.getEnc2().getEncryptedData()).isNotEqualTo("World");
assertThat(model.getEnc3().getEncryptedData()).isNotEqualTo("Test");
assertThat(model.getEnc4().getEncryptedData()).isNotEqualTo("Hello".getBytes(StandardCharsets.UTF_8));
assertThat(model.getEnc5().getEncryptedData()).isNotEqualTo("World".getBytes(StandardCharsets.UTF_8));
assertThat(model.getEnc6().getEncryptedData()).isNotEqualTo("Test".getBytes(StandardCharsets.UTF_8));
assertThat(model.getEnc1().decrypt()).isEqualTo("Hello");
assertThat(model.getEnc2().decrypt()).isEqualTo("World");
assertThat(model.getEnc3().decrypt()).isEqualTo("Test");
assertThat(model.getEnc4().decrypt()).isEqualTo("Hello".getBytes(StandardCharsets.UTF_8));
assertThat(model.getEnc5().decrypt()).isEqualTo("World".getBytes(StandardCharsets.UTF_8));
assertThat(model.getEnc6().decrypt()).isEqualTo("Test".getBytes(StandardCharsets.UTF_8));
}
}
@@ -2,6 +2,9 @@ package org.tests.types;
import io.ebean.BaseTestCase;
import io.ebean.Ebean;
import io.ebean.plugin.BeanType;
import io.ebean.plugin.ExpressionPath;
import org.junit.Test;
import org.tests.model.types.SomeNewTypesBean;
@@ -21,9 +24,7 @@ import java.time.ZonedDateTime;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.*;
public class TestNewTypes extends BaseTestCase {
@@ -145,4 +146,90 @@ public class TestNewTypes extends BaseTestCase {
assertNull(fetched.getPath());
assertNull(fetched.getPeriod());
}
@Test
public void testSetGetPathNonNull() throws Exception {
SomeNewTypesBean refBean = new SomeNewTypesBean();
refBean.setLocalDate(LocalDate.now());
refBean.setLocalDateTime(LocalDateTime.now());
refBean.setOffsetDateTime(OffsetDateTime.now());
refBean.setZonedDateTime(ZonedDateTime.now());
refBean.setInstant(Instant.now());
refBean.setYear(Year.now());
refBean.setMonth(Month.APRIL);
refBean.setDayOfWeek(DayOfWeek.WEDNESDAY);
refBean.setZoneId(ZoneId.systemDefault());
refBean.setZoneOffset(ZonedDateTime.now().getOffset());
refBean.setYearMonth(YearMonth.of(2014, 9));
refBean.setPath(Paths.get(TEMP_PATH));
refBean.setPeriod(Period.of(4,3,2));
testSetGetPath(refBean);
}
@Test
public void testSetGetPathNull() throws Exception {
SomeNewTypesBean refBean = new SomeNewTypesBean();
testSetGetPath(refBean);
}
private void testSetGetPath(SomeNewTypesBean refBean) {
SomeNewTypesBean testBean = new SomeNewTypesBean();
BeanType<SomeNewTypesBean> beanType = Ebean.getDefaultServer().getPluginApi().getBeanType(SomeNewTypesBean.class);
ExpressionPath localDate = beanType.getExpressionPath("localDate");
ExpressionPath localDateTime = beanType.getExpressionPath("localDateTime");
ExpressionPath offsetDateTime = beanType.getExpressionPath("offsetDateTime");
ExpressionPath zonedDateTime = beanType.getExpressionPath("zonedDateTime");
ExpressionPath instant = beanType.getExpressionPath("instant");
ExpressionPath year = beanType.getExpressionPath("year");
ExpressionPath month = beanType.getExpressionPath("month");
ExpressionPath dayOfWeek = beanType.getExpressionPath("dayOfWeek");
ExpressionPath zoneId = beanType.getExpressionPath("zoneId");
ExpressionPath zoneOffset = beanType.getExpressionPath("zoneOffset");
ExpressionPath yearMonth = beanType.getExpressionPath("yearMonth");
ExpressionPath path = beanType.getExpressionPath("path");
ExpressionPath period = beanType.getExpressionPath("period");
localDate.pathSet(testBean, refBean.getLocalDate());
assertThat(localDate.pathGet(testBean)).isEqualTo(refBean.getLocalDate());
localDateTime.pathSet(testBean, refBean.getLocalDateTime());
assertThat(localDateTime.pathGet(testBean)).isEqualTo(refBean.getLocalDateTime());
offsetDateTime.pathSet(testBean, refBean.getOffsetDateTime());
assertThat(offsetDateTime.pathGet(testBean)).isEqualTo(refBean.getOffsetDateTime());
zonedDateTime.pathSet(testBean, refBean.getZonedDateTime());
assertThat(zonedDateTime.pathGet(testBean)).isEqualTo(refBean.getZonedDateTime());
instant.pathSet(testBean, refBean.getInstant());
assertThat(instant.pathGet(testBean)).isEqualTo(refBean.getInstant());
year.pathSet(testBean, refBean.getYear());
assertThat(year.pathGet(testBean)).isEqualTo(refBean.getYear());
month.pathSet(testBean, refBean.getMonth());
assertThat(month.pathGet(testBean)).isEqualTo(refBean.getMonth());
dayOfWeek.pathSet(testBean, refBean.getDayOfWeek());
assertThat(dayOfWeek.pathGet(testBean)).isEqualTo(refBean.getDayOfWeek());
zoneId.pathSet(testBean, refBean.getZoneId());
assertThat(zoneId.pathGet(testBean)).isEqualTo(refBean.getZoneId());
zoneOffset.pathSet(testBean, refBean.getZoneOffset());
assertThat(zoneOffset.pathGet(testBean)).isEqualTo(refBean.getZoneOffset());
yearMonth.pathSet(testBean, refBean.getYearMonth());
assertThat(yearMonth.pathGet(testBean)).isEqualTo(refBean.getYearMonth());
path.pathSet(testBean, refBean.getPath());
assertThat(path.pathGet(testBean)).isEqualTo(refBean.getPath());
period.pathSet(testBean, refBean.getPeriod());
assertThat(period.pathGet(testBean)).isEqualTo(refBean.getPeriod());
Ebean.save(refBean);
Ebean.save(testBean);
}
}
@@ -39,10 +39,6 @@ alter table migtest_e_basic add constraint ck_mgtst__bsc_stts check ( status in
-- rename all collisions;
-- NOT SUPPORTED alter table migtest_e_basic add constraint uq_mgtst__b_vs45xo unique (description);
update migtest_e_basic set some_date = '2000-01-01T00:00:00' where some_date is null;
alter table migtest_e_basic alter column some_date set default '2000-01-01T00:00:00';
alter table migtest_e_basic alter column some_date set not null;
insert into migtest_e_user (id) select distinct user_id from migtest_e_basic;
alter table migtest_e_basic add constraint fk_mgtst__bsc_sr_d foreign key (user_id) references migtest_e_user (id) on delete restrict;
alter table migtest_e_basic alter column user_id set null;
@@ -72,6 +68,7 @@ alter table migtest_e_history2 alter column test_string set default 'unknown';
alter table migtest_e_history2 alter column test_string set not null;
alter table migtest_e_history2 add column test_string2 varchar(255);
alter table migtest_e_history2 add column test_string3 varchar(255) default 'unknown' not null;
alter table migtest_e_history2 add column new_column varchar(20);
alter table migtest_e_history4 alter column test_number bigint;
alter table migtest_e_history5 add column test_boolean boolean default false not null;
@@ -19,8 +19,6 @@ alter table migtest_e_basic alter column status drop default;
alter table migtest_e_basic alter column status set null;
alter table migtest_e_basic add constraint ck_mgtst__bsc_stts check ( status in ('N','A','I'));
alter table migtest_e_basic drop constraint uq_mgtst__b_vs45xo;
alter table migtest_e_basic alter column some_date drop default;
alter table migtest_e_basic alter column some_date set null;
update migtest_e_basic set user_id = 23 where user_id is null;
alter table migtest_e_basic drop constraint fk_mgtst__bsc_sr_d;
@@ -20,6 +20,8 @@ alter table migtest_e_history2 drop column test_string2;
alter table migtest_e_history2 drop column test_string3;
alter table migtest_e_history2 drop column new_column;
alter table migtest_e_history5 drop column test_boolean;
alter table migtest_e_softdelete drop column deleted;
@@ -13,7 +13,7 @@ create table migtest_ckey_detail (
);
create table migtest_ckey_parent (
one_key integer(127) not null,
one_key integer not null,
two_key varchar(127) not null,
name varchar(255),
version integer not null,
@@ -23,7 +23,7 @@ create table migtest_mtm_m_migtest_mtm_c (
constraint pk_migtest_mtm_m_migtest_mtm_c primary key (migtest_mtm_m_id,migtest_mtm_c_id)
);
alter table migtest_ckey_detail add column one_key integer(127);
alter table migtest_ckey_detail add column one_key integer;
alter table migtest_ckey_detail add column two_key varchar(127);
alter table migtest_ckey_detail add constraint fk_migtest_ckey_detail_parent foreign key (one_key,two_key) references migtest_ckey_parent (one_key,two_key) on delete restrict on update restrict;
@@ -45,10 +45,6 @@ alter table migtest_e_basic add constraint ck_migtest_e_basic_status check ( sta
-- rename all collisions;
alter table migtest_e_basic add constraint uq_migtest_e_basic_description unique (description);
update migtest_e_basic set some_date = '2000-01-01T00:00:00' where some_date is null;
alter table migtest_e_basic alter column some_date set default '2000-01-01T00:00:00';
alter table migtest_e_basic alter column some_date set not null;
insert into migtest_e_user (id) select distinct user_id from migtest_e_basic;
alter table migtest_e_basic add constraint fk_migtest_e_basic_user_id foreign key (user_id) references migtest_e_user (id) on delete restrict on update restrict;
alter table migtest_e_basic alter column user_id set null;
@@ -78,8 +74,10 @@ alter table migtest_e_history2 alter column test_string set default 'unknown';
alter table migtest_e_history2 alter column test_string set not null;
alter table migtest_e_history2 add column test_string2 varchar(255);
alter table migtest_e_history2 add column test_string3 varchar(255) default 'unknown' not null;
alter table migtest_e_history2 add column new_column varchar(20);
alter table migtest_e_history2_history add column test_string2 varchar(255);
alter table migtest_e_history2_history add column test_string3 varchar(255) default 'unknown';
alter table migtest_e_history2_history add column new_column varchar(20);
alter table migtest_e_history4 alter column test_number bigint;
alter table migtest_e_history4_history alter column test_number bigint;
@@ -136,7 +134,7 @@ create view migtest_e_history4_with_history as select * from migtest_e_history4
create view migtest_e_history5_with_history as select * from migtest_e_history5 union all select * from migtest_e_history5_history;
create trigger migtest_e_history_history_upd before update,delete on migtest_e_history for each row call "io.ebean.config.dbplatform.h2.H2HistoryTrigger";
-- changes: [add test_string2, add test_string3]
-- changes: [add test_string2, add test_string3, add new_column]
drop trigger migtest_e_history2_history_upd;
create trigger migtest_e_history2_history_upd before update,delete on migtest_e_history2 for each row call "io.ebean.config.dbplatform.h2.H2HistoryTrigger";
-- changes: [exclude test_string]
@@ -24,8 +24,6 @@ alter table migtest_e_basic alter column status drop default;
alter table migtest_e_basic alter column status set null;
alter table migtest_e_basic add constraint ck_migtest_e_basic_status check ( status in ('N','A','I'));
alter table migtest_e_basic drop constraint uq_migtest_e_basic_description;
alter table migtest_e_basic alter column some_date drop default;
alter table migtest_e_basic alter column some_date set null;
update migtest_e_basic set user_id = 23 where user_id is null;
alter table migtest_e_basic drop constraint if exists fk_migtest_e_basic_user_id;
@@ -32,6 +32,9 @@ alter table migtest_e_history2_history drop column test_string2;
alter table migtest_e_history2 drop column test_string3;
alter table migtest_e_history2_history drop column test_string3;
alter table migtest_e_history2 drop column new_column;
alter table migtest_e_history2_history drop column new_column;
alter table migtest_e_history5 drop column test_boolean;
alter table migtest_e_history5_history drop column test_boolean;
@@ -47,7 +50,7 @@ create view migtest_e_history2_with_history as select * from migtest_e_history2
create view migtest_e_history5_with_history as select * from migtest_e_history5 union all select * from migtest_e_history5_history;
-- changes: [drop test_string2, drop test_string3]
-- changes: [drop test_string2, drop test_string3, drop new_column]
drop trigger migtest_e_history2_history_upd;
create trigger migtest_e_history2_history_upd before update,delete on migtest_e_history2 for each row call "io.ebean.config.dbplatform.h2.H2HistoryTrigger";
-- changes: [drop test_boolean]
@@ -39,10 +39,6 @@ alter table migtest_e_basic add constraint ck_migtest_e_basic_status check ( sta
-- rename all collisions;
alter table migtest_e_basic add constraint uq_migtest_e_basic_description unique (description);
update migtest_e_basic set some_date = '2000-01-01T00:00:00' where some_date is null;
alter table migtest_e_basic alter column some_date set default '2000-01-01T00:00:00';
alter table migtest_e_basic alter column some_date set not null;
insert into migtest_e_user (id) select distinct user_id from migtest_e_basic;
alter table migtest_e_basic add constraint fk_migtest_e_basic_user_id foreign key (user_id) references migtest_e_user (id) on delete restrict on update restrict;
alter table migtest_e_basic alter column user_id set null;
@@ -72,6 +68,7 @@ alter table migtest_e_history2 alter column test_string set default 'unknown';
alter table migtest_e_history2 alter column test_string set not null;
alter table migtest_e_history2 add column test_string2 varchar(255);
alter table migtest_e_history2 add column test_string3 varchar(255) default 'unknown' not null;
alter table migtest_e_history2 add column new_column varchar(20);
alter table migtest_e_history4 alter column test_number bigint;
alter table migtest_e_history5 add column test_boolean boolean default false not null;
@@ -19,8 +19,6 @@ alter table migtest_e_basic alter column status drop default;
alter table migtest_e_basic alter column status set null;
alter table migtest_e_basic add constraint ck_migtest_e_basic_status check ( status in ('N','A','I'));
alter table migtest_e_basic drop constraint uq_migtest_e_basic_description;
alter table migtest_e_basic alter column some_date drop default;
alter table migtest_e_basic alter column some_date set null;
update migtest_e_basic set user_id = 23 where user_id is null;
alter table migtest_e_basic drop constraint if exists fk_migtest_e_basic_user_id;
@@ -20,6 +20,8 @@ alter table migtest_e_history2 drop column test_string2;
alter table migtest_e_history2 drop column test_string3;
alter table migtest_e_history2 drop column new_column;
alter table migtest_e_history5 drop column test_boolean;
alter table migtest_e_softdelete drop column deleted;
@@ -10,7 +10,7 @@
<column name="something" type="varchar"/>
</createTable>
<createTable name="migtest_ckey_parent" pkName="pk_migtest_ckey_parent">
<column name="one_key" type="integer(127)" primaryKey="true"/>
<column name="one_key" type="integer" primaryKey="true"/>
<column name="two_key" type="varchar(127)" primaryKey="true"/>
<column name="name" type="varchar"/>
<column name="version" type="integer" notnull="true"/>
@@ -2,7 +2,7 @@
<migration xmlns="http://ebean-orm.github.io/xml/ns/dbmigration">
<changeSet type="apply">
<addColumn tableName="migtest_ckey_detail">
<column name="one_key" type="integer(127)"/>
<column name="one_key" type="integer"/>
<column name="two_key" type="varchar(127)"/>
</addColumn>
<alterForeignKey name="fk_migtest_ckey_detail_parent" columnNames="one_key,two_key" refColumnNames="one_key,two_key" refTableName="migtest_ckey_parent" indexName="ix_migtest_ckey_detail_parent" tableName="migtest_ckey_detail"/>
@@ -17,7 +17,6 @@
<alterColumn columnName="description" tableName="migtest_e_basic" unique="uq_migtest_e_basic_description">
<before>-- rename all collisions</before>
</alterColumn>
<alterColumn columnName="some_date" tableName="migtest_e_basic" currentType="timestamp" defaultValue="'2000-01-01T00:00:00'" notnull="true" currentNotnull="false"/>
<alterColumn columnName="user_id" tableName="migtest_e_basic" currentType="integer" notnull="false" currentNotnull="true" references="migtest_e_user.id" foreignKeyName="fk_migtest_e_basic_user_id" foreignKeyIndex="ix_migtest_e_basic_user_id">
<before>insert into migtest_e_user (id) select distinct user_id from migtest_e_basic</before>
</alterColumn>
@@ -46,6 +45,7 @@
<addColumn tableName="migtest_e_history2" withHistory="true">
<column name="test_string2" type="varchar" historyExclude="true"/>
<column name="test_string3" type="varchar" defaultValue="'unknown'" notnull="true"/>
<column name="new_column" type="varchar(20)"/>
</addColumn>
<alterColumn columnName="test_string" tableName="migtest_e_history3" withHistory="true" historyExclude="true"/>
<alterColumn columnName="test_number" tableName="migtest_e_history4" withHistory="true" type="bigint" currentType="integer" currentNotnull="false"/>
@@ -8,7 +8,6 @@
<alterColumn columnName="one_id" tableName="migtest_fk_set_null" references="migtest_fk_one.id" foreignKeyName="fk_migtest_fk_set_null_one_id" foreignKeyIndex="ix_migtest_fk_set_null_one_id" foreignKeyOnDelete="SET_NULL" foreignKeyOnUpdate="RESTRICT" dropForeignKey="fk_migtest_fk_set_null_one_id" dropForeignKeyIndex="ix_migtest_fk_set_null_one_id"/>
<alterColumn columnName="status" tableName="migtest_e_basic" currentType="varchar(1)" defaultValue="DROP DEFAULT" notnull="false" currentNotnull="true" checkConstraint="check ( status in ('N','A','I'))" checkConstraintName="ck_migtest_e_basic_status"/>
<alterColumn columnName="description" tableName="migtest_e_basic" dropUnique="uq_migtest_e_basic_description"/>
<alterColumn columnName="some_date" tableName="migtest_e_basic" currentType="timestamp" defaultValue="DROP DEFAULT" notnull="false" currentNotnull="true"/>
<alterColumn columnName="user_id" tableName="migtest_e_basic" currentType="integer" defaultValue="23" notnull="true" currentNotnull="false" dropForeignKey="fk_migtest_e_basic_user_id" dropForeignKeyIndex="ix_migtest_e_basic_user_id"/>
<addColumn tableName="migtest_e_basic">
<column name="old_boolean" type="boolean" defaultValue="false" notnull="true"/>
@@ -55,6 +54,7 @@
<dropHistoryTable baseTable="migtest_e_history"/>
<dropColumn columnName="test_string2" tableName="migtest_e_history2" withHistory="true"/>
<dropColumn columnName="test_string3" tableName="migtest_e_history2" withHistory="true"/>
<dropColumn columnName="new_column" tableName="migtest_e_history2" withHistory="true"/>
<dropColumn columnName="test_boolean" tableName="migtest_e_history5" withHistory="true"/>
<dropColumn columnName="deleted" tableName="migtest_e_softdelete"/>
<dropColumn columnName="master_id" tableName="migtest_oto_child"/>
@@ -12,6 +12,7 @@
<dropHistoryTable baseTable="migtest_e_history"/>
<dropColumn columnName="test_string2" tableName="migtest_e_history2" withHistory="true"/>
<dropColumn columnName="test_string3" tableName="migtest_e_history2" withHistory="true"/>
<dropColumn columnName="new_column" tableName="migtest_e_history2" withHistory="true"/>
<dropColumn columnName="test_boolean" tableName="migtest_e_history5" withHistory="true"/>
<dropColumn columnName="deleted" tableName="migtest_e_softdelete"/>
<dropColumn columnName="master_id" tableName="migtest_oto_child"/>
@@ -13,7 +13,7 @@ create table migtest_ckey_detail (
);
create table migtest_ckey_parent (
one_key integer(127) not null,
one_key integer not null,
two_key varchar(127) not null,
name varchar(255),
version integer not null,
@@ -23,7 +23,7 @@ create table migtest_mtm_m_migtest_mtm_c (
constraint pk_migtest_mtm_m_migtest_mtm_c primary key (migtest_mtm_m_id,migtest_mtm_c_id)
);
alter table migtest_ckey_detail add column one_key integer(127);
alter table migtest_ckey_detail add column one_key integer;
alter table migtest_ckey_detail add column two_key varchar(127);
alter table migtest_ckey_detail add constraint fk_migtest_ckey_detail_parent foreign key (one_key,two_key) references migtest_ckey_parent (one_key,two_key) on delete restrict on update restrict;
@@ -44,10 +44,6 @@ alter table migtest_e_basic add constraint ck_migtest_e_basic_status check ( sta
-- rename all collisions;
alter table migtest_e_basic add constraint uq_migtest_e_basic_description unique (description);
update migtest_e_basic set some_date = '2000-01-01T00:00:00' where some_date is null;
alter table migtest_e_basic alter some_date set default '2000-01-01T00:00:00';
alter table migtest_e_basic modify some_date datetime(6) not null;
insert into migtest_e_user (id) select distinct user_id from migtest_e_basic;
alter table migtest_e_basic add constraint fk_migtest_e_basic_user_id foreign key (user_id) references migtest_e_user (id) on delete restrict on update restrict;
alter table migtest_e_basic modify user_id integer;
@@ -75,8 +71,10 @@ alter table migtest_e_history2 alter test_string set default 'unknown';
alter table migtest_e_history2 modify test_string varchar(255) not null;
alter table migtest_e_history2 add column test_string2 varchar(255);
alter table migtest_e_history2 add column test_string3 varchar(255) default 'unknown' not null;
alter table migtest_e_history2 add column new_column varchar(20);
alter table migtest_e_history2_history add column test_string2 varchar(255);
alter table migtest_e_history2_history add column test_string3 varchar(255) default 'unknown';
alter table migtest_e_history2_history add column new_column varchar(20);
alter table migtest_e_history4 modify test_number bigint;
alter table migtest_e_history4_history modify test_number bigint;
@@ -142,17 +140,17 @@ create trigger migtest_e_history_history_del before delete on migtest_e_history
insert into migtest_e_history_history (sys_period_start,sys_period_end,id, test_string) values (OLD.sys_period_start, now(6),OLD.id, OLD.test_string);
end$$
lock tables migtest_e_history2 write, migtest_e_history3 write, migtest_e_history4 write, migtest_e_history5 write;
-- changes: [add test_string2, add test_string3]
-- changes: [add test_string2, add test_string3, add new_column]
drop trigger migtest_e_history2_history_upd;
drop trigger migtest_e_history2_history_del;
delimiter $$
create trigger migtest_e_history2_history_upd before update on migtest_e_history2 for each row begin
insert into migtest_e_history2_history (sys_period_start,sys_period_end,id, test_string, test_string3, obsolete_string1, obsolete_string2) values (OLD.sys_period_start, now(6),OLD.id, OLD.test_string, OLD.test_string3, OLD.obsolete_string1, OLD.obsolete_string2);
insert into migtest_e_history2_history (sys_period_start,sys_period_end,id, test_string, test_string3, new_column, obsolete_string1, obsolete_string2) values (OLD.sys_period_start, now(6),OLD.id, OLD.test_string, OLD.test_string3, OLD.new_column, OLD.obsolete_string1, OLD.obsolete_string2);
set NEW.sys_period_start = now(6);
end$$
delimiter $$
create trigger migtest_e_history2_history_del before delete on migtest_e_history2 for each row begin
insert into migtest_e_history2_history (sys_period_start,sys_period_end,id, test_string, test_string3, obsolete_string1, obsolete_string2) values (OLD.sys_period_start, now(6),OLD.id, OLD.test_string, OLD.test_string3, OLD.obsolete_string1, OLD.obsolete_string2);
insert into migtest_e_history2_history (sys_period_start,sys_period_end,id, test_string, test_string3, new_column, obsolete_string1, obsolete_string2) values (OLD.sys_period_start, now(6),OLD.id, OLD.test_string, OLD.test_string3, OLD.new_column, OLD.obsolete_string1, OLD.obsolete_string2);
end$$
-- changes: [exclude test_string]
drop trigger migtest_e_history3_history_upd;
@@ -3,17 +3,17 @@
drop view if exists migtest_e_history2_with_history;
-- apply changes
alter table migtest_e_basic drop column old_boolean;
CALL usp_ebean_drop_column('migtest_e_basic', 'old_boolean');
alter table migtest_e_basic drop column old_boolean2;
CALL usp_ebean_drop_column('migtest_e_basic', 'old_boolean2');
alter table migtest_e_basic drop column eref_id;
CALL usp_ebean_drop_column('migtest_e_basic', 'eref_id');
alter table migtest_e_history2 drop column obsolete_string1;
alter table migtest_e_history2_history drop column obsolete_string1;
CALL usp_ebean_drop_column('migtest_e_history2', 'obsolete_string1');
CALL usp_ebean_drop_column('migtest_e_history2_history', 'obsolete_string1');
alter table migtest_e_history2 drop column obsolete_string2;
alter table migtest_e_history2_history drop column obsolete_string2;
CALL usp_ebean_drop_column('migtest_e_history2', 'obsolete_string2');
CALL usp_ebean_drop_column('migtest_e_history2_history', 'obsolete_string2');
drop table if exists migtest_e_ref;
create view migtest_e_history2_with_history as select * from migtest_e_history2 union all select * from migtest_e_history2_history;
@@ -24,11 +24,11 @@ drop trigger migtest_e_history2_history_upd;
drop trigger migtest_e_history2_history_del;
delimiter $$
create trigger migtest_e_history2_history_upd before update on migtest_e_history2 for each row begin
insert into migtest_e_history2_history (sys_period_start,sys_period_end,id, test_string, test_string3) values (OLD.sys_period_start, now(6),OLD.id, OLD.test_string, OLD.test_string3);
insert into migtest_e_history2_history (sys_period_start,sys_period_end,id, test_string, test_string3, new_column) values (OLD.sys_period_start, now(6),OLD.id, OLD.test_string, OLD.test_string3, OLD.new_column);
set NEW.sys_period_start = now(6);
end$$
delimiter $$
create trigger migtest_e_history2_history_del before delete on migtest_e_history2 for each row begin
insert into migtest_e_history2_history (sys_period_start,sys_period_end,id, test_string, test_string3) values (OLD.sys_period_start, now(6),OLD.id, OLD.test_string, OLD.test_string3);
insert into migtest_e_history2_history (sys_period_start,sys_period_end,id, test_string, test_string3, new_column) values (OLD.sys_period_start, now(6),OLD.id, OLD.test_string, OLD.test_string3, OLD.new_column);
end$$
unlock tables;

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