mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
94
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
04cd520719 | ||
|
|
838af0478e | ||
|
|
9064e96b90 | ||
|
|
8e91268979 | ||
|
|
cc637d56e1 | ||
|
|
9846ebd65d | ||
|
|
b568e2efc7 | ||
|
|
20fc74219a | ||
|
|
92a4bfb38e | ||
|
|
5c34b0daa5 | ||
|
|
f4ea674d60 | ||
|
|
21f43dc395 | ||
|
|
5082ce4280 | ||
|
|
ed061fb3b1 | ||
|
|
247e96f5db | ||
|
|
ce60eac583 | ||
|
|
c34fcdf7b7 | ||
|
|
dcfada0b52 | ||
|
|
fb3fd439bb | ||
|
|
6226672d27 | ||
|
|
bf72794a4c | ||
|
|
30a00cb092 | ||
|
|
0bfb6895ad | ||
|
|
29345c823e | ||
|
|
e71cb4f2ff | ||
|
|
108a1c7181 | ||
|
|
5ce07afed8 | ||
|
|
d9c4798d4e | ||
|
|
6ecd849499 | ||
|
|
e5b0b31da6 | ||
|
|
1371cb4ff6 | ||
|
|
c788d339fe | ||
|
|
35580fa62b | ||
|
|
b61ae74d3d | ||
|
|
fead4350ce | ||
|
|
04a651c40d | ||
|
|
f394e7f39b | ||
|
|
8f7827d3d9 | ||
|
|
06b54bd824 | ||
|
|
f473e40bfc | ||
|
|
1eb5cf1d22 | ||
|
|
b540d70b2d | ||
|
|
7b5a8aef73 | ||
|
|
3e4daf6947 | ||
|
|
0918cbf221 | ||
|
|
3e078e41ff | ||
|
|
a80ab94479 | ||
|
|
e6f0ab90dc | ||
|
|
53f4739c8f | ||
|
|
c6e33ba3ac | ||
|
|
0e2528e542 | ||
|
|
6ecc10a35c | ||
|
|
59bd2bb251 | ||
|
|
9fa83cdd5a | ||
|
|
f383f3f759 | ||
|
|
c044bc52f7 | ||
|
|
0abcc9e06e | ||
|
|
4a594b32ef | ||
|
|
8b9f760cb2 | ||
|
|
1d1cf76b5e | ||
|
|
194c14b99a | ||
|
|
fa8c6839dd | ||
|
|
1e44b81e87 | ||
|
|
85b21a02e8 | ||
|
|
4313fb6f58 | ||
|
|
ee19fd17fa | ||
|
|
a7c6f9835a | ||
|
|
06b1babed9 | ||
|
|
73ea91d4c9 | ||
|
|
14839f0c0f | ||
|
|
db8f4e141d | ||
|
|
09fa406f84 | ||
|
|
50d22ba357 | ||
|
|
c6f9d193be | ||
|
|
5e1aa47c05 | ||
|
|
21dd8cee37 | ||
|
|
ece82996c2 | ||
|
|
fa520c95ea | ||
|
|
a6685141a4 | ||
|
|
78ab0ad923 | ||
|
|
4fb67a4c8c | ||
|
|
dd94e60d16 | ||
|
|
aa70e17657 | ||
|
|
016cd3fb71 | ||
|
|
17f28ba0aa | ||
|
|
ab88a879e9 | ||
|
|
5b85f3c8dd | ||
|
|
16a5100f35 | ||
|
|
86b2c5d5b5 | ||
|
|
e0c3198ee6 | ||
|
|
12bdd847b5 | ||
|
|
9860816ab7 | ||
|
|
e17283726a | ||
|
|
eff61ae5fc |
+7
-11
@@ -4,9 +4,11 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.5.2-SNAPSHOT</version>
|
||||
<version>12.6.1</version>
|
||||
</parent>
|
||||
|
||||
<name>ebean api</name>
|
||||
<description>ebean api</description>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
|
||||
<properties>
|
||||
@@ -23,14 +25,14 @@
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>1.7.25</version>
|
||||
<version>1.7.30</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.avaje</groupId>
|
||||
<artifactId>avaje-config</artifactId>
|
||||
<version>1.1</version>
|
||||
<version>1.2</version>
|
||||
</dependency>
|
||||
|
||||
<!--
|
||||
@@ -64,14 +66,8 @@
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-datasource</artifactId>
|
||||
<version>6.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-migration</artifactId>
|
||||
<version>12.1.4</version>
|
||||
<artifactId>ebean-datasource-api</artifactId>
|
||||
<version>${ebean-datasource.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Jackson core used internally by Ebean -->
|
||||
|
||||
@@ -70,6 +70,13 @@ public final class DB {
|
||||
private DB() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Backdoor for registering a mock implementation of Database as the default database.
|
||||
*/
|
||||
protected static Database mock(String name, Database server, boolean defaultServer) {
|
||||
return context.mock(name, server, defaultServer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default database.
|
||||
*/
|
||||
|
||||
@@ -14,6 +14,7 @@ import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.persistence.OptimisticLockException;
|
||||
import javax.persistence.PersistenceException;
|
||||
import javax.sql.DataSource;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -121,6 +122,16 @@ public interface Database {
|
||||
*/
|
||||
AutoTune getAutoTune();
|
||||
|
||||
/**
|
||||
* Return the associated DataSource for this Database instance.
|
||||
*/
|
||||
DataSource getDataSource();
|
||||
|
||||
/**
|
||||
* Return the associated read only DataSource for this Database instance (can be null).
|
||||
*/
|
||||
DataSource getReadOnlyDataSource();
|
||||
|
||||
/**
|
||||
* Return the name. This is used with {@link DB#byName(String)} to get a
|
||||
* Database that was registered with the DB singleton.
|
||||
|
||||
@@ -2,8 +2,8 @@ package io.ebean;
|
||||
|
||||
import io.ebean.docstore.DocQueryContext;
|
||||
import io.ebean.docstore.RawDoc;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -2,13 +2,6 @@ package io.ebean;
|
||||
|
||||
import io.ebean.config.ContainerConfig;
|
||||
import io.ebean.config.ServerConfig;
|
||||
import io.ebean.service.SpiContainer;
|
||||
import io.ebean.service.SpiContainerFactory;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.util.Iterator;
|
||||
import java.util.Properties;
|
||||
import java.util.ServiceLoader;
|
||||
|
||||
/**
|
||||
* Deprecated - please migrate to DatabaseFactory.
|
||||
|
||||
@@ -174,6 +174,11 @@ public interface ExpressionList<T> {
|
||||
*/
|
||||
Query<T> forUpdate();
|
||||
|
||||
/**
|
||||
* Execute using "for update" with given lock type (currently Postgres only).
|
||||
*/
|
||||
Query<T> forUpdate(Query.LockType lockType);
|
||||
|
||||
/**
|
||||
* Execute using "for update" clause with No Wait option.
|
||||
* <p>
|
||||
@@ -182,6 +187,11 @@ public interface ExpressionList<T> {
|
||||
*/
|
||||
Query<T> forUpdateNoWait();
|
||||
|
||||
/**
|
||||
* Execute using "for update nowait" with given lock type (currently Postgres only).
|
||||
*/
|
||||
Query<T> forUpdateNoWait(Query.LockType lockType);
|
||||
|
||||
/**
|
||||
* Execute using "for update" clause with Skip Locked option.
|
||||
* <p>
|
||||
@@ -190,6 +200,11 @@ public interface ExpressionList<T> {
|
||||
*/
|
||||
Query<T> forUpdateSkipLocked();
|
||||
|
||||
/**
|
||||
* Execute using "for update skip locked" with given lock type (currently Postgres only).
|
||||
*/
|
||||
Query<T> forUpdateSkipLocked(Query.LockType lockType);
|
||||
|
||||
/**
|
||||
* Execute the query including soft deleted rows.
|
||||
*/
|
||||
|
||||
+3
-10
@@ -1,11 +1,9 @@
|
||||
package io.ebeaninternal.json;
|
||||
|
||||
import java.io.Serializable;
|
||||
package io.ebean;
|
||||
|
||||
/**
|
||||
* Owner object notified when a modification is detected.
|
||||
*/
|
||||
public interface ModifyAwareOwner extends Serializable {
|
||||
public interface ModifyAwareType {
|
||||
|
||||
/**
|
||||
* Return true if the value is considered dirty.
|
||||
@@ -16,11 +14,6 @@ public interface ModifyAwareOwner extends Serializable {
|
||||
/**
|
||||
* Marks the object as modified.
|
||||
*/
|
||||
void markAsModified();
|
||||
|
||||
/**
|
||||
* Reset the dirty state to clean.
|
||||
*/
|
||||
void resetMarkedDirty();
|
||||
void setMarkedDirty(boolean markedDirty);
|
||||
|
||||
}
|
||||
@@ -180,13 +180,43 @@ import java.util.stream.Stream;
|
||||
public interface Query<T> {
|
||||
|
||||
/**
|
||||
* For update mode.
|
||||
* The lock type (strength) to use with query FOR UPDATE row locking.
|
||||
*/
|
||||
enum ForUpdate {
|
||||
enum LockType {
|
||||
/**
|
||||
* The default lock type - See PlatformConfig.forUpdateNoKey option.
|
||||
*/
|
||||
DEFAULT,
|
||||
|
||||
/**
|
||||
* FOR UPDATE.
|
||||
*/
|
||||
UPDATE,
|
||||
|
||||
/**
|
||||
* FOR NO KEY UPDATE.
|
||||
*/
|
||||
NO_KEY_UPDATE,
|
||||
|
||||
/**
|
||||
* FOR SHARE UPDATE.
|
||||
*/
|
||||
SHARE,
|
||||
|
||||
/**
|
||||
* FOR KEY SHARE UPDATE.
|
||||
*/
|
||||
KEY_SHARE
|
||||
}
|
||||
|
||||
/**
|
||||
* FOR UPDATE wait mode.
|
||||
*/
|
||||
enum LockWait {
|
||||
/**
|
||||
* Standard For update clause.
|
||||
*/
|
||||
BASE,
|
||||
WAIT,
|
||||
|
||||
/**
|
||||
* For update with No Wait option.
|
||||
@@ -1618,6 +1648,11 @@ public interface Query<T> {
|
||||
*/
|
||||
Query<T> forUpdate();
|
||||
|
||||
/**
|
||||
* Execute using "for update" with given lock type (currently Postgres only).
|
||||
*/
|
||||
Query<T> forUpdate(LockType lockType);
|
||||
|
||||
/**
|
||||
* Execute using "for update" clause with "no wait" option.
|
||||
* <p>
|
||||
@@ -1626,6 +1661,11 @@ public interface Query<T> {
|
||||
*/
|
||||
Query<T> forUpdateNoWait();
|
||||
|
||||
/**
|
||||
* Execute using "for update nowait" with given lock type (currently Postgres only).
|
||||
*/
|
||||
Query<T> forUpdateNoWait(LockType lockType);
|
||||
|
||||
/**
|
||||
* Execute using "for update" clause with "skip locked" option.
|
||||
* <p>
|
||||
@@ -1634,15 +1674,25 @@ public interface Query<T> {
|
||||
*/
|
||||
Query<T> forUpdateSkipLocked();
|
||||
|
||||
/**
|
||||
* Execute using "for update skip locked" with given lock type (currently Postgres only).
|
||||
*/
|
||||
Query<T> forUpdateSkipLocked(LockType lockType);
|
||||
|
||||
/**
|
||||
* Return true if this query has forUpdate set.
|
||||
*/
|
||||
boolean isForUpdate();
|
||||
|
||||
/**
|
||||
* Return the "for update" mode to use.
|
||||
* Return the "for update" wait mode to use.
|
||||
*/
|
||||
ForUpdate getForUpdateMode();
|
||||
LockWait getForUpdateLockWait();
|
||||
|
||||
/**
|
||||
* Return the lock type (strength) to use with "for update".
|
||||
*/
|
||||
LockType getForUpdateLockType();
|
||||
|
||||
/**
|
||||
* Set root table alias.
|
||||
|
||||
@@ -2,8 +2,8 @@ package io.ebean;
|
||||
|
||||
import io.ebean.annotation.DocStoreMode;
|
||||
import io.ebean.annotation.PersistBatch;
|
||||
import io.ebean.config.DocStoreConfig;
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebean.config.DocStoreConfig;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.sql.Connection;
|
||||
|
||||
@@ -26,20 +26,6 @@ public class ClassLoadConfig {
|
||||
this.context = new ClassLoaderContext(classLoader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the Java.time types are available and should be supported.
|
||||
*/
|
||||
public boolean isJavaTimePresent() {
|
||||
return isPresent("java.time.LocalDate");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if Java7 is present.
|
||||
*/
|
||||
public boolean isJava7Present() {
|
||||
return isPresent("java.nio.file.Path");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the Joda types are available and should be supported.
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package io.ebean.config;
|
||||
|
||||
import io.ebean.config.dbplatform.DbType;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.config.dbplatform.DbType;
|
||||
|
||||
/**
|
||||
* Custom mappings for DB types that override the default.
|
||||
|
||||
@@ -3,6 +3,7 @@ package io.ebean.config;
|
||||
import com.fasterxml.jackson.core.JsonFactory;
|
||||
import io.avaje.config.Config;
|
||||
import io.ebean.DatabaseFactory;
|
||||
import io.ebean.EbeanVersion;
|
||||
import io.ebean.PersistenceContextScope;
|
||||
import io.ebean.Query;
|
||||
import io.ebean.Transaction;
|
||||
@@ -28,12 +29,13 @@ import io.ebean.event.changelog.ChangeLogPrepare;
|
||||
import io.ebean.event.changelog.ChangeLogRegister;
|
||||
import io.ebean.event.readaudit.ReadAuditLogger;
|
||||
import io.ebean.event.readaudit.ReadAuditPrepare;
|
||||
import io.ebean.migration.MigrationRunner;
|
||||
import io.ebean.util.StringHelper;
|
||||
|
||||
import javax.persistence.EnumType;
|
||||
import javax.sql.DataSource;
|
||||
import java.time.Clock;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
@@ -277,6 +279,25 @@ public class DatabaseConfig {
|
||||
|
||||
private String ddlSeedSql;
|
||||
|
||||
private String ddlHeader;
|
||||
|
||||
/**
|
||||
* Mode used to check non-null columns added via migration have a default value specified etc.
|
||||
*/
|
||||
private boolean ddlStrictMode = true;
|
||||
|
||||
/**
|
||||
* Comma and equals delimited key/value placeholders to replace in DDL scripts.
|
||||
*/
|
||||
private String ddlPlaceholders;
|
||||
|
||||
/**
|
||||
* Map of key/value placeholders to replace in DDL scripts.
|
||||
*/
|
||||
private Map<String, String> ddlPlaceholderMap;
|
||||
|
||||
private boolean runMigration;
|
||||
|
||||
/**
|
||||
* When true L2 bean cache use is skipped after a write has occurred on a transaction.
|
||||
*/
|
||||
@@ -322,11 +343,6 @@ public class DatabaseConfig {
|
||||
*/
|
||||
private String dbSchema;
|
||||
|
||||
/**
|
||||
* The db migration config (migration resource path etc).
|
||||
*/
|
||||
private DbMigrationConfig migrationConfig = new DbMigrationConfig();
|
||||
|
||||
/**
|
||||
* The ClassLoadConfig used to detect Joda, Java8, Jackson etc and create plugin instances given a className.
|
||||
*/
|
||||
@@ -1212,20 +1228,6 @@ public class DatabaseConfig {
|
||||
this.dbSchema = dbSchema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DB migration configuration.
|
||||
*/
|
||||
public DbMigrationConfig getMigrationConfig() {
|
||||
return migrationConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the DB migration configuration.
|
||||
*/
|
||||
public void setMigrationConfig(DbMigrationConfig migrationConfig) {
|
||||
this.migrationConfig = migrationConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Geometry SRID.
|
||||
*/
|
||||
@@ -2026,7 +2028,15 @@ public class DatabaseConfig {
|
||||
* as it is often the only thing we need to configure for migrations.
|
||||
*/
|
||||
public void setRunMigration(boolean runMigration) {
|
||||
migrationConfig.setRunMigration(runMigration);
|
||||
this.runMigration = runMigration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the DB migration should run on server start.
|
||||
*/
|
||||
public boolean isRunMigration() {
|
||||
final String run = System.getProperty("ebean.migration.run");
|
||||
return (run != null) ? Boolean.parseBoolean(run) : runMigration;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2134,6 +2144,67 @@ public class DatabaseConfig {
|
||||
return ddlExtra;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the header to use with DDL generation.
|
||||
*/
|
||||
public void setDdlHeader(String ddlHeader) {
|
||||
this.ddlHeader = ddlHeader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the header to use with DDL generation.
|
||||
*/
|
||||
public String getDdlHeader() {
|
||||
if (ddlHeader != null && !ddlHeader.isEmpty()) {
|
||||
String header = ddlHeader.replace("${version}", EbeanVersion.getVersion());
|
||||
header = header.replace("${timestamp}", ZonedDateTime.now().format(DateTimeFormatter.ISO_INSTANT));
|
||||
return header;
|
||||
}
|
||||
return ddlHeader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if strict mode is used which includes a check that non-null columns have a default value.
|
||||
*/
|
||||
public boolean isDdlStrictMode() {
|
||||
return ddlStrictMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to false to turn off strict mode allowing non-null columns to not have a default value.
|
||||
*/
|
||||
public void setDdlStrictMode(boolean ddlStrictMode) {
|
||||
this.ddlStrictMode = ddlStrictMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a comma and equals delimited placeholders that are substituted in DDL scripts.
|
||||
*/
|
||||
public String getDdlPlaceholders() {
|
||||
return ddlPlaceholders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a comma and equals delimited placeholders that are substituted in DDL scripts.
|
||||
*/
|
||||
public void setDdlPlaceholders(String ddlPlaceholders) {
|
||||
this.ddlPlaceholders = ddlPlaceholders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a map of placeholder values that are substituted in DDL scripts.
|
||||
*/
|
||||
public Map<String, String> getDdlPlaceholderMap() {
|
||||
return ddlPlaceholderMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a map of placeholder values that are substituted in DDL scripts.
|
||||
*/
|
||||
public void setDdlPlaceholderMap(Map<String, String> ddlPlaceholderMap) {
|
||||
this.ddlPlaceholderMap = ddlPlaceholderMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the class path search should be disabled.
|
||||
*/
|
||||
@@ -2699,13 +2770,8 @@ public class DatabaseConfig {
|
||||
* Load the configuration settings from the properties file.
|
||||
*/
|
||||
protected void loadSettings(PropertiesWrapper p) {
|
||||
|
||||
dbSchema = p.get("dbSchema", dbSchema);
|
||||
if (dbSchema != null) {
|
||||
migrationConfig.setDefaultDbSchema(dbSchema);
|
||||
}
|
||||
profilingConfig.loadSettings(p, name);
|
||||
migrationConfig.loadSettings(p, name);
|
||||
platformConfig.loadSettings(p);
|
||||
if (platformConfig.isAllQuotedIdentifiers()) {
|
||||
adjustNamingConventionForAllQuoted();
|
||||
@@ -2807,12 +2873,16 @@ public class DatabaseConfig {
|
||||
jsonDateTime = p.getEnum(JsonConfig.DateTime.class, "jsonDateTime", jsonDateTime);
|
||||
jsonDate = p.getEnum(JsonConfig.Date.class, "jsonDate", jsonDate);
|
||||
|
||||
runMigration = p.getBoolean("migration.run", runMigration);
|
||||
ddlGenerate = p.getBoolean("ddl.generate", ddlGenerate);
|
||||
ddlRun = p.getBoolean("ddl.run", ddlRun);
|
||||
ddlExtra = p.getBoolean("ddl.extra", ddlExtra);
|
||||
ddlCreateOnly = p.getBoolean("ddl.createOnly", ddlCreateOnly);
|
||||
ddlInitSql = p.get("ddl.initSql", ddlInitSql);
|
||||
ddlSeedSql = p.get("ddl.seedSql", ddlSeedSql);
|
||||
ddlStrictMode = p.getBoolean("ddl.strictMode", ddlStrictMode);
|
||||
ddlPlaceholders = p.get("ddl.placeholders", ddlPlaceholders);
|
||||
ddlHeader = p.get("ddl.header", ddlHeader);
|
||||
|
||||
// read tenant-configuration from config:
|
||||
// tenant.mode = NONE | DB | SCHEMA | CATALOG | PARTITION
|
||||
@@ -3034,17 +3104,6 @@ public class DatabaseConfig {
|
||||
this.queryPlanTTLSeconds = queryPlanTTLSeconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the DB migration against the DataSource.
|
||||
*/
|
||||
public DataSource runDbMigration(DataSource dataSource) {
|
||||
if (migrationConfig.isRunMigration()) {
|
||||
MigrationRunner runner = migrationConfig.createRunner(getClassLoadConfig().getClassLoader(), properties);
|
||||
runner.run(dataSource);
|
||||
}
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new PlatformConfig based of the one held but with overridden properties by reading
|
||||
* properties with the given path and prefix.
|
||||
|
||||
@@ -1,509 +0,0 @@
|
||||
package io.ebean.config;
|
||||
|
||||
import io.ebean.EbeanVersion;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.migration.MigrationConfig;
|
||||
import io.ebean.migration.MigrationRunner;
|
||||
import io.ebean.util.StringHelper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import static io.ebean.util.StringHelper.replace;
|
||||
|
||||
/**
|
||||
* Configuration for the DB migration processing.
|
||||
*/
|
||||
public class DbMigrationConfig {
|
||||
|
||||
protected static final Logger logger = LoggerFactory.getLogger(DbMigrationConfig.class);
|
||||
|
||||
protected MigrationConfig runnerConfig = new MigrationConfig();
|
||||
|
||||
/**
|
||||
* The database platform to generate migration DDL for.
|
||||
*/
|
||||
protected Platform platform;
|
||||
|
||||
/**
|
||||
* Resource path for the migration xml and sql.
|
||||
*/
|
||||
protected String migrationPath = "dbmigration";
|
||||
|
||||
protected String migrationInitPath = "dbinit";
|
||||
|
||||
/**
|
||||
* Subdirectory the model xml files go into.
|
||||
*/
|
||||
protected String modelPath = "model";
|
||||
|
||||
protected String applySuffix = ".sql";
|
||||
|
||||
/**
|
||||
* Set this to "V" to be compatible with FlywayDB.
|
||||
*/
|
||||
protected String applyPrefix = "";
|
||||
|
||||
protected String modelSuffix = ".model.xml";
|
||||
|
||||
/**
|
||||
* For running migration the DB table that holds migration execution status.
|
||||
*/
|
||||
protected String metaTable = "db_migration";
|
||||
|
||||
/**
|
||||
* Flag set to true means to run any outstanding migrations on startup.
|
||||
*/
|
||||
protected boolean runMigration;
|
||||
|
||||
/**
|
||||
* Comma and equals delimited key/value placeholders to replace in DDL scripts.
|
||||
*/
|
||||
protected String runPlaceholders;
|
||||
|
||||
/**
|
||||
* Map of key/value placeholders to replace in DDL scripts.
|
||||
*/
|
||||
protected Map<String, String> runPlaceholderMap;
|
||||
|
||||
/**
|
||||
* DB schema used for the migration (and testing).
|
||||
*/
|
||||
protected String dbSchema;
|
||||
|
||||
/**
|
||||
* Set to true if we consider this the 'default schema' (Postgres schema that matches DB username)
|
||||
*/
|
||||
protected boolean defaultDbSchema;
|
||||
|
||||
/**
|
||||
* DB user used to run the DB migration.
|
||||
*/
|
||||
protected String dbUsername;
|
||||
|
||||
/**
|
||||
* DB password used to run the DB migration.
|
||||
*/
|
||||
protected String dbPassword;
|
||||
|
||||
protected String patchInsertOn;
|
||||
|
||||
protected String patchResetChecksumOn;
|
||||
|
||||
/**
|
||||
* Mode used to check non-null columns added via migration have a default value specified etc.
|
||||
*/
|
||||
protected boolean strictMode = true;
|
||||
|
||||
/**
|
||||
* Contains the DDL-header information.
|
||||
*/
|
||||
protected String ddlHeader;
|
||||
|
||||
/**
|
||||
* Return the DB platform to generate migration DDL for.
|
||||
* <p>
|
||||
* We typically need to explicitly specify this as migration can often be generated
|
||||
* when running against H2.
|
||||
*/
|
||||
public Platform getPlatform() {
|
||||
return platform;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the DB platform to generate migration DDL for.
|
||||
*/
|
||||
public void setPlatform(Platform platform) {
|
||||
this.platform = platform;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path for normal migrations or dbinit migrations.
|
||||
*
|
||||
* @param dbinitMigration When true return the path for dbinit migrations.
|
||||
*/
|
||||
public String getMigrationPath(boolean dbinitMigration) {
|
||||
return dbinitMigration ? migrationInitPath : migrationPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the resource path for db migrations.
|
||||
*/
|
||||
public String getMigrationPath() {
|
||||
return migrationPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the resource path for db migrations.
|
||||
* <p>
|
||||
* The default of "dbmigration" is reasonable in most cases. You may look to set this
|
||||
* to be something like "dbmigration/myapp" where myapp gives it a unique resource path
|
||||
* in the case there are multiple Database applications in the single classpath.
|
||||
* </p>
|
||||
*/
|
||||
public void setMigrationPath(String migrationPath) {
|
||||
this.migrationPath = migrationPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the relative path for the model files (defaults to model).
|
||||
*/
|
||||
public String getModelPath() {
|
||||
return modelPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the relative path for the model files.
|
||||
*/
|
||||
public void setModelPath(String modelPath) {
|
||||
this.modelPath = modelPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the model suffix (defaults to model.xml)
|
||||
*/
|
||||
public String getModelSuffix() {
|
||||
return modelSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the model suffix.
|
||||
*/
|
||||
public void setModelSuffix(String modelSuffix) {
|
||||
this.modelSuffix = modelSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the apply script suffix (defaults to sql).
|
||||
*/
|
||||
public String getApplySuffix() {
|
||||
return applySuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the apply script suffix (defaults to sql).
|
||||
*/
|
||||
public void setApplySuffix(String applySuffix) {
|
||||
this.applySuffix = applySuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the apply prefix.
|
||||
*/
|
||||
public String getApplyPrefix() {
|
||||
return applyPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the apply prefix. This might be set to "V" for use with FlywayDB.
|
||||
*/
|
||||
public void setApplyPrefix(String applyPrefix) {
|
||||
this.applyPrefix = applyPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the table name that holds the migration run details
|
||||
* (used by DB Migration runner only).
|
||||
*/
|
||||
public String getMetaTable() {
|
||||
return metaTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the table name that holds the migration run details
|
||||
* (used by DB Migration runner only).
|
||||
*/
|
||||
public void setMetaTable(String metaTable) {
|
||||
this.metaTable = metaTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a comma and equals delimited placeholders that are substituted in SQL scripts when running migration
|
||||
* (used by DB Migration runner only).
|
||||
*/
|
||||
public String getRunPlaceholders() {
|
||||
// environment properties take precedence
|
||||
String placeholders = readEnvironment("ddl.migration.placeholders");
|
||||
if (placeholders != null) {
|
||||
return placeholders;
|
||||
}
|
||||
return runPlaceholders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a comma and equals delimited placeholders that are substituted in SQL scripts when running migration
|
||||
* (used by DB Migration runner only).
|
||||
*/
|
||||
public void setRunPlaceholders(String runPlaceholders) {
|
||||
this.runPlaceholders = runPlaceholders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a map of placeholder values that are substituted in SQL scripts when running migration
|
||||
* (used by DB Migration runner only).
|
||||
*/
|
||||
public Map<String, String> getRunPlaceholderMap() {
|
||||
return runPlaceholderMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a map of placeholder values that are substituted when running migration
|
||||
* (used by DB Migration runner only).
|
||||
*/
|
||||
public void setRunPlaceholderMap(Map<String, String> runPlaceholderMap) {
|
||||
this.runPlaceholderMap = runPlaceholderMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the DB migration should be run on startup.
|
||||
*/
|
||||
public boolean isRunMigration() {
|
||||
// environment properties take precedence
|
||||
String run = readEnvironment("ddl.migration.run");
|
||||
if (run != null) {
|
||||
return "true".equalsIgnoreCase(run.trim());
|
||||
}
|
||||
return runMigration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true to run the DB migration on startup.
|
||||
*/
|
||||
public void setRunMigration(boolean runMigration) {
|
||||
this.runMigration = runMigration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DB username to use for running DB migrations.
|
||||
*/
|
||||
public String getDbUsername() {
|
||||
// environment properties take precedence
|
||||
String user = readEnvironment("ddl.migration.user");
|
||||
if (user != null) {
|
||||
return user;
|
||||
}
|
||||
return dbUsername;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the DB username to use for running DB migrations.
|
||||
*/
|
||||
public void setDbUsername(String dbUsername) {
|
||||
this.dbUsername = dbUsername;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DB password to use for running DB migrations.
|
||||
*/
|
||||
public String getDbPassword() {
|
||||
String user = readEnvironment("ddl.migration.password");
|
||||
if (user != null) {
|
||||
return user;
|
||||
}
|
||||
return dbPassword;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the DB password to use for running DB migrations.
|
||||
*/
|
||||
public void setDbPassword(String dbPassword) {
|
||||
this.dbPassword = dbPassword;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DB schema to use (for migration, testing etc).
|
||||
*/
|
||||
public String getDbSchema() {
|
||||
String schema = readEnvironment("ddl.migration.schema");
|
||||
if (schema != null) {
|
||||
return schema;
|
||||
}
|
||||
return dbSchema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Db schema to use.
|
||||
*/
|
||||
public void setDbSchema(String dbSchema) {
|
||||
this.dbSchema = dbSchema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Db schema if it hasn't already been defined.
|
||||
*/
|
||||
public void setDefaultDbSchema(String dbSchema) {
|
||||
this.defaultDbSchema = true;
|
||||
this.dbSchema = dbSchema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is considered the default DB schema (Postgres schema matching DB username).
|
||||
*/
|
||||
public boolean isDefaultDbSchema() {
|
||||
return defaultDbSchema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return migration versions that should be added to history without running.
|
||||
*/
|
||||
public String getPatchInsertOn() {
|
||||
return patchInsertOn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set migration versions that should be added to history without running.
|
||||
* <p>
|
||||
* Value can be a string containing comma delimited list of version numbers.
|
||||
* </p>
|
||||
*/
|
||||
public void setPatchInsertOn(String patchInsertOn) {
|
||||
this.patchInsertOn = patchInsertOn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return migration versions that should have their checksum reset and not run.
|
||||
*/
|
||||
public String getPatchResetChecksumOn() {
|
||||
return patchResetChecksumOn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a DDL header prepend for each DDL. E.g. for copyright headers
|
||||
* You can use placeholders like ${version} or ${timestamp} in properties file.
|
||||
*/
|
||||
public String getDdlHeader() {
|
||||
if (ddlHeader != null && !ddlHeader.isEmpty()) {
|
||||
ddlHeader = replace(ddlHeader, "${version}", EbeanVersion.getVersion());
|
||||
ddlHeader = replace(ddlHeader, "${timestamp}", ZonedDateTime.now().format( DateTimeFormatter.ISO_INSTANT ));
|
||||
}
|
||||
return ddlHeader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the header prepended to the DDL.
|
||||
*/
|
||||
public void setDdlHeader(String ddlHeader) {
|
||||
this.ddlHeader = ddlHeader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set migration versions that should have their checksum reset and not run.
|
||||
* <p>
|
||||
* Value can be a string containing comma delimited list of version numbers.
|
||||
* </p>
|
||||
*/
|
||||
public void setPatchResetChecksumOn(String patchResetChecksumOn) {
|
||||
this.patchResetChecksumOn = patchResetChecksumOn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if strict mode is used which includes a check that non-null columns have a default value.
|
||||
*/
|
||||
public boolean isStrictMode() {
|
||||
String envValue = readEnvironment("ddl.migration.strictMode");
|
||||
if (!isEmpty(envValue)) {
|
||||
return Boolean.parseBoolean(envValue.trim());
|
||||
}
|
||||
return strictMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to false to turn off strict mode allowing non-null columns to not have a default value.
|
||||
*/
|
||||
public void setStrictMode(boolean strictMode) {
|
||||
this.strictMode = strictMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the underlying migration runner configuration allowing for more advanced settings.
|
||||
*/
|
||||
public MigrationConfig getRunnerConfig() {
|
||||
return runnerConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the settings from the PropertiesWrapper.
|
||||
*/
|
||||
public void loadSettings(PropertiesWrapper properties, String serverName) {
|
||||
|
||||
migrationPath = properties.get("migration.migrationPath", migrationPath);
|
||||
migrationInitPath = properties.get("migration.migrationInitPath", migrationInitPath);
|
||||
modelPath = properties.get("migration.modelPath", modelPath);
|
||||
applyPrefix = properties.get("migration.applyPrefix", applyPrefix);
|
||||
applySuffix = properties.get("migration.applySuffix", applySuffix);
|
||||
modelSuffix = properties.get("migration.modelSuffix", modelSuffix);
|
||||
|
||||
platform = properties.getEnum(Platform.class, "migration.platform", platform);
|
||||
patchInsertOn = properties.get("migration.patchInsertOn", patchInsertOn);
|
||||
patchResetChecksumOn = properties.get("migration.patchResetChecksumOn", patchResetChecksumOn);
|
||||
|
||||
runMigration = properties.getBoolean("migration.run", runMigration);
|
||||
metaTable = properties.get("migration.metaTable", metaTable);
|
||||
runPlaceholders = properties.get("migration.placeholders", runPlaceholders);
|
||||
dbSchema = properties.get("migration.dbSchema", dbSchema);
|
||||
|
||||
//Do not set user and pass from "datasource.db.username"
|
||||
//There is a null test in MigrationRunner::getConnection to handle this
|
||||
//String adminUser = properties.get("datasource." + serverName + ".username", dbUsername);
|
||||
String adminUser = properties.get("datasource." + serverName + ".adminusername", dbUsername);
|
||||
dbUsername = properties.get("migration.dbusername", adminUser);
|
||||
|
||||
//String adminPwd = properties.get("datasource." + serverName + ".password", dbPassword);
|
||||
String adminPwd = properties.get("datasource." + serverName + ".adminpassword", dbPassword);
|
||||
dbPassword = properties.get("migration.dbpassword", adminPwd);
|
||||
ddlHeader = properties.get("ddl.header", ddlHeader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the system or environment property.
|
||||
*/
|
||||
protected String readEnvironment(String key) {
|
||||
|
||||
String val = System.getProperty(key);
|
||||
if (val == null) {
|
||||
val = System.getenv(key);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the string is null or empty.
|
||||
*/
|
||||
protected boolean isEmpty(String val) {
|
||||
return val == null || val.trim().isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the MigrationRunner to run migrations if necessary.
|
||||
*/
|
||||
public MigrationRunner createRunner(ClassLoader classLoader, Properties properties) {
|
||||
|
||||
runnerConfig.setMetaTable(metaTable);
|
||||
runnerConfig.setApplySuffix(applySuffix);
|
||||
runnerConfig.setMigrationPath(migrationPath);
|
||||
runnerConfig.setMigrationInitPath(migrationInitPath);
|
||||
runnerConfig.setRunPlaceholderMap(runPlaceholderMap);
|
||||
runnerConfig.setRunPlaceholders(runPlaceholders);
|
||||
runnerConfig.setDbUsername(getDbUsername());
|
||||
runnerConfig.setDbPassword(getDbPassword());
|
||||
runnerConfig.setDbSchema(getDbSchema());
|
||||
if (defaultDbSchema) {
|
||||
runnerConfig.setSetCurrentSchema(false);
|
||||
}
|
||||
runnerConfig.setClassLoader(classLoader);
|
||||
if (patchInsertOn != null) {
|
||||
runnerConfig.setPatchInsertOn(patchInsertOn);
|
||||
}
|
||||
if (patchResetChecksumOn != null) {
|
||||
runnerConfig.setPatchResetChecksumOn(patchResetChecksumOn);
|
||||
}
|
||||
if (properties != null) {
|
||||
runnerConfig.load(properties);
|
||||
}
|
||||
return new MigrationRunner(runnerConfig);
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,11 @@ public class PlatformConfig {
|
||||
|
||||
private boolean allQuotedIdentifiers;
|
||||
|
||||
/**
|
||||
* Set this to true for Postgres FOR UPDATE to use NO KEY option.
|
||||
*/
|
||||
private boolean forUpdateNoKey;
|
||||
|
||||
private DbConstraintNaming constraintNaming;
|
||||
|
||||
/**
|
||||
@@ -77,6 +82,7 @@ public class PlatformConfig {
|
||||
* Construct based on given config - typically for DbMigration generation with many platforms.
|
||||
*/
|
||||
public PlatformConfig(PlatformConfig platformConfig) {
|
||||
this.forUpdateNoKey = platformConfig.forUpdateNoKey;
|
||||
this.databaseBooleanFalse = platformConfig.databaseBooleanFalse;
|
||||
this.databaseBooleanTrue = platformConfig.databaseBooleanTrue;
|
||||
this.databaseSequenceBatchSize = platformConfig.databaseSequenceBatchSize;
|
||||
@@ -133,14 +139,26 @@ public class PlatformConfig {
|
||||
this.caseSensitiveCollation = caseSensitiveCollation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if Postgres FOR UPDATE should use the NO KEY option.
|
||||
*/
|
||||
public boolean isForUpdateNoKey() {
|
||||
return forUpdateNoKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true such that Postgres FOR UPDATE should use the NO KEY option.
|
||||
*/
|
||||
public void setForUpdateNoKey(boolean forUpdateNoKey) {
|
||||
this.forUpdateNoKey = forUpdateNoKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a value used to represent TRUE in the database.
|
||||
* <p>
|
||||
* This is used for databases that do not support boolean natively.
|
||||
* </p>
|
||||
* <p>
|
||||
* The value returned is either a Integer or a String (e.g. "1", or "T").
|
||||
* </p>
|
||||
*/
|
||||
public String getDatabaseBooleanTrue() {
|
||||
return databaseBooleanTrue;
|
||||
@@ -150,10 +168,8 @@ public class PlatformConfig {
|
||||
* Set the value to represent TRUE in the database.
|
||||
* <p>
|
||||
* This is used for databases that do not support boolean natively.
|
||||
* </p>
|
||||
* <p>
|
||||
* The value set is either a Integer or a String (e.g. "1", or "T").
|
||||
* </p>
|
||||
*/
|
||||
public void setDatabaseBooleanTrue(String databaseBooleanTrue) {
|
||||
this.databaseBooleanTrue = databaseBooleanTrue;
|
||||
@@ -245,7 +261,6 @@ public class PlatformConfig {
|
||||
|
||||
/**
|
||||
* Add a custom type mapping.
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // set the default mapping for BigDecimal.class/decimal
|
||||
@@ -266,7 +281,6 @@ public class PlatformConfig {
|
||||
|
||||
/**
|
||||
* Add a custom type mapping that applies to all platforms.
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // set the default mapping for BigDecimal/decimal
|
||||
@@ -294,6 +308,7 @@ public class PlatformConfig {
|
||||
public void loadSettings(PropertiesWrapper p) {
|
||||
|
||||
idType = p.getEnum(IdType.class, "idType", idType);
|
||||
forUpdateNoKey = p.getBoolean("forUpdateNoKey", forUpdateNoKey);
|
||||
databaseSequenceBatchSize = p.getInt("databaseSequenceBatchSize", databaseSequenceBatchSize);
|
||||
databaseBooleanTrue = p.get("databaseBooleanTrue", databaseBooleanTrue);
|
||||
databaseBooleanFalse = p.get("databaseBooleanFalse", databaseBooleanFalse);
|
||||
@@ -334,7 +349,6 @@ public class PlatformConfig {
|
||||
*/
|
||||
public enum DbUuid {
|
||||
|
||||
|
||||
/**
|
||||
* Store using native UUID in H2 and Postgres and otherwise fallback to VARCHAR(40).
|
||||
*/
|
||||
|
||||
@@ -1,47 +1,6 @@
|
||||
package io.ebean.config;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonFactory;
|
||||
import io.avaje.config.Config;
|
||||
import io.ebean.DatabaseFactory;
|
||||
import io.ebean.PersistenceContextScope;
|
||||
import io.ebean.Query;
|
||||
import io.ebean.Transaction;
|
||||
import io.ebean.annotation.Encrypted;
|
||||
import io.ebean.annotation.PersistBatch;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.cache.ServerCachePlugin;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
import io.ebean.config.dbplatform.DbEncrypt;
|
||||
import io.ebean.config.dbplatform.DbType;
|
||||
import io.ebean.config.dbplatform.IdType;
|
||||
import io.ebean.datasource.DataSourceConfig;
|
||||
import io.ebean.event.BeanFindController;
|
||||
import io.ebean.event.BeanPersistController;
|
||||
import io.ebean.event.BeanPersistListener;
|
||||
import io.ebean.event.BeanPostConstructListener;
|
||||
import io.ebean.event.BeanPostLoad;
|
||||
import io.ebean.event.BeanQueryAdapter;
|
||||
import io.ebean.event.BulkTableEventListener;
|
||||
import io.ebean.event.ServerConfigStartup;
|
||||
import io.ebean.event.changelog.ChangeLogListener;
|
||||
import io.ebean.event.changelog.ChangeLogPrepare;
|
||||
import io.ebean.event.changelog.ChangeLogRegister;
|
||||
import io.ebean.event.readaudit.ReadAuditLogger;
|
||||
import io.ebean.event.readaudit.ReadAuditPrepare;
|
||||
import io.ebean.migration.MigrationRunner;
|
||||
import io.ebean.util.StringHelper;
|
||||
|
||||
import javax.persistence.EnumType;
|
||||
import javax.sql.DataSource;
|
||||
import java.time.Clock;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.ServiceLoader;
|
||||
|
||||
/**
|
||||
* Deprecated - please migrate to <code>io.ebean.DatabaseConfig</code>.
|
||||
|
||||
@@ -679,21 +679,20 @@ public class DatabasePlatform {
|
||||
|
||||
public String completeSql(String sql, Query<?> query) {
|
||||
if (query.isForUpdate()) {
|
||||
sql = withForUpdate(sql, query.getForUpdateMode());
|
||||
sql = withForUpdate(sql, query.getForUpdateLockWait(), query.getForUpdateLockType());
|
||||
}
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* For update hint on the FROM clause (SQL server only).
|
||||
*/
|
||||
public String fromForUpdate(Query.ForUpdate forUpdateMode) {
|
||||
public String fromForUpdate(Query.LockWait lockWait) {
|
||||
// return null except for sql server
|
||||
return null;
|
||||
}
|
||||
|
||||
protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) {
|
||||
protected String withForUpdate(String sql, Query.LockWait lockWait, Query.LockType lockType) {
|
||||
// silently assume the database does not support the "for update" clause.
|
||||
logger.info("it seems your database does not support the 'for update' clause");
|
||||
return sql;
|
||||
|
||||
@@ -16,6 +16,7 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.NavigableSet;
|
||||
import java.util.TreeSet;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
@@ -42,7 +43,7 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator {
|
||||
|
||||
protected final int allocationSize;
|
||||
|
||||
protected boolean currentlyBackgroundLoading;
|
||||
protected AtomicBoolean currentlyBackgroundLoading = new AtomicBoolean(false);
|
||||
|
||||
/**
|
||||
* Construct given a dataSource and sql to return the next sequence value.
|
||||
@@ -128,27 +129,16 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator {
|
||||
* Load another batch of Id's using a background thread.
|
||||
*/
|
||||
protected void loadInBackground(final int requestSize) {
|
||||
// single threaded processing...
|
||||
loadLock.lock();
|
||||
try {
|
||||
if (currentlyBackgroundLoading) {
|
||||
// skip as already background loading
|
||||
logger.debug("... skip background sequence load (another load in progress)");
|
||||
return;
|
||||
}
|
||||
currentlyBackgroundLoading = true;
|
||||
backgroundExecutor.execute(() -> {
|
||||
loadMore(requestSize);
|
||||
loadLock.lock();
|
||||
try {
|
||||
currentlyBackgroundLoading = false;
|
||||
} finally {
|
||||
loadLock.unlock();
|
||||
}
|
||||
});
|
||||
} finally {
|
||||
loadLock.lock();
|
||||
if (currentlyBackgroundLoading.get()) {
|
||||
// skip as already background loading
|
||||
logger.debug("... skip background sequence load (another load in progress)");
|
||||
return;
|
||||
}
|
||||
currentlyBackgroundLoading.set(true);
|
||||
backgroundExecutor.execute(() -> {
|
||||
loadMore(requestSize);
|
||||
currentlyBackgroundLoading.set(false);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -51,7 +51,7 @@ public class H2Platform extends DatabasePlatform {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) {
|
||||
protected String withForUpdate(String sql, Query.LockWait lockWait, Query.LockType lockType) {
|
||||
// NOWAIT and SKIP LOCKED currently not supported with H2
|
||||
return sql + " for update";
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.ebean.config.dbplatform.hana;
|
||||
|
||||
import io.ebean.Query.ForUpdate;
|
||||
import io.ebean.Query;
|
||||
import io.ebean.Query.LockWait;
|
||||
import io.ebean.annotation.PersistBatch;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.config.PlatformConfig;
|
||||
@@ -68,16 +69,16 @@ public class HanaPlatform extends DatabasePlatform {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String withForUpdate(String sql, ForUpdate forUpdateMode) {
|
||||
switch (forUpdateMode) {
|
||||
case BASE:
|
||||
protected String withForUpdate(String sql, LockWait lockWait, Query.LockType lockType) {
|
||||
switch (lockWait) {
|
||||
case WAIT:
|
||||
return sql + " for update";
|
||||
case NOWAIT:
|
||||
return sql + " for update nowait";
|
||||
case SKIPLOCKED:
|
||||
return sql + " for update ignore locked";
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown update mode: " + forUpdateMode.name());
|
||||
throw new IllegalArgumentException("Unknown update mode: " + lockWait);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ public abstract class BaseMySqlPlatform extends DatabasePlatform {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) {
|
||||
protected String withForUpdate(String sql, Query.LockWait lockWait, Query.LockType lockType) {
|
||||
// NOWAIT and SKIP LOCKED currently not supported with MySQL
|
||||
return sql + " for update";
|
||||
}
|
||||
|
||||
@@ -48,8 +48,8 @@ public class NuoDbPlatform extends DatabasePlatform {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) {
|
||||
switch (forUpdateMode) {
|
||||
protected String withForUpdate(String sql, Query.LockWait lockWait, Query.LockType lockType) {
|
||||
switch (lockWait) {
|
||||
case NOWAIT:
|
||||
return sql + " for update nowait";
|
||||
case SKIPLOCKED:
|
||||
|
||||
@@ -79,8 +79,8 @@ public class OraclePlatform extends DatabasePlatform {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) {
|
||||
switch (forUpdateMode) {
|
||||
protected String withForUpdate(String sql, Query.LockWait lockWait, Query.LockType lockType) {
|
||||
switch (lockWait) {
|
||||
case SKIPLOCKED:
|
||||
return sql + " for update skip locked";
|
||||
case NOWAIT:
|
||||
|
||||
@@ -4,6 +4,7 @@ import io.ebean.BackgroundExecutor;
|
||||
import io.ebean.Query;
|
||||
import io.ebean.annotation.PartitionMode;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.config.PlatformConfig;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
import io.ebean.config.dbplatform.DbPlatformType;
|
||||
import io.ebean.config.dbplatform.DbType;
|
||||
@@ -25,6 +26,15 @@ import java.sql.Types;
|
||||
*/
|
||||
public class PostgresPlatform extends DatabasePlatform {
|
||||
|
||||
private static final String SKIP_LOCKED = " skip locked";
|
||||
private static final String NO_WAIT = " nowait";
|
||||
private static final String FOR_UPDATE = " for update";
|
||||
private static final String FOR_NO_KEY_UPDATE = " for no key update";
|
||||
private static final String FOR_SHARE = " for share";
|
||||
private static final String FOR_KEY_SHARE = " for key share";
|
||||
|
||||
private boolean forUpdateNoKey;
|
||||
|
||||
public PostgresPlatform() {
|
||||
super();
|
||||
this.platform = Platform.POSTGRES;
|
||||
@@ -81,6 +91,12 @@ public class PostgresPlatform extends DatabasePlatform {
|
||||
dbTypeMap.put(DbType.LONGVARCHAR, dbTypeText);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(PlatformConfig config) {
|
||||
super.configure(config);
|
||||
forUpdateNoKey = config.isForUpdateNoKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addGeoTypes(int srid) {
|
||||
dbTypeMap.put(DbType.POINT, geoType("point", srid));
|
||||
@@ -108,22 +124,32 @@ public class PostgresPlatform extends DatabasePlatform {
|
||||
*/
|
||||
@Override
|
||||
public PlatformIdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds, int stepSize, String seqName) {
|
||||
|
||||
return new PostgresSequenceIdGenerator(be, ds, seqName, sequenceBatchSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) {
|
||||
switch (forUpdateMode) {
|
||||
protected String withForUpdate(String sql, Query.LockWait lockWait, Query.LockType lockType) {
|
||||
switch (lockWait) {
|
||||
case SKIPLOCKED:
|
||||
return sql + " for update skip locked";
|
||||
return sql + lock(lockType) + SKIP_LOCKED;
|
||||
case NOWAIT:
|
||||
return sql + " for update nowait";
|
||||
return sql + lock(lockType) + NO_WAIT;
|
||||
default:
|
||||
return sql + " for update";
|
||||
return sql + lock(lockType);
|
||||
}
|
||||
}
|
||||
|
||||
private String lock(Query.LockType lockType) {
|
||||
switch (lockType) {
|
||||
case UPDATE: return FOR_UPDATE;
|
||||
case NO_KEY_UPDATE: return FOR_NO_KEY_UPDATE;
|
||||
case SHARE: return FOR_SHARE;
|
||||
case KEY_SHARE: return FOR_KEY_SHARE;
|
||||
case DEFAULT: return forUpdateNoKey ? FOR_NO_KEY_UPDATE : FOR_UPDATE;
|
||||
}
|
||||
return FOR_UPDATE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tablePartitionsExist(Connection connection, String table) throws SQLException {
|
||||
try (PreparedStatement statement = connection.prepareStatement("select count(*) from pg_inherits i WHERE i.inhparent = ?::regclass")) {
|
||||
|
||||
+3
-3
@@ -105,8 +105,8 @@ abstract class SqlServerBasePlatform extends DatabasePlatform {
|
||||
* For update is part of the FROM clause on the base table for sql server.
|
||||
*/
|
||||
@Override
|
||||
public String fromForUpdate(Query.ForUpdate forUpdateMode) {
|
||||
switch (forUpdateMode) {
|
||||
public String fromForUpdate(Query.LockWait lockWait) {
|
||||
switch (lockWait) {
|
||||
case SKIPLOCKED:
|
||||
return "with (updlock,readpast)";
|
||||
case NOWAIT:
|
||||
@@ -117,7 +117,7 @@ abstract class SqlServerBasePlatform extends DatabasePlatform {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) {
|
||||
protected String withForUpdate(String sql, Query.LockWait lockWait, Query.LockType lockType) {
|
||||
// for update are hints on from clause of base table
|
||||
return sql;
|
||||
}
|
||||
|
||||
@@ -2,11 +2,11 @@ package io.ebean.plugin;
|
||||
|
||||
import io.ebean.Query;
|
||||
import io.ebean.config.dbplatform.IdType;
|
||||
import io.ebean.docstore.DocMapping;
|
||||
import io.ebean.event.BeanFindController;
|
||||
import io.ebean.event.BeanPersistController;
|
||||
import io.ebean.event.BeanPersistListener;
|
||||
import io.ebean.event.BeanQueryAdapter;
|
||||
import io.ebean.docstore.DocMapping;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.Collection;
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
package io.ebean.plugin;
|
||||
|
||||
import io.ebean.EbeanServer;
|
||||
import io.ebean.Database;
|
||||
import io.ebean.bean.BeanLoader;
|
||||
import io.ebean.bean.EntityBeanIntercept;
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Extensions to Database API made available to plugins.
|
||||
*/
|
||||
public interface SpiServer extends EbeanServer {
|
||||
public interface SpiServer extends Database {
|
||||
|
||||
/**
|
||||
* Return the DatabaseConfig.
|
||||
@@ -44,16 +43,6 @@ public interface SpiServer extends EbeanServer {
|
||||
*/
|
||||
BeanType<?> getBeanTypeForQueueId(String queueId);
|
||||
|
||||
/**
|
||||
* Return the associated DataSource for this Database instance.
|
||||
*/
|
||||
DataSource getDataSource();
|
||||
|
||||
/**
|
||||
* Return the associated read only DataSource for this Database instance (can be null).
|
||||
*/
|
||||
DataSource getReadOnlyDataSource();
|
||||
|
||||
/**
|
||||
* Return a BeanLoader.
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package io.ebean.text.json;
|
||||
|
||||
import io.ebean.bean.PersistenceContext;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import io.ebean.bean.PersistenceContext;
|
||||
|
||||
/**
|
||||
* Provides a JSON reader that can hold a persistence context and load context while reading JSON.
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package io.ebean.text.json;
|
||||
|
||||
import io.ebean.FetchPath;
|
||||
import io.ebean.plugin.BeanType;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import io.ebean.FetchPath;
|
||||
import io.ebean.plugin.BeanType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
|
||||
+19
-12
@@ -1,32 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<!-- <parent>-->
|
||||
<!-- <artifactId>ebean-parent</artifactId>-->
|
||||
<!-- <groupId>io.ebean</groupId>-->
|
||||
<!-- <version>12.5.2-SNAPSHOT</version>-->
|
||||
<!-- </parent>-->
|
||||
<parent>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>java8-oss</artifactId>
|
||||
<version>2.2</version>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.6.1</version>
|
||||
</parent>
|
||||
<!-- <parent>-->
|
||||
<!-- <groupId>org.avaje</groupId>-->
|
||||
<!-- <artifactId>java8-oss</artifactId>-->
|
||||
<!-- <version>2.2</version>-->
|
||||
<!-- </parent>-->
|
||||
|
||||
<scm>
|
||||
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
|
||||
<tag>HEAD</tag>
|
||||
<tag>ebean-parent-12.6.1</tag>
|
||||
</scm>
|
||||
|
||||
<name>ebean autotune</name>
|
||||
<description>ebean automatic query tuning module</description>
|
||||
<artifactId>ebean-autotune</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.5.2-SNAPSHOT</version>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>12.5.1</version>
|
||||
<version>12.6.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -38,6 +38,13 @@
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-datasource</artifactId>
|
||||
<version>${ebean-datasource.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje.composite</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
|
||||
+58
-15
@@ -4,15 +4,22 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.5.2-SNAPSHOT</version>
|
||||
<version>12.6.1</version>
|
||||
</parent>
|
||||
|
||||
<name>ebean bom</name>
|
||||
<description>ebean bill of materials pom</description>
|
||||
<artifactId>ebean-bom</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<properties>
|
||||
<ebean-agent.version>12.5.0</ebean-agent.version>
|
||||
<ebean-maven-plugin.version>12.5.0</ebean-maven-plugin.version>
|
||||
<ebean-ddl-runner.version>1.0</ebean-ddl-runner.version>
|
||||
<ebean-migration-auto.version>1.0</ebean-migration-auto.version>
|
||||
<ebean-migration.version>12.2.0</ebean-migration.version>
|
||||
<ebean-test-docker.version>4.0</ebean-test-docker.version>
|
||||
<ebean-datasource.version>7.0</ebean-datasource.version>
|
||||
<ebean-agent.version>12.6.0</ebean-agent.version>
|
||||
<ebean-maven-plugin.version>12.6.0</ebean-maven-plugin.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
@@ -21,6 +28,36 @@
|
||||
|
||||
<!-- dependencies external to this ebean.git build -->
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-ddl-runner</artifactId>
|
||||
<version>${ebean-ddl-runner.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-migration-auto</artifactId>
|
||||
<version>${ebean-migration-auto.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-migration</artifactId>
|
||||
<version>${ebean-migration.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-datasource-api</artifactId>
|
||||
<version>${ebean-datasource.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-datasource</artifactId>
|
||||
<version>${ebean-datasource.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-agent</artifactId>
|
||||
@@ -33,74 +70,80 @@
|
||||
<version>${ebean-maven-plugin.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-test-docker</artifactId>
|
||||
<version>${ebean-test-docker.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- modules -->
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<version>12.6.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<version>12.6.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<version>12.6.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-ddlgen</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<artifactId>ebean-ddl-generator</artifactId>
|
||||
<version>12.6.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-externalmapping-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<version>12.6.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-externalmapping-xml</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<version>12.6.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-autotune</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<version>12.6.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<version>12.6.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>querybean-generator</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<version>12.6.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>kotlin-querybean-generator</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<version>12.6.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-test</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<version>12.6.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.6.1</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>ebean-core-type</artifactId>
|
||||
|
||||
<properties>
|
||||
<jackson-core.version>2.11.3</jackson-core.version>
|
||||
<jackson-databind.version>2.11.3</jackson-databind.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>12.6.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<version>${jackson-core.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,166 @@
|
||||
package io.ebean.core.type;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Time;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Data binder for ScalarTypes generally to an underlying PreparedStatement.
|
||||
*/
|
||||
public interface DataBinder {
|
||||
|
||||
/**
|
||||
* Add something to the binding log.
|
||||
*/
|
||||
StringBuilder append(Object entry);
|
||||
|
||||
/**
|
||||
* Return the binding log.
|
||||
*/
|
||||
StringBuilder log();
|
||||
|
||||
/**
|
||||
* Close the underlying prepared statement.
|
||||
*/
|
||||
void close() throws SQLException;
|
||||
|
||||
/**
|
||||
* Return the current position. Effectively column binding position.
|
||||
*/
|
||||
int currentPos();
|
||||
|
||||
/**
|
||||
* Return the next position.
|
||||
*/
|
||||
int nextPos();
|
||||
|
||||
/**
|
||||
* Decrement the position.
|
||||
*/
|
||||
void decrementPos();
|
||||
|
||||
/**
|
||||
* Execute as a dml statement.
|
||||
*/
|
||||
int executeUpdate() throws SQLException;
|
||||
|
||||
/**
|
||||
* Return the underlying PreparedStatement.
|
||||
*/
|
||||
PreparedStatement getPstmt();
|
||||
|
||||
/**
|
||||
* Return any inputStreams that have been bound (and should be closed).
|
||||
* This is used for batched statement execution only.
|
||||
*/
|
||||
List<InputStream> getInputStreams();
|
||||
|
||||
/**
|
||||
* Bind an object.
|
||||
*/
|
||||
void setObject(Object value) throws SQLException;
|
||||
|
||||
/**
|
||||
* Bind an object with given sql type.
|
||||
*/
|
||||
void setObject(Object value, int sqlType) throws SQLException;
|
||||
|
||||
/**
|
||||
* Bind null.
|
||||
*/
|
||||
void setNull(int jdbcType) throws SQLException;
|
||||
|
||||
/**
|
||||
* Bind a string value.
|
||||
*/
|
||||
void setString(String value) throws SQLException;
|
||||
|
||||
/**
|
||||
* Bind a int value.
|
||||
*/
|
||||
void setInt(int value) throws SQLException;
|
||||
|
||||
/**
|
||||
* Bind a long value.
|
||||
*/
|
||||
void setLong(long value) throws SQLException;
|
||||
|
||||
/**
|
||||
* Bind a short value.
|
||||
*/
|
||||
void setShort(short value) throws SQLException;
|
||||
|
||||
/**
|
||||
* Bind a float value.
|
||||
*/
|
||||
void setFloat(float value) throws SQLException;
|
||||
|
||||
/**
|
||||
* Bind a double value.
|
||||
*/
|
||||
void setDouble(double value) throws SQLException;
|
||||
|
||||
/**
|
||||
* Bind a BigDecimal value.
|
||||
*/
|
||||
void setBigDecimal(BigDecimal value) throws SQLException;
|
||||
|
||||
/**
|
||||
* Bind a date value.
|
||||
*/
|
||||
void setDate(java.sql.Date value) throws SQLException;
|
||||
|
||||
/**
|
||||
* Bind a timestamp value.
|
||||
*/
|
||||
void setTimestamp(Timestamp value) throws SQLException;
|
||||
|
||||
/**
|
||||
* Bind a time value.
|
||||
*/
|
||||
void setTime(Time value) throws SQLException;
|
||||
|
||||
/**
|
||||
* Bind a boolean value.
|
||||
*/
|
||||
void setBoolean(boolean value) throws SQLException;
|
||||
|
||||
/**
|
||||
* Bind a byte array value.
|
||||
*/
|
||||
void setBytes(byte[] value) throws SQLException;
|
||||
|
||||
/**
|
||||
* Bind a byte value.
|
||||
*/
|
||||
void setByte(byte value) throws SQLException;
|
||||
|
||||
/**
|
||||
* Bind a char value.
|
||||
*/
|
||||
void setChar(char value) throws SQLException;
|
||||
|
||||
/**
|
||||
* Bind a InputStream value.
|
||||
*/
|
||||
void setBinaryStream(InputStream inputStream, long length) throws SQLException;
|
||||
|
||||
/**
|
||||
* Bind a byte array value.
|
||||
*/
|
||||
void setBlob(byte[] bytes) throws SQLException;
|
||||
|
||||
/**
|
||||
* Bind a string clob value.
|
||||
*/
|
||||
void setClob(String content) throws SQLException;
|
||||
|
||||
/**
|
||||
* Bind an array value.
|
||||
*/
|
||||
void setArray(String arrayType, Object[] elements) throws SQLException;
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package io.ebeaninternal.server.type;
|
||||
package io.ebean.core.type;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.math.BigDecimal;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package io.ebeanservice.docstore.api.mapping;
|
||||
package io.ebean.core.type;
|
||||
|
||||
/**
|
||||
* Types as defined for document store property types.
|
||||
+1
-2
@@ -1,7 +1,6 @@
|
||||
package io.ebeaninternal.api;
|
||||
package io.ebean.core.type;
|
||||
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
package io.ebeaninternal.server.type;
|
||||
package io.ebean.core.type;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
@@ -10,6 +10,6 @@ public interface ScalarDataReader<T> {
|
||||
/**
|
||||
* Read and return the appropriate value from the dataReader.
|
||||
*/
|
||||
T read(DataReader dataReader) throws SQLException;
|
||||
T read(DataReader reader) throws SQLException;
|
||||
|
||||
}
|
||||
+2
-3
@@ -1,10 +1,9 @@
|
||||
package io.ebeaninternal.server.type;
|
||||
package io.ebean.core.type;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import io.ebean.text.StringFormatter;
|
||||
import io.ebean.text.StringParser;
|
||||
import io.ebeanservice.docstore.api.mapping.DocPropertyType;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
@@ -112,7 +111,7 @@ public interface ScalarType<T> extends StringParser, StringFormatter, ScalarData
|
||||
* JDBC type.
|
||||
* </p>
|
||||
*/
|
||||
void bind(DataBind bind, T value) throws SQLException;
|
||||
void bind(DataBinder binder, T value) throws SQLException;
|
||||
|
||||
/**
|
||||
* Convert the value as necessary to the JDBC type.
|
||||
+52
-12
@@ -3,18 +3,19 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.5.2-SNAPSHOT</version>
|
||||
<version>12.6.1</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>ebean-core</name>
|
||||
<url>http://ebean-orm.github.io/</url>
|
||||
<name>ebean core</name>
|
||||
<description>ebean core module</description>
|
||||
<url>https://ebean.io/</url>
|
||||
|
||||
<scm>
|
||||
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
|
||||
<tag>HEAD</tag>
|
||||
<tag>ebean-parent-12.6.1</tag>
|
||||
</scm>
|
||||
|
||||
<properties>
|
||||
@@ -47,14 +48,40 @@
|
||||
</profiles>
|
||||
<dependencies>
|
||||
|
||||
<!-- keep testing in core using ebean-ddlgen -->
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-ddlgen</artifactId>
|
||||
<version>12.5.0</version>
|
||||
<artifactId>ebean-ddl-runner</artifactId>
|
||||
<version>1.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.avaje</groupId>
|
||||
<artifactId>classpath-scanner</artifactId>
|
||||
<version>4.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-migration-auto</artifactId>
|
||||
<version>1.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- keep testing in core using ebean-ddl-generator & ebean-migration -->
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-migration</artifactId>
|
||||
<version>12.2.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- test scope for supporting ebean-ddlgen -->
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-ddl-generator</artifactId>
|
||||
<version>12.6.1.PreRelease.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- test scope for supporting ebean-ddl-generator -->
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jaxb</groupId>
|
||||
<artifactId>jaxb-runtime</artifactId>
|
||||
@@ -65,13 +92,19 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<version>12.6.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core-type</artifactId>
|
||||
<version>12.6.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-externalmapping-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<version>12.6.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -145,6 +178,13 @@
|
||||
|
||||
<!-- Test scope -->
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-datasource</artifactId>
|
||||
<version>${ebean-datasource.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.nuodb.jdbc</groupId>
|
||||
<artifactId>nuodb-jdbc</artifactId>
|
||||
@@ -160,9 +200,9 @@
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean.test</groupId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-test-docker</artifactId>
|
||||
<version>3.1.5</version>
|
||||
<version>4.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package io.ebeaninternal.api;
|
||||
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebeaninternal.server.type.GeoTypeBinder;
|
||||
|
||||
/**
|
||||
* Provider of Geometry type binder support.
|
||||
*/
|
||||
public interface GeoTypeProvider {
|
||||
|
||||
/**
|
||||
* Create a binder for binding geometry types.
|
||||
*/
|
||||
GeoTypeBinder createBinder(DatabaseConfig config);
|
||||
}
|
||||
@@ -237,7 +237,7 @@ public interface SpiQuery<T> extends Query<T>, TxnProfileEventCodes {
|
||||
* Return the ForUpdate mode.
|
||||
*/
|
||||
@Override
|
||||
ForUpdate getForUpdateMode();
|
||||
LockWait getForUpdateLockWait();
|
||||
|
||||
/**
|
||||
* Return the bean descriptor for this query.
|
||||
|
||||
@@ -3,6 +3,7 @@ package io.ebeaninternal.json;
|
||||
import com.fasterxml.jackson.core.JsonFactory;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonToken;
|
||||
import io.ebean.ModifyAwareType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
@@ -145,7 +146,7 @@ class EJsonReader {
|
||||
currentContext = stack.pop(currentContext);
|
||||
}
|
||||
if (modifyAwareOwner != null) {
|
||||
modifyAwareOwner.resetMarkedDirty();
|
||||
modifyAwareOwner.setMarkedDirty(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -296,7 +297,7 @@ class EJsonReader {
|
||||
map = new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
ObjectContext(ModifyAwareOwner owner) {
|
||||
ObjectContext(ModifyAwareType owner) {
|
||||
map = new ModifyAwareMap<>(owner, new LinkedHashMap<>());
|
||||
}
|
||||
|
||||
@@ -334,7 +335,7 @@ class EJsonReader {
|
||||
values = new ArrayList<>();
|
||||
}
|
||||
|
||||
ArrayContext(ModifyAwareOwner owner) {
|
||||
ArrayContext(ModifyAwareType owner) {
|
||||
values = new ModifyAwareList<>(owner, new ArrayList<>());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,28 +1,26 @@
|
||||
package io.ebeaninternal.json;
|
||||
|
||||
import io.ebean.ModifyAwareType;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Detects when content has been modified and as such needs to be persisted (included in an update).
|
||||
*/
|
||||
public class ModifyAwareFlag implements ModifyAwareOwner {
|
||||
public class ModifyAwareFlag implements ModifyAwareType, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1;
|
||||
|
||||
boolean dirty;
|
||||
private boolean markedDirty;
|
||||
|
||||
@Override
|
||||
public boolean isMarkedDirty() {
|
||||
if (!dirty) return false;
|
||||
dirty = false;
|
||||
return true;
|
||||
return markedDirty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markAsModified() {
|
||||
dirty = true;
|
||||
public void setMarkedDirty(boolean markedDirty) {
|
||||
this.markedDirty = markedDirty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetMarkedDirty() {
|
||||
dirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package io.ebeaninternal.json;
|
||||
|
||||
import io.ebean.ModifyAwareType;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
@@ -7,7 +9,7 @@ import java.util.Iterator;
|
||||
*/
|
||||
public class ModifyAwareIterator<E> implements Iterator<E> {
|
||||
|
||||
private final ModifyAwareOwner owner;
|
||||
private final ModifyAwareType owner;
|
||||
|
||||
private final Iterator<E> it;
|
||||
|
||||
@@ -17,7 +19,7 @@ public class ModifyAwareIterator<E> implements Iterator<E> {
|
||||
* The owner is notified of the removals.
|
||||
* </p>
|
||||
*/
|
||||
public ModifyAwareIterator(ModifyAwareOwner owner, Iterator<E> it) {
|
||||
public ModifyAwareIterator(ModifyAwareType owner, Iterator<E> it) {
|
||||
this.owner = owner;
|
||||
this.it = it;
|
||||
}
|
||||
@@ -34,7 +36,7 @@ public class ModifyAwareIterator<E> implements Iterator<E> {
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
owner.markAsModified();
|
||||
owner.setMarkedDirty(true);
|
||||
it.remove();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package io.ebeaninternal.json;
|
||||
|
||||
import io.ebean.ModifyAwareType;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
@@ -10,20 +13,20 @@ import java.util.Objects;
|
||||
/**
|
||||
* Modify aware wrapper of a list.
|
||||
*/
|
||||
public class ModifyAwareList<E> implements List<E>, ModifyAwareOwner {
|
||||
public class ModifyAwareList<E> implements List<E>, ModifyAwareType, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1;
|
||||
|
||||
final List<E> list;
|
||||
|
||||
final ModifyAwareOwner owner;
|
||||
final ModifyAwareType owner;
|
||||
|
||||
public ModifyAwareList(List<E> list) {
|
||||
this.list = list;
|
||||
this.owner = new ModifyAwareFlag();
|
||||
}
|
||||
|
||||
public ModifyAwareList(ModifyAwareOwner owner, List<E> list) {
|
||||
public ModifyAwareList(ModifyAwareType owner, List<E> list) {
|
||||
this.list = list;
|
||||
this.owner = owner;
|
||||
}
|
||||
@@ -56,13 +59,12 @@ public class ModifyAwareList<E> implements List<E>, ModifyAwareOwner {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markAsModified() {
|
||||
owner.markAsModified();
|
||||
public void setMarkedDirty(boolean markedDirty) {
|
||||
owner.setMarkedDirty(markedDirty);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetMarkedDirty() {
|
||||
owner.resetMarkedDirty();
|
||||
private void markAsDirty() {
|
||||
owner.setMarkedDirty(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -98,13 +100,13 @@ public class ModifyAwareList<E> implements List<E>, ModifyAwareOwner {
|
||||
|
||||
@Override
|
||||
public boolean add(E e) {
|
||||
owner.markAsModified();
|
||||
markAsDirty();
|
||||
return list.add(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
owner.markAsModified();
|
||||
markAsDirty();
|
||||
return list.remove(o);
|
||||
}
|
||||
|
||||
@@ -115,31 +117,31 @@ public class ModifyAwareList<E> implements List<E>, ModifyAwareOwner {
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends E> c) {
|
||||
owner.markAsModified();
|
||||
markAsDirty();
|
||||
return list.addAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(int index, Collection<? extends E> c) {
|
||||
owner.markAsModified();
|
||||
markAsDirty();
|
||||
return list.addAll(index, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
owner.markAsModified();
|
||||
markAsDirty();
|
||||
return list.removeAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> c) {
|
||||
owner.markAsModified();
|
||||
markAsDirty();
|
||||
return list.retainAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
owner.markAsModified();
|
||||
markAsDirty();
|
||||
list.clear();
|
||||
}
|
||||
|
||||
@@ -150,19 +152,19 @@ public class ModifyAwareList<E> implements List<E>, ModifyAwareOwner {
|
||||
|
||||
@Override
|
||||
public E set(int index, E element) {
|
||||
owner.markAsModified();
|
||||
markAsDirty();
|
||||
return list.set(index, element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(int index, E element) {
|
||||
owner.markAsModified();
|
||||
markAsDirty();
|
||||
list.add(index, element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public E remove(int index) {
|
||||
owner.markAsModified();
|
||||
markAsDirty();
|
||||
return list.remove(index);
|
||||
}
|
||||
|
||||
@@ -195,7 +197,6 @@ public class ModifyAwareList<E> implements List<E>, ModifyAwareOwner {
|
||||
* Create an return a modify aware Set.
|
||||
*/
|
||||
public ModifyAwareSet<E> asSet() {
|
||||
|
||||
return new ModifyAwareSet<>(owner, new LinkedHashSet<>(list));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package io.ebeaninternal.json;
|
||||
|
||||
import io.ebean.ModifyAwareType;
|
||||
|
||||
import java.util.ListIterator;
|
||||
|
||||
/**
|
||||
@@ -7,11 +9,11 @@ import java.util.ListIterator;
|
||||
*/
|
||||
public class ModifyAwareListIterator<E> implements ListIterator<E> {
|
||||
|
||||
final ModifyAwareOwner owner;
|
||||
final ModifyAwareType owner;
|
||||
|
||||
final ListIterator<E> iterator;
|
||||
|
||||
public ModifyAwareListIterator(ModifyAwareOwner owner, ListIterator<E> iterator) {
|
||||
public ModifyAwareListIterator(ModifyAwareType owner, ListIterator<E> iterator) {
|
||||
this.owner = owner;
|
||||
this.iterator = iterator;
|
||||
}
|
||||
@@ -48,19 +50,19 @@ public class ModifyAwareListIterator<E> implements ListIterator<E> {
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
owner.markAsModified();
|
||||
owner.setMarkedDirty(true);
|
||||
iterator.remove();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(E e) {
|
||||
owner.markAsModified();
|
||||
owner.setMarkedDirty(true);
|
||||
iterator.set(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(E e) {
|
||||
owner.markAsModified();
|
||||
owner.setMarkedDirty(true);
|
||||
iterator.add(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package io.ebeaninternal.json;
|
||||
|
||||
import io.ebean.ModifyAwareType;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
@@ -9,11 +12,11 @@ import java.util.Set;
|
||||
/**
|
||||
* Map that is wraps an underlying map for the purpose of detecting changes.
|
||||
*/
|
||||
public class ModifyAwareMap<K, V> implements Map<K, V>, ModifyAwareOwner {
|
||||
public class ModifyAwareMap<K, V> implements Map<K, V>, ModifyAwareType, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1;
|
||||
|
||||
final ModifyAwareOwner owner;
|
||||
final ModifyAwareType owner;
|
||||
|
||||
/**
|
||||
* The underlying map.
|
||||
@@ -25,7 +28,7 @@ public class ModifyAwareMap<K, V> implements Map<K, V>, ModifyAwareOwner {
|
||||
this.owner = new ModifyAwareFlag();
|
||||
}
|
||||
|
||||
public ModifyAwareMap(ModifyAwareOwner owner, Map<K, V> underlying) {
|
||||
public ModifyAwareMap(ModifyAwareType owner, Map<K, V> underlying) {
|
||||
this.owner = owner;
|
||||
this.map = underlying;
|
||||
}
|
||||
@@ -58,13 +61,12 @@ public class ModifyAwareMap<K, V> implements Map<K, V>, ModifyAwareOwner {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markAsModified() {
|
||||
owner.markAsModified();
|
||||
public void setMarkedDirty(boolean markedDirty) {
|
||||
owner.setMarkedDirty(markedDirty);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetMarkedDirty() {
|
||||
owner.resetMarkedDirty();
|
||||
private void markAsDirty() {
|
||||
owner.setMarkedDirty(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -94,7 +96,7 @@ public class ModifyAwareMap<K, V> implements Map<K, V>, ModifyAwareOwner {
|
||||
|
||||
@Override
|
||||
public V put(K key, V value) {
|
||||
markAsModified();
|
||||
markAsDirty();
|
||||
return map.put(key, value);
|
||||
}
|
||||
|
||||
@@ -102,14 +104,14 @@ public class ModifyAwareMap<K, V> implements Map<K, V>, ModifyAwareOwner {
|
||||
public V remove(Object key) {
|
||||
V value = map.remove(key);
|
||||
if (value != null) {
|
||||
markAsModified();
|
||||
markAsDirty();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends K, ? extends V> m) {
|
||||
markAsModified();
|
||||
markAsDirty();
|
||||
map.putAll(m);
|
||||
}
|
||||
|
||||
@@ -117,7 +119,7 @@ public class ModifyAwareMap<K, V> implements Map<K, V>, ModifyAwareOwner {
|
||||
@Override
|
||||
public void clear() {
|
||||
if (!map.isEmpty()) {
|
||||
markAsModified();
|
||||
markAsDirty();
|
||||
}
|
||||
map.clear();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package io.ebeaninternal.json;
|
||||
|
||||
import io.ebean.ModifyAwareType;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Objects;
|
||||
@@ -8,11 +11,11 @@ import java.util.Set;
|
||||
/**
|
||||
* Wraps a Set for the purposes of detecting modifications.
|
||||
*/
|
||||
public class ModifyAwareSet<E> implements Set<E>, ModifyAwareOwner {
|
||||
public class ModifyAwareSet<E> implements Set<E>, ModifyAwareType, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1;
|
||||
|
||||
protected final ModifyAwareOwner owner;
|
||||
protected final ModifyAwareType owner;
|
||||
|
||||
protected final Set<E> set;
|
||||
|
||||
@@ -26,7 +29,7 @@ public class ModifyAwareSet<E> implements Set<E>, ModifyAwareOwner {
|
||||
/**
|
||||
* Create with an Owner that is notified of modifications.
|
||||
*/
|
||||
public ModifyAwareSet(ModifyAwareOwner owner, Set<E> underlying) {
|
||||
public ModifyAwareSet(ModifyAwareType owner, Set<E> underlying) {
|
||||
this.owner = owner;
|
||||
this.set = underlying;
|
||||
}
|
||||
@@ -37,16 +40,14 @@ public class ModifyAwareSet<E> implements Set<E>, ModifyAwareOwner {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markAsModified() {
|
||||
owner.markAsModified();
|
||||
public void setMarkedDirty(boolean markedDirty) {
|
||||
owner.setMarkedDirty(markedDirty);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetMarkedDirty() {
|
||||
owner.resetMarkedDirty();
|
||||
private void markAsDirty() {
|
||||
owner.setMarkedDirty(true);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return set.toString();
|
||||
@@ -72,7 +73,7 @@ public class ModifyAwareSet<E> implements Set<E>, ModifyAwareOwner {
|
||||
@Override
|
||||
public boolean add(E o) {
|
||||
if (set.add(o)) {
|
||||
owner.markAsModified();
|
||||
markAsDirty();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -83,7 +84,7 @@ public class ModifyAwareSet<E> implements Set<E>, ModifyAwareOwner {
|
||||
boolean changed = false;
|
||||
for (E o : collection) {
|
||||
if (set.add(o)) {
|
||||
owner.markAsModified();
|
||||
markAsDirty();
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
@@ -93,7 +94,7 @@ public class ModifyAwareSet<E> implements Set<E>, ModifyAwareOwner {
|
||||
@Override
|
||||
public void clear() {
|
||||
if (!set.isEmpty()) {
|
||||
owner.markAsModified();
|
||||
markAsDirty();
|
||||
}
|
||||
set.clear();
|
||||
}
|
||||
@@ -121,7 +122,7 @@ public class ModifyAwareSet<E> implements Set<E>, ModifyAwareOwner {
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
if (set.remove(o)) {
|
||||
owner.markAsModified();
|
||||
markAsDirty();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -132,7 +133,7 @@ public class ModifyAwareSet<E> implements Set<E>, ModifyAwareOwner {
|
||||
boolean changed = false;
|
||||
for (Object element : collection) {
|
||||
if (set.remove(element)) {
|
||||
owner.markAsModified();
|
||||
markAsDirty();
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
@@ -147,7 +148,7 @@ public class ModifyAwareSet<E> implements Set<E>, ModifyAwareOwner {
|
||||
Object o = it.next();
|
||||
if (!collection.contains(o)) {
|
||||
it.remove();
|
||||
owner.markAsModified();
|
||||
markAsDirty();
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
|
||||
import io.ebean.ScriptRunner;
|
||||
import io.ebean.migration.ddl.DdlRunner;
|
||||
import io.ebean.migration.runner.ScriptTransform;
|
||||
import io.ebean.ddlrunner.DdlRunner;
|
||||
import io.ebean.ddlrunner.ScriptTransform;
|
||||
import io.ebeaninternal.api.SpiEbeanServer;
|
||||
import io.ebeaninternal.util.UrlHelper;
|
||||
|
||||
@@ -102,7 +102,7 @@ class DScriptRunner implements ScriptRunner {
|
||||
|
||||
private Connection obtainConnection() {
|
||||
try {
|
||||
return server.getPluginApi().getDataSource().getConnection();
|
||||
return server.getDataSource().getConnection();
|
||||
} catch (SQLException e) {
|
||||
throw new PersistenceException("Failed to obtain connection to run script", e);
|
||||
}
|
||||
|
||||
@@ -61,6 +61,7 @@ import io.ebean.meta.MetaQueryPlan;
|
||||
import io.ebean.meta.MetricVisitor;
|
||||
import io.ebean.meta.QueryPlanInit;
|
||||
import io.ebean.meta.QueryPlanRequest;
|
||||
import io.ebean.migration.auto.AutoMigrationRunner;
|
||||
import io.ebean.plugin.BeanType;
|
||||
import io.ebean.plugin.Plugin;
|
||||
import io.ebean.plugin.Property;
|
||||
@@ -397,8 +398,17 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
* Start any services after registering with the ClusterManager.
|
||||
*/
|
||||
public void start() {
|
||||
if (TenantMode.DB != config.getTenantMode()) {
|
||||
config.runDbMigration(config.getDataSource());
|
||||
if (config.isRunMigration() && TenantMode.DB != config.getTenantMode()) {
|
||||
final AutoMigrationRunner migrationRunner = config.service(AutoMigrationRunner.class);
|
||||
if (migrationRunner == null) {
|
||||
throw new IllegalStateException("No AutoMigrationRunner found. Probably ebean-migration is not in the classpath?");
|
||||
}
|
||||
final String dbSchema = config.getDbSchema();
|
||||
if (dbSchema != null) {
|
||||
migrationRunner.setDefaultDbSchema(dbSchema);
|
||||
}
|
||||
migrationRunner.loadProperties(config.getProperties());
|
||||
migrationRunner.run(config.getDataSource());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
|
||||
import io.ebean.core.type.DataReader;
|
||||
import io.ebeaninternal.api.SpiDtoQuery;
|
||||
import io.ebeaninternal.api.SpiEbeanServer;
|
||||
import io.ebeaninternal.api.SpiQuery;
|
||||
@@ -8,7 +9,6 @@ import io.ebeaninternal.server.dto.DtoMappingRequest;
|
||||
import io.ebeaninternal.server.dto.DtoQueryPlan;
|
||||
import io.ebeaninternal.server.persist.Binder;
|
||||
import io.ebeaninternal.server.query.DtoQueryEngine;
|
||||
import io.ebeaninternal.server.type.DataReader;
|
||||
import io.ebeaninternal.server.type.RsetDataReader;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
|
||||
@@ -104,7 +104,6 @@ public abstract class PersistRequest extends BeanRequest implements BatchPostExe
|
||||
return transaction.isLogSummary();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return true if this persist request should use JDBC batch.
|
||||
*/
|
||||
@@ -119,23 +118,22 @@ public abstract class PersistRequest extends BeanRequest implements BatchPostExe
|
||||
return transaction.translate(e.getMessage(), e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the statement.
|
||||
*/
|
||||
int executeStatement() {
|
||||
return executeStatement(false);
|
||||
}
|
||||
|
||||
int executeStatement(boolean addBatch) {
|
||||
boolean batch = isBatchThisRequest();
|
||||
|
||||
try {
|
||||
int rows;
|
||||
BatchControl control = transaction.getBatchControl();
|
||||
if (control != null) {
|
||||
rows = control.executeStatementOrBatch(this, batch);
|
||||
rows = control.executeStatementOrBatch(this, batch, addBatch);
|
||||
|
||||
} else if (batch) {
|
||||
// need to create the BatchControl
|
||||
control = persistExecute.createBatchControl(transaction);
|
||||
rows = control.executeStatementOrBatch(this, true);
|
||||
rows = control.executeStatementOrBatch(this, true, addBatch);
|
||||
} else {
|
||||
rows = executeNow();
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ public final class PersistRequestUpdateSql extends PersistRequest {
|
||||
*/
|
||||
public int addBatch() {
|
||||
this.addBatch = true;
|
||||
return executeOrQueue();
|
||||
return executeStatement(true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,6 +5,7 @@ import io.ebean.annotation.DocStore;
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebean.config.IdGenerator;
|
||||
import io.ebean.config.ScalarTypeConverter;
|
||||
import io.ebean.core.type.ScalarType;
|
||||
import io.ebean.event.BeanFindController;
|
||||
import io.ebean.event.BeanPersistController;
|
||||
import io.ebean.event.BeanPersistListener;
|
||||
@@ -18,7 +19,6 @@ import io.ebean.event.changelog.ChangeLogRegister;
|
||||
import io.ebean.event.readaudit.ReadAuditLogger;
|
||||
import io.ebean.event.readaudit.ReadAuditPrepare;
|
||||
import io.ebean.util.AnnotationUtil;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ package io.ebeaninternal.server.deploy;
|
||||
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.bean.PersistenceContext;
|
||||
import io.ebean.core.type.DataReader;
|
||||
import io.ebeaninternal.server.query.SqlJoinType;
|
||||
import io.ebeaninternal.server.type.DataReader;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package io.ebeaninternal.server.deploy;
|
||||
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebeaninternal.server.type.DataReader;
|
||||
import io.ebean.core.type.DataReader;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@ import io.ebean.config.DatabaseConfig;
|
||||
import io.ebean.config.EncryptKey;
|
||||
import io.ebean.config.dbplatform.IdType;
|
||||
import io.ebean.config.dbplatform.PlatformIdGenerator;
|
||||
import io.ebean.core.type.DocPropertyType;
|
||||
import io.ebean.core.type.ScalarType;
|
||||
import io.ebean.event.BeanFindController;
|
||||
import io.ebean.event.BeanPersistController;
|
||||
import io.ebean.event.BeanPersistListener;
|
||||
@@ -82,7 +84,6 @@ import io.ebeaninternal.server.querydefn.OrmQueryDetail;
|
||||
import io.ebeaninternal.server.querydefn.OrmQueryProperties;
|
||||
import io.ebeaninternal.server.rawsql.SpiRawSql;
|
||||
import io.ebeaninternal.server.type.DataBind;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
import io.ebeaninternal.util.SortByClause;
|
||||
import io.ebeaninternal.util.SortByClauseParser;
|
||||
import io.ebeanservice.docstore.api.DocStoreBeanAdapter;
|
||||
@@ -90,7 +91,6 @@ import io.ebeanservice.docstore.api.DocStoreUpdateContext;
|
||||
import io.ebeanservice.docstore.api.DocStoreUpdates;
|
||||
import io.ebeanservice.docstore.api.mapping.DocMappingBuilder;
|
||||
import io.ebeanservice.docstore.api.mapping.DocPropertyMapping;
|
||||
import io.ebeanservice.docstore.api.mapping.DocPropertyType;
|
||||
import io.ebeanservice.docstore.api.mapping.DocumentMapping;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package io.ebeaninternal.server.deploy;
|
||||
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.core.type.ScalarType;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
|
||||
+1
-2
@@ -1,12 +1,11 @@
|
||||
package io.ebeaninternal.server.deploy;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonToken;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.core.type.ScalarType;
|
||||
import io.ebeaninternal.api.json.SpiJsonReader;
|
||||
import io.ebeaninternal.api.json.SpiJsonWriter;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
+1
-1
@@ -5,10 +5,10 @@ import com.fasterxml.jackson.core.JsonToken;
|
||||
import io.ebean.PersistenceIOException;
|
||||
import io.ebean.SqlUpdate;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.core.type.ScalarType;
|
||||
import io.ebeaninternal.api.json.SpiJsonReader;
|
||||
import io.ebeaninternal.api.json.SpiJsonWriter;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
+1
-1
@@ -2,10 +2,10 @@ package io.ebeaninternal.server.deploy;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.core.type.ScalarType;
|
||||
import io.ebeaninternal.api.json.SpiJsonReader;
|
||||
import io.ebeaninternal.api.json.SpiJsonWriter;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
@@ -16,6 +16,7 @@ import io.ebean.config.dbplatform.DbHistorySupport;
|
||||
import io.ebean.config.dbplatform.DbIdentity;
|
||||
import io.ebean.config.dbplatform.IdType;
|
||||
import io.ebean.config.dbplatform.PlatformIdGenerator;
|
||||
import io.ebean.core.type.ScalarType;
|
||||
import io.ebean.event.changelog.ChangeLogFilter;
|
||||
import io.ebean.event.changelog.ChangeLogListener;
|
||||
import io.ebean.event.changelog.ChangeLogPrepare;
|
||||
@@ -56,7 +57,6 @@ import io.ebeaninternal.server.persist.platform.MultiValueBind;
|
||||
import io.ebeaninternal.server.properties.BeanPropertiesReader;
|
||||
import io.ebeaninternal.server.properties.BeanPropertyAccess;
|
||||
import io.ebeaninternal.server.properties.EnhanceBeanPropertyAccess;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
import io.ebeaninternal.server.type.ScalarTypeInteger;
|
||||
import io.ebeaninternal.server.type.TypeManager;
|
||||
import io.ebeaninternal.xmapping.api.XmapEbean;
|
||||
|
||||
@@ -3,10 +3,10 @@ package io.ebeaninternal.server.deploy;
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebean.config.EncryptKey;
|
||||
import io.ebean.config.NamingConvention;
|
||||
import io.ebean.core.type.ScalarType;
|
||||
import io.ebeaninternal.server.cache.SpiCacheManager;
|
||||
import io.ebeaninternal.server.deploy.id.IdBinder;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
import io.ebeanservice.docstore.api.DocStoreBeanAdapter;
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,6 +8,9 @@ import io.ebean.bean.PersistenceContext;
|
||||
import io.ebean.config.EncryptKey;
|
||||
import io.ebean.config.dbplatform.DbEncryptFunction;
|
||||
import io.ebean.config.dbplatform.DbPlatformType;
|
||||
import io.ebean.core.type.DataReader;
|
||||
import io.ebean.core.type.DocPropertyType;
|
||||
import io.ebean.core.type.ScalarType;
|
||||
import io.ebean.plugin.Property;
|
||||
import io.ebean.text.StringParser;
|
||||
import io.ebean.util.SplitName;
|
||||
@@ -28,9 +31,7 @@ import io.ebeaninternal.server.query.STreeProperty;
|
||||
import io.ebeaninternal.server.query.SqlBeanLoad;
|
||||
import io.ebeaninternal.server.query.SqlJoinType;
|
||||
import io.ebeaninternal.server.type.DataBind;
|
||||
import io.ebeaninternal.server.type.DataReader;
|
||||
import io.ebeaninternal.server.type.LocalEncryptedType;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
import io.ebeaninternal.server.type.ScalarTypeBoolean;
|
||||
import io.ebeaninternal.server.type.ScalarTypeEnum;
|
||||
import io.ebeaninternal.server.type.ScalarTypeLogicalType;
|
||||
@@ -38,7 +39,6 @@ import io.ebeaninternal.util.ValueUtil;
|
||||
import io.ebeanservice.docstore.api.mapping.DocMappingBuilder;
|
||||
import io.ebeanservice.docstore.api.mapping.DocPropertyMapping;
|
||||
import io.ebeanservice.docstore.api.mapping.DocPropertyOptions;
|
||||
import io.ebeanservice.docstore.api.mapping.DocPropertyType;
|
||||
import io.ebeanservice.docstore.api.support.DocStructure;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -2,6 +2,7 @@ package io.ebeaninternal.server.deploy;
|
||||
|
||||
import io.ebean.Query;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.core.type.DocPropertyType;
|
||||
import io.ebean.text.PathProperties;
|
||||
import io.ebean.util.SplitName;
|
||||
import io.ebeaninternal.api.SpiEbeanServer;
|
||||
@@ -22,7 +23,6 @@ import io.ebeaninternal.server.query.SqlJoinType;
|
||||
import io.ebeaninternal.server.querydefn.DefaultOrmQuery;
|
||||
import io.ebeanservice.docstore.api.mapping.DocMappingBuilder;
|
||||
import io.ebeanservice.docstore.api.mapping.DocPropertyMapping;
|
||||
import io.ebeanservice.docstore.api.mapping.DocPropertyType;
|
||||
import io.ebeanservice.docstore.api.support.DocStructure;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -7,6 +7,9 @@ import io.ebean.ValuePair;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.bean.EntityBeanIntercept;
|
||||
import io.ebean.bean.PersistenceContext;
|
||||
import io.ebean.core.type.DataReader;
|
||||
import io.ebean.core.type.ScalarDataReader;
|
||||
import io.ebean.core.type.ScalarType;
|
||||
import io.ebean.util.SplitName;
|
||||
import io.ebeaninternal.api.SpiEbeanServer;
|
||||
import io.ebeaninternal.api.SpiQuery;
|
||||
@@ -23,9 +26,6 @@ import io.ebeaninternal.server.el.ElPropertyValue;
|
||||
import io.ebeaninternal.server.query.STreePropertyAssocOne;
|
||||
import io.ebeaninternal.server.query.SqlBeanLoad;
|
||||
import io.ebeaninternal.server.query.SqlJoinType;
|
||||
import io.ebeaninternal.server.type.DataReader;
|
||||
import io.ebeaninternal.server.type.ScalarDataReader;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -4,9 +4,9 @@ import io.ebean.bean.BeanCollection;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.bean.EntityBeanIntercept;
|
||||
import io.ebean.bean.PersistenceContext;
|
||||
import io.ebean.core.type.DataReader;
|
||||
import io.ebeaninternal.api.SpiQuery;
|
||||
import io.ebeaninternal.server.query.STreePropertyAssocMany;
|
||||
import io.ebeaninternal.server.type.DataReader;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
package io.ebeaninternal.server.deploy;
|
||||
|
||||
import io.ebean.core.type.DataReader;
|
||||
import io.ebean.core.type.ScalarType;
|
||||
import io.ebeaninternal.server.query.SqlBeanLoad;
|
||||
import io.ebeaninternal.server.type.DataReader;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package io.ebeaninternal.server.deploy;
|
||||
|
||||
import io.ebean.core.type.ScalarType;
|
||||
import io.ebeaninternal.server.query.STreeProperty;
|
||||
import io.ebeaninternal.server.query.SqlJoinType;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package io.ebeaninternal.server.deploy;
|
||||
|
||||
import io.ebean.core.type.ScalarType;
|
||||
import io.ebeaninternal.server.el.ElPropertyDeploy;
|
||||
import io.ebeaninternal.server.query.STreeProperty;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
|
||||
import java.sql.Types;
|
||||
|
||||
|
||||
+4
-6
@@ -26,12 +26,10 @@ class InsertTimestampFactory {
|
||||
map.put(Long.class, longTime);
|
||||
map.put(long.class, longTime);
|
||||
|
||||
if (classLoadConfig.isJavaTimePresent()) {
|
||||
map.put(Instant.class, new GeneratedInsertJavaTime.InstantDT());
|
||||
map.put(LocalDateTime.class, new GeneratedInsertJavaTime.LocalDT());
|
||||
map.put(OffsetDateTime.class, new GeneratedInsertJavaTime.OffsetDT());
|
||||
map.put(ZonedDateTime.class, new GeneratedInsertJavaTime.ZonedDT());
|
||||
}
|
||||
map.put(Instant.class, new GeneratedInsertJavaTime.InstantDT());
|
||||
map.put(LocalDateTime.class, new GeneratedInsertJavaTime.LocalDT());
|
||||
map.put(OffsetDateTime.class, new GeneratedInsertJavaTime.OffsetDT());
|
||||
map.put(ZonedDateTime.class, new GeneratedInsertJavaTime.ZonedDT());
|
||||
if (classLoadConfig.isJodaTimePresent()) {
|
||||
map.put(org.joda.time.LocalDateTime.class, new GeneratedInsertJodaTime.LocalDT());
|
||||
map.put(org.joda.time.DateTime.class, new GeneratedInsertJodaTime.DateTimeDT());
|
||||
|
||||
+5
-6
@@ -26,12 +26,11 @@ class UpdateTimestampFactory {
|
||||
map.put(Long.class, longTime);
|
||||
map.put(long.class, longTime);
|
||||
|
||||
if (classLoadConfig.isJavaTimePresent()) {
|
||||
map.put(Instant.class, new GeneratedUpdateJavaTime.InstantDT());
|
||||
map.put(LocalDateTime.class, new GeneratedUpdateJavaTime.LocalDT());
|
||||
map.put(OffsetDateTime.class, new GeneratedUpdateJavaTime.OffsetDT());
|
||||
map.put(ZonedDateTime.class, new GeneratedUpdateJavaTime.ZonedDT());
|
||||
}
|
||||
map.put(Instant.class, new GeneratedUpdateJavaTime.InstantDT());
|
||||
map.put(LocalDateTime.class, new GeneratedUpdateJavaTime.LocalDT());
|
||||
map.put(OffsetDateTime.class, new GeneratedUpdateJavaTime.OffsetDT());
|
||||
map.put(ZonedDateTime.class, new GeneratedUpdateJavaTime.ZonedDT());
|
||||
|
||||
if (classLoadConfig.isJodaTimePresent()) {
|
||||
map.put(org.joda.time.LocalDateTime.class, new GeneratedUpdateJodaTime.LocalDT());
|
||||
map.put(org.joda.time.DateTime.class, new GeneratedUpdateJodaTime.DateTimeDT());
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.ebeaninternal.server.deploy.id;
|
||||
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.core.type.ScalarType;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
import io.ebeaninternal.server.core.DefaultSqlUpdate;
|
||||
import io.ebeaninternal.server.core.InternString;
|
||||
@@ -10,7 +11,6 @@ import io.ebeaninternal.server.deploy.DbSqlContext;
|
||||
import io.ebeaninternal.server.persist.MultiValueWrapper;
|
||||
import io.ebeaninternal.server.persist.platform.MultiValueBind;
|
||||
import io.ebeaninternal.server.type.DataBind;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
|
||||
+1
-1
@@ -17,6 +17,7 @@ import io.ebean.config.ScalarTypeConverter;
|
||||
import io.ebean.config.dbplatform.DbDefaultValue;
|
||||
import io.ebean.config.dbplatform.DbEncrypt;
|
||||
import io.ebean.config.dbplatform.DbEncryptFunction;
|
||||
import io.ebean.core.type.ScalarType;
|
||||
import io.ebean.util.AnnotationUtil;
|
||||
import io.ebeaninternal.server.core.InternString;
|
||||
import io.ebeaninternal.server.deploy.BeanProperty;
|
||||
@@ -26,7 +27,6 @@ import io.ebeaninternal.server.deploy.generatedproperty.GeneratedProperty;
|
||||
import io.ebeaninternal.server.el.ElPropertyValue;
|
||||
import io.ebeaninternal.server.properties.BeanPropertyGetter;
|
||||
import io.ebeaninternal.server.properties.BeanPropertySetter;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
import io.ebeaninternal.server.type.ScalarTypeWrapper;
|
||||
import io.ebeanservice.docstore.api.mapping.DocPropertyOptions;
|
||||
|
||||
|
||||
+1
-1
@@ -8,6 +8,7 @@ import io.ebean.bean.BeanCollection.ModifyListenMode;
|
||||
import io.ebean.config.BeanNotRegisteredException;
|
||||
import io.ebean.config.NamingConvention;
|
||||
import io.ebean.config.TableName;
|
||||
import io.ebean.core.type.ScalarType;
|
||||
import io.ebean.util.CamelCaseHelper;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptorManager;
|
||||
import io.ebeaninternal.server.deploy.BeanProperty;
|
||||
@@ -21,7 +22,6 @@ import io.ebeaninternal.server.deploy.meta.DeployOrderColumn;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployTableJoin;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployTableJoinColumn;
|
||||
import io.ebeaninternal.server.query.SqlJoinType;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.CollectionTable;
|
||||
|
||||
@@ -39,6 +39,7 @@ import io.ebean.config.dbplatform.DbEncrypt;
|
||||
import io.ebean.config.dbplatform.DbEncryptFunction;
|
||||
import io.ebean.config.dbplatform.IdType;
|
||||
import io.ebean.config.dbplatform.PlatformIdGenerator;
|
||||
import io.ebean.core.type.ScalarType;
|
||||
import io.ebeaninternal.server.deploy.DbMigrationInfo;
|
||||
import io.ebeaninternal.server.deploy.IndexDefinition;
|
||||
import io.ebeaninternal.server.deploy.generatedproperty.GeneratedPropertyFactory;
|
||||
@@ -46,7 +47,6 @@ import io.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssoc;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
|
||||
import io.ebeaninternal.server.type.DataEncryptSupport;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
import io.ebeaninternal.server.type.ScalarTypeBytesBase;
|
||||
import io.ebeaninternal.server.type.ScalarTypeBytesEncrypted;
|
||||
import io.ebeaninternal.server.type.ScalarTypeEncryptedWrapper;
|
||||
|
||||
+2
-2
@@ -2,10 +2,11 @@ package io.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import io.ebean.Model;
|
||||
import io.ebean.annotation.DbArray;
|
||||
import io.ebean.annotation.DbMap;
|
||||
import io.ebean.annotation.DbJson;
|
||||
import io.ebean.annotation.DbJsonB;
|
||||
import io.ebean.annotation.DbMap;
|
||||
import io.ebean.annotation.UnmappedJson;
|
||||
import io.ebean.core.type.ScalarType;
|
||||
import io.ebean.util.AnnotationUtil;
|
||||
import io.ebeaninternal.server.deploy.DetermineManyType;
|
||||
import io.ebeaninternal.server.deploy.ManyType;
|
||||
@@ -14,7 +15,6 @@ import io.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocMany;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployBeanPropertySimpleCollection;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
import io.ebeaninternal.server.type.TypeManager;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -14,9 +14,9 @@ import io.ebean.config.NamingConvention;
|
||||
import io.ebean.config.TableName;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
import io.ebean.config.dbplatform.DbPlatformType;
|
||||
import io.ebean.core.type.ScalarType;
|
||||
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;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package io.ebeaninternal.server.dto;
|
||||
|
||||
import io.ebeaninternal.server.type.DataReader;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
import io.ebean.core.type.DataReader;
|
||||
import io.ebean.core.type.ScalarType;
|
||||
import io.ebeaninternal.server.type.TypeManager;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package io.ebeaninternal.server.dto;
|
||||
|
||||
import io.ebeaninternal.server.type.DataReader;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
import io.ebean.core.type.DataReader;
|
||||
import io.ebean.core.type.ScalarType;
|
||||
import io.ebeaninternal.server.type.TypeManager;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package io.ebeaninternal.server.dto;
|
||||
|
||||
import io.ebean.core.type.DataReader;
|
||||
import io.ebean.meta.MetricVisitor;
|
||||
import io.ebeaninternal.server.type.DataReader;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package io.ebeaninternal.server.dto;
|
||||
|
||||
import io.ebeaninternal.server.type.DataReader;
|
||||
import io.ebean.core.type.DataReader;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package io.ebeaninternal.server.dto;
|
||||
|
||||
import io.ebeaninternal.server.type.DataReader;
|
||||
import io.ebean.core.type.DataReader;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package io.ebeaninternal.server.dto;
|
||||
|
||||
import io.ebeaninternal.server.type.DataReader;
|
||||
import io.ebean.core.type.DataReader;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package io.ebeaninternal.server.dto;
|
||||
|
||||
import io.ebeaninternal.server.type.DataReader;
|
||||
import io.ebean.core.type.DataReader;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package io.ebeaninternal.server.dto;
|
||||
|
||||
import io.ebeaninternal.server.type.DataReader;
|
||||
import io.ebean.core.type.DataReader;
|
||||
|
||||
/**
|
||||
* Placeholder to skip reading a column that isn't mapped to a bean property.
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package io.ebeaninternal.server.el;
|
||||
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.core.type.ScalarType;
|
||||
import io.ebean.plugin.Property;
|
||||
import io.ebean.text.StringParser;
|
||||
import io.ebean.util.SplitName;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
import io.ebeaninternal.server.deploy.BeanProperty;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
|
||||
+15
@@ -491,16 +491,31 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
|
||||
return query.forUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> forUpdate(Query.LockType lockType) {
|
||||
return query.forUpdate(lockType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> forUpdateNoWait() {
|
||||
return query.forUpdateNoWait();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> forUpdateNoWait(Query.LockType lockType) {
|
||||
return query.forUpdateNoWait(lockType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> forUpdateSkipLocked() {
|
||||
return query.forUpdateSkipLocked();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> forUpdateSkipLocked(Query.LockType lockType) {
|
||||
return query.forUpdateSkipLocked(lockType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> select(String fetchProperties) {
|
||||
return query.select(fetchProperties);
|
||||
|
||||
@@ -496,16 +496,31 @@ class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expression
|
||||
return exprList.forUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> forUpdate(Query.LockType lockType) {
|
||||
return exprList.forUpdate(lockType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> forUpdateNoWait() {
|
||||
return exprList.forUpdateNoWait();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> forUpdateNoWait(Query.LockType lockType) {
|
||||
return exprList.forUpdateNoWait(lockType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> forUpdateSkipLocked() {
|
||||
return exprList.forUpdateSkipLocked();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> forUpdateSkipLocked(Query.LockType lockType) {
|
||||
return exprList.forUpdateSkipLocked(lockType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Path exists - for the given path in a JSON document.
|
||||
*/
|
||||
|
||||
@@ -138,9 +138,8 @@ public final class BatchControl {
|
||||
* These all go straight to jdbc and use addBatch(). Entity beans goto a queue
|
||||
* and wait there so that the jdbc is executed in the correct order according
|
||||
* to the depth.
|
||||
* </p>
|
||||
*/
|
||||
public int executeStatementOrBatch(PersistRequest request, boolean batch) throws BatchedSqlException {
|
||||
public int executeStatementOrBatch(PersistRequest request, boolean batch, boolean addBatch) throws BatchedSqlException {
|
||||
if (!batch || (batchFlushOnMixed && !isBeansEmpty())) {
|
||||
// flush when mixing beans and updateSql
|
||||
flush();
|
||||
@@ -149,8 +148,7 @@ public final class BatchControl {
|
||||
// execute the request immediately without batching
|
||||
return request.executeNow();
|
||||
}
|
||||
|
||||
if (pstmtHolder.getMaxSize() >= batchSize) {
|
||||
if (!addBatch && pstmtHolder.getMaxSize() >= batchSize) {
|
||||
flush();
|
||||
}
|
||||
// for OrmUpdate, SqlUpdate, CallableSql there is no queue...
|
||||
@@ -166,7 +164,6 @@ public final class BatchControl {
|
||||
* according to the depth (object graph depth).
|
||||
*/
|
||||
public int executeOrQueue(PersistRequestBean<?> request, boolean batch) throws BatchedSqlException {
|
||||
|
||||
if (!batch || (batchFlushOnMixed && !pstmtHolder.isEmpty())) {
|
||||
// flush when mixing beans and updateSql
|
||||
flush();
|
||||
@@ -185,7 +182,6 @@ public final class BatchControl {
|
||||
* Add the request to the batch and return true if we should flush.
|
||||
*/
|
||||
private boolean addToBatch(PersistRequestBean<?> request) {
|
||||
|
||||
Object alreadyInBatch = persistedBeans.put(request.getEntityBean(), DUMMY);
|
||||
if (alreadyInBatch != null) {
|
||||
// special case where the same bean instance has already been
|
||||
@@ -220,7 +216,11 @@ public final class BatchControl {
|
||||
* Flush any batched PreparedStatements.
|
||||
*/
|
||||
private void flushPstmtHolder() throws BatchedSqlException {
|
||||
pstmtHolder.flush(getGeneratedKeys);
|
||||
pstmtHolder.flush(getGeneratedKeys, false);
|
||||
}
|
||||
|
||||
private void flushPstmtHolder(boolean reset) throws BatchedSqlException {
|
||||
pstmtHolder.flush(getGeneratedKeys, reset);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -237,6 +237,15 @@ public final class BatchControl {
|
||||
flushPstmtHolder();
|
||||
}
|
||||
|
||||
public void flushOnCommit() throws BatchedSqlException {
|
||||
try {
|
||||
flushBuffer(false);
|
||||
} finally {
|
||||
// ensure PreparedStatements are closed
|
||||
pstmtHolder.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush without resetting the depth info.
|
||||
*/
|
||||
@@ -261,8 +270,8 @@ public final class BatchControl {
|
||||
persistedBeans.clear();
|
||||
}
|
||||
|
||||
private void flushBuffer(boolean resetTop) throws BatchedSqlException {
|
||||
flushInternal(resetTop);
|
||||
private void flushBuffer(boolean reset) throws BatchedSqlException {
|
||||
flushInternal(reset);
|
||||
flushQueue(earlyQueue);
|
||||
flushQueue(lateQueue);
|
||||
}
|
||||
@@ -275,14 +284,15 @@ public final class BatchControl {
|
||||
|
||||
/**
|
||||
* execute all the requests currently queued or batched.
|
||||
*
|
||||
* @param reset When true close all batched statements (completely empty)
|
||||
*/
|
||||
private void flushInternal(boolean resetTop) throws BatchedSqlException {
|
||||
|
||||
private void flushInternal(boolean reset) throws BatchedSqlException {
|
||||
try {
|
||||
bufferMax = 0;
|
||||
if (!pstmtHolder.isEmpty()) {
|
||||
// Flush existing pstmts (updateSql or callableSql)
|
||||
flushPstmtHolder();
|
||||
flushPstmtHolder(reset);
|
||||
}
|
||||
if (isEmpty()) {
|
||||
// Nothing in queue to flush
|
||||
@@ -301,7 +311,7 @@ public final class BatchControl {
|
||||
beanHolder.executeNow();
|
||||
}
|
||||
persistedBeans.clear();
|
||||
if (resetTop) {
|
||||
if (reset) {
|
||||
beanHoldMap.clear();
|
||||
depthOrder.clear();
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ public class BatchedPstmt implements SpiProfileTransactionEvent {
|
||||
/**
|
||||
* The list of BatchPostExecute used to perform post processing.
|
||||
*/
|
||||
private final ArrayList<BatchPostExecute> list = new ArrayList<>();
|
||||
private final List<BatchPostExecute> list = new ArrayList<>();
|
||||
|
||||
private final String sql;
|
||||
|
||||
@@ -68,6 +68,10 @@ public class BatchedPstmt implements SpiProfileTransactionEvent {
|
||||
return list.size();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return list.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the sql
|
||||
*/
|
||||
@@ -95,9 +99,7 @@ public class BatchedPstmt implements SpiProfileTransactionEvent {
|
||||
if (rows.length != list.size()) {
|
||||
throw new IllegalStateException("Invalid state on executeBatch, rows:" + rows.length + " != " + list.size());
|
||||
}
|
||||
for (BatchPostExecute item : list) {
|
||||
item.postExecute();
|
||||
}
|
||||
postExecute();
|
||||
list.clear();
|
||||
}
|
||||
|
||||
@@ -113,7 +115,9 @@ public class BatchedPstmt implements SpiProfileTransactionEvent {
|
||||
* Run any post processing including getGeneratedKeys.
|
||||
*/
|
||||
public void executeBatch(boolean getGeneratedKeys) throws SQLException {
|
||||
|
||||
if (list.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
timedStart = System.nanoTime();
|
||||
profileStart = transaction.profileOffset();
|
||||
executeAndCheckRowCounts();
|
||||
@@ -121,8 +125,8 @@ public class BatchedPstmt implements SpiProfileTransactionEvent {
|
||||
getGeneratedKeys();
|
||||
}
|
||||
postExecute();
|
||||
close();
|
||||
addTimingMetrics();
|
||||
list.clear();
|
||||
transaction.profileEvent(this);
|
||||
}
|
||||
|
||||
@@ -140,10 +144,15 @@ public class BatchedPstmt implements SpiProfileTransactionEvent {
|
||||
/**
|
||||
* Close the underlying statement.
|
||||
*/
|
||||
public void close() throws SQLException {
|
||||
public void close() {
|
||||
if (pstmt != null) {
|
||||
pstmt.close();
|
||||
pstmt = null;
|
||||
try {
|
||||
pstmt.close();
|
||||
} catch (SQLException e) {
|
||||
log.warn("Error closing statement", e);
|
||||
} finally {
|
||||
pstmt = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,7 +178,6 @@ public class BatchedPstmt implements SpiProfileTransactionEvent {
|
||||
}
|
||||
|
||||
private void getGeneratedKeys() throws SQLException {
|
||||
|
||||
int index = 0;
|
||||
try (ResultSet rset = pstmt.getGeneratedKeys()) {
|
||||
while (rset.next()) {
|
||||
@@ -190,8 +198,13 @@ public class BatchedPstmt implements SpiProfileTransactionEvent {
|
||||
/**
|
||||
* Register any inputStreams that should be closed after execution.
|
||||
*/
|
||||
public void registerInputStreams(List<InputStream> inputStreams) {
|
||||
this.inputStreams = inputStreams;
|
||||
public void registerInputStreams(List<InputStream> streams) {
|
||||
if (streams != null) {
|
||||
if (this.inputStreams == null) {
|
||||
this.inputStreams = new ArrayList<>();
|
||||
}
|
||||
this.inputStreams.addAll(streams);
|
||||
}
|
||||
}
|
||||
|
||||
private void closeInputStreams() {
|
||||
@@ -203,6 +216,7 @@ public class BatchedPstmt implements SpiProfileTransactionEvent {
|
||||
log.warn("Error closing inputStream ", e);
|
||||
}
|
||||
}
|
||||
inputStreams = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
package io.ebeaninternal.server.persist;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Used to hold BatchedPstmt objects for batch based execution.
|
||||
@@ -18,13 +17,11 @@ import java.util.LinkedHashMap;
|
||||
*/
|
||||
public class BatchedPstmtHolder {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(BatchedPstmtHolder.class);
|
||||
|
||||
/**
|
||||
* A Map of the statements using a String key. This is used so that the same
|
||||
* Statement,Prepared,Callable is reused.
|
||||
*/
|
||||
private final LinkedHashMap<String, BatchedPstmt> stmtMap = new LinkedHashMap<>();
|
||||
private Map<String, BatchedPstmt> stmtMap = new LinkedHashMap<>();
|
||||
|
||||
/**
|
||||
* The Max size across all the BatchedPstmt.
|
||||
@@ -47,13 +44,10 @@ public class BatchedPstmtHolder {
|
||||
* Return the BatchedPstmt that holds the batched statement.
|
||||
*/
|
||||
public BatchedPstmt getBatchedPstmt(String stmtKey) {
|
||||
|
||||
BatchedPstmt bs = stmtMap.get(stmtKey);
|
||||
if (bs == null) {
|
||||
// the PreparedStatement has need been created
|
||||
return null;
|
||||
}
|
||||
|
||||
// maintain a max batch size for any given batched stmt.
|
||||
// Used to determine when to flush.
|
||||
int bsSize = bs.size();
|
||||
@@ -63,14 +57,19 @@ public class BatchedPstmtHolder {
|
||||
return bs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the size of the biggest batched statement.
|
||||
* Used to determine when to flush the batch.
|
||||
*/
|
||||
int getMaxSize() {
|
||||
return maxSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new PreparedStatement wrapped in the BatchStatement object.
|
||||
*/
|
||||
public void addStmt(BatchedPstmt bs, BatchPostExecute postExecute) {
|
||||
// add the batch post execute to the statement for POST processing
|
||||
bs.add(postExecute);
|
||||
|
||||
// cache so that getStmt() can find it for additional beans/rows
|
||||
stmtMap.put(bs.getSql(), bs);
|
||||
}
|
||||
|
||||
@@ -78,15 +77,22 @@ public class BatchedPstmtHolder {
|
||||
* Return true if the batch has no statements to execute.
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return stmtMap.isEmpty();
|
||||
if (stmtMap.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
for (BatchedPstmt bs : stmtMap.values()) {
|
||||
if (!bs.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute one of the batched statements returning the row counts.
|
||||
*/
|
||||
public int[] execute(String key, boolean getGeneratedKeys) throws SQLException {
|
||||
|
||||
BatchedPstmt batchedPstmt = stmtMap.remove(key);
|
||||
BatchedPstmt batchedPstmt = stmtMap.get(key);
|
||||
if (batchedPstmt == null) {
|
||||
throw new PersistenceException("No batched statement found for key " + key);
|
||||
}
|
||||
@@ -96,69 +102,56 @@ public class BatchedPstmtHolder {
|
||||
|
||||
/**
|
||||
* Execute all batched PreparedStatements.
|
||||
*
|
||||
* @param getGeneratedKeys if true try to get generated keys for inserts
|
||||
*/
|
||||
public void flush(boolean getGeneratedKeys) throws BatchedSqlException {
|
||||
|
||||
SQLException firstError = null;
|
||||
String errorSql = null;
|
||||
|
||||
// flag set if something fails. Will not execute
|
||||
// but still need to close PreparedStatements.
|
||||
boolean isError = false;
|
||||
|
||||
public void flush(boolean getGeneratedKeys, boolean reset) throws BatchedSqlException {
|
||||
// if there are Listeners/Controllers that interact with the database,
|
||||
// the flush may get called recursively in executeBatch/postExecute.
|
||||
// which leads that we process stmtMap.values() twice in the loop.
|
||||
// So we copy the values, that we want to flush and clear it immediately.
|
||||
BatchedPstmt[] values = stmtMap.values().toArray(new BatchedPstmt[0]);
|
||||
clear();
|
||||
// which means this needs to process a copy of stmtMap, create a new stmtMap and loadBack after
|
||||
final Map<String, BatchedPstmt> copyMap = stmtMap;
|
||||
final Collection<BatchedPstmt> copy = copyMap.values();
|
||||
this.stmtMap = new LinkedHashMap<>();
|
||||
this.maxSize = 0;
|
||||
try {
|
||||
executeAll(copy, getGeneratedKeys);
|
||||
if (reset) {
|
||||
closeStatements(copy);
|
||||
} else {
|
||||
loadBack(copyMap);
|
||||
}
|
||||
} catch (BatchedSqlException e) {
|
||||
closeStatements(copy);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private void loadBack(Map<String, BatchedPstmt> copyMap) {
|
||||
if (stmtMap.isEmpty()) {
|
||||
// just restore, was not modified during flush by Listeners/Controllers
|
||||
stmtMap = copyMap;
|
||||
} else {
|
||||
closeStatements(copyMap.values());
|
||||
}
|
||||
}
|
||||
|
||||
private void executeAll(Collection<BatchedPstmt> values, boolean getGeneratedKeys) throws BatchedSqlException {
|
||||
for (BatchedPstmt bs : values) {
|
||||
try {
|
||||
if (!isError) {
|
||||
bs.executeBatch(getGeneratedKeys);
|
||||
}
|
||||
bs.executeBatch(getGeneratedKeys);
|
||||
} catch (SQLException ex) {
|
||||
SQLException next = ex.getNextException();
|
||||
while (next != null) {
|
||||
logger.trace("Next Exception during batch execution", next);
|
||||
next = next.getNextException();
|
||||
}
|
||||
|
||||
firstError = ex;
|
||||
errorSql = bs.getSql();
|
||||
isError = true;
|
||||
|
||||
} finally {
|
||||
try {
|
||||
bs.close();
|
||||
} catch (SQLException ex) {
|
||||
logger.error("Error closing batched PreparedStatement", ex);
|
||||
}
|
||||
throw new BatchedSqlException("Error when batch flush on sql: " + bs.getSql(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (firstError != null) {
|
||||
String msg = "Error when batch flush on sql: " + errorSql;
|
||||
throw new BatchedSqlException(msg, firstError);
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
closeStatements(stmtMap.values());
|
||||
stmtMap.clear();
|
||||
maxSize = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the size of the biggest batched statement.
|
||||
* <p>
|
||||
* Used to determine when to flush the batch.
|
||||
* </p>
|
||||
*/
|
||||
int getMaxSize() {
|
||||
return maxSize;
|
||||
private void closeStatements(Collection<BatchedPstmt> batchedStatements) {
|
||||
for (BatchedPstmt bs: batchedStatements) {
|
||||
bs.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
package io.ebeaninternal.server.persist;
|
||||
|
||||
import io.ebean.config.dbplatform.DbPlatformType;
|
||||
import io.ebean.core.type.DataReader;
|
||||
import io.ebean.core.type.ScalarType;
|
||||
import io.ebeaninternal.api.BindParams;
|
||||
import io.ebeaninternal.api.SpiLogManager;
|
||||
import io.ebeaninternal.server.core.timezone.DataTimeZone;
|
||||
import io.ebeaninternal.server.expression.platform.DbExpressionHandler;
|
||||
import io.ebeaninternal.server.persist.platform.MultiValueBind;
|
||||
import io.ebeaninternal.server.type.DataBind;
|
||||
import io.ebeaninternal.server.type.DataReader;
|
||||
import io.ebeaninternal.server.type.GeoTypeBinder;
|
||||
import io.ebeaninternal.server.type.PostgresHelper;
|
||||
import io.ebeaninternal.server.type.RsetDataReader;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
import io.ebeaninternal.server.type.TypeManager;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -35,26 +36,18 @@ public class Binder {
|
||||
private static final Logger logger = LoggerFactory.getLogger(Binder.class);
|
||||
|
||||
private final TypeManager typeManager;
|
||||
|
||||
private final int asOfBindCount;
|
||||
|
||||
private final boolean asOfStandardsBased;
|
||||
|
||||
private final DbExpressionHandler dbExpressionHandler;
|
||||
|
||||
private final DataTimeZone dataTimeZone;
|
||||
|
||||
private final MultiValueBind multiValueBind;
|
||||
|
||||
private final boolean enableBindLog;
|
||||
private final GeoTypeBinder geoTypeBinder;
|
||||
|
||||
/**
|
||||
* Set the PreparedStatement with which to bind variables to.
|
||||
*/
|
||||
public Binder(TypeManager typeManager, SpiLogManager logManager, int asOfBindCount, boolean asOfStandardsBased,
|
||||
DbExpressionHandler dbExpressionHandler, DataTimeZone dataTimeZone, MultiValueBind multiValueBind) {
|
||||
|
||||
this.typeManager = typeManager;
|
||||
this.geoTypeBinder = typeManager.getGeoTypeBinder();
|
||||
this.asOfBindCount = asOfBindCount;
|
||||
this.asOfStandardsBased = asOfStandardsBased;
|
||||
this.dbExpressionHandler = dbExpressionHandler;
|
||||
@@ -88,9 +81,7 @@ public class Binder {
|
||||
* Bind the values to the Prepared Statement.
|
||||
*/
|
||||
public void bind(BindValues bindValues, DataBind dataBind, StringBuilder bindBuf) throws SQLException {
|
||||
|
||||
String logPrefix = "";
|
||||
|
||||
ArrayList<BindValues.Value> list = bindValues.values();
|
||||
for (BindValues.Value bindValue : list) {
|
||||
Object val = bindValue.getValue();
|
||||
@@ -124,7 +115,6 @@ public class Binder {
|
||||
* Bind the list of positionedParameters in BindParams.
|
||||
*/
|
||||
private String bind(BindParams bindParams, DataBind dataBind) throws SQLException {
|
||||
|
||||
StringBuilder bindLog = new StringBuilder();
|
||||
bind(bindParams, dataBind, bindLog);
|
||||
return bindLog.toString();
|
||||
@@ -134,7 +124,6 @@ public class Binder {
|
||||
* Bind the list of positionedParameters in BindParams.
|
||||
*/
|
||||
public void bind(BindParams bindParams, DataBind dataBind, StringBuilder bindLog) throws SQLException {
|
||||
|
||||
bind(bindParams.positionedParameters(), dataBind, bindLog);
|
||||
}
|
||||
|
||||
@@ -142,13 +131,10 @@ public class Binder {
|
||||
* Bind the list of parameters..
|
||||
*/
|
||||
private void bind(List<BindParams.Param> list, DataBind dataBind, StringBuilder bindLog) throws SQLException {
|
||||
|
||||
CallableStatement cstmt = null;
|
||||
|
||||
if (dataBind.getPstmt() instanceof CallableStatement) {
|
||||
cstmt = (CallableStatement) dataBind.getPstmt();
|
||||
}
|
||||
|
||||
// the iterator is assumed to be in the correct order
|
||||
Object value = null;
|
||||
try {
|
||||
@@ -211,7 +197,6 @@ public class Binder {
|
||||
* Bind an Object with unknown data type.
|
||||
*/
|
||||
public Object bindObject(DataBind dataBind, Object value) throws SQLException {
|
||||
|
||||
if (value == null) {
|
||||
// null of unknown type
|
||||
bindObject(dataBind, null, Types.OTHER);
|
||||
@@ -233,9 +218,7 @@ public class Binder {
|
||||
// convert to a JDBC native type
|
||||
value = type.toJdbcType(value);
|
||||
}
|
||||
|
||||
int dbType = type.getJdbcType();
|
||||
bindObject(dataBind, value, dbType);
|
||||
bindObject(dataBind, value, type.getJdbcType());
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -261,12 +244,10 @@ public class Binder {
|
||||
* </p>
|
||||
*/
|
||||
private void bindObject(DataBind dataBind, Object data, int dbType) throws SQLException {
|
||||
|
||||
if (data == null) {
|
||||
dataBind.setNull(dbType);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (dbType) {
|
||||
case java.sql.Types.LONGVARCHAR:
|
||||
bindLongVarChar(dataBind, data);
|
||||
@@ -293,7 +274,6 @@ public class Binder {
|
||||
* Binds the value to the statement according to the data type.
|
||||
*/
|
||||
private void bindSimpleData(DataBind b, int dataType, Object data) {
|
||||
|
||||
try {
|
||||
switch (dataType) {
|
||||
case java.sql.Types.BOOLEAN:
|
||||
@@ -370,6 +350,15 @@ public class Binder {
|
||||
b.setObject(PostgresHelper.asInet(data.toString()));
|
||||
break;
|
||||
|
||||
case DbPlatformType.POINT:
|
||||
case DbPlatformType.POLYGON:
|
||||
case DbPlatformType.MULTIPOINT:
|
||||
case DbPlatformType.LINESTRING:
|
||||
case DbPlatformType.MULTILINESTRING:
|
||||
case DbPlatformType.MULTIPOLYGON:
|
||||
geoTypeBinder.bind(b, dataType, data);
|
||||
break;
|
||||
|
||||
case java.sql.Types.OTHER:
|
||||
b.setObject(data, dataType);
|
||||
break;
|
||||
@@ -393,7 +382,6 @@ public class Binder {
|
||||
* Bind String data to a LONGVARCHAR column.
|
||||
*/
|
||||
private void bindLongVarChar(DataBind dataBind, Object data) throws SQLException {
|
||||
|
||||
dataBind.setClob((String) data);
|
||||
}
|
||||
|
||||
@@ -401,7 +389,6 @@ public class Binder {
|
||||
* Bind byte[] data to a LONGVARBINARY column.
|
||||
*/
|
||||
private void bindLongVarBinary(DataBind dataBind, Object data) throws SQLException {
|
||||
|
||||
dataBind.setBlob((byte[]) data);
|
||||
}
|
||||
|
||||
@@ -409,7 +396,6 @@ public class Binder {
|
||||
* Bind String data to a CLOB column.
|
||||
*/
|
||||
private void bindClob(DataBind dataBind, Object data) throws SQLException {
|
||||
|
||||
dataBind.setClob((String) data);
|
||||
}
|
||||
|
||||
@@ -417,7 +403,6 @@ public class Binder {
|
||||
* Bind byte[] data to a BLOB column.
|
||||
*/
|
||||
private void bindBlob(DataBind dataBind, Object data) throws SQLException {
|
||||
|
||||
dataBind.setBlob((byte[]) data);
|
||||
}
|
||||
|
||||
|
||||
@@ -44,10 +44,12 @@ class PstmtFactory {
|
||||
* Return a prepared statement taking into account batch requirements.
|
||||
*/
|
||||
PreparedStatement getPstmtBatch(SpiTransaction t, String sql, BatchPostExecute batchExe) throws SQLException {
|
||||
|
||||
BatchedPstmtHolder batch = t.getBatchControl().getPstmtHolder();
|
||||
BatchedPstmt existingStmt = batch.getBatchedPstmt(sql);
|
||||
if (existingStmt != null) {
|
||||
if (existingStmt.isEmpty() && t.isLogSql()) {
|
||||
t.logSql(TrimLogSql.trim(sql));
|
||||
}
|
||||
return existingStmt.getStatement(batchExe);
|
||||
}
|
||||
|
||||
@@ -57,7 +59,6 @@ class PstmtFactory {
|
||||
|
||||
Connection conn = t.getInternalConnection();
|
||||
PreparedStatement stmt = conn.prepareStatement(sql);
|
||||
|
||||
BatchedPstmt bs = new BatchedPstmt(stmt, false, sql, t);
|
||||
batch.addStmt(bs, batchExe);
|
||||
return stmt;
|
||||
|
||||
@@ -24,8 +24,8 @@ public abstract class DmlHandler implements PersistHandler, BindableRequest {
|
||||
private static final Logger logger = LoggerFactory.getLogger(DmlHandler.class);
|
||||
|
||||
private static final int[] GENERATED_KEY_COLUMNS = new int[]{1};
|
||||
private static final int BATCHED_FIRST = 1;
|
||||
private static final int BATCHED = 2;
|
||||
private static final short BATCHED_FIRST = 1;
|
||||
private static final short BATCHED = 2;
|
||||
|
||||
/**
|
||||
* The originating request.
|
||||
@@ -261,17 +261,15 @@ public abstract class DmlHandler implements PersistHandler, BindableRequest {
|
||||
* Return a prepared statement taking into account batch requirements.
|
||||
*/
|
||||
PreparedStatement getPstmtBatch(SpiTransaction t, String sql, PersistRequestBean<?> request, boolean genKeys) throws SQLException {
|
||||
|
||||
BatchedPstmtHolder batch = t.getBatchControl().getPstmtHolder();
|
||||
batchedPstmt = batch.getBatchedPstmt(sql);
|
||||
if (batchedPstmt != null) {
|
||||
batchedStatus = BATCHED;
|
||||
batchedStatus = batchedPstmt.isEmpty() ? BATCHED_FIRST : BATCHED;
|
||||
return batchedPstmt.getStatement(request);
|
||||
}
|
||||
|
||||
batchedStatus = BATCHED_FIRST;
|
||||
PreparedStatement stmt = getPstmt(t, sql, genKeys);
|
||||
|
||||
batchedPstmt = new BatchedPstmt(stmt, genKeys, sql, t);
|
||||
batch.addStmt(batchedPstmt, request);
|
||||
return stmt;
|
||||
|
||||
+1
-1
@@ -1,8 +1,8 @@
|
||||
package io.ebeaninternal.server.persist.platform;
|
||||
|
||||
import io.ebean.config.dbplatform.ExtraDbTypes;
|
||||
import io.ebean.core.type.ScalarType;
|
||||
import io.ebeaninternal.server.type.DataBind;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
package io.ebeaninternal.server.persist.platform;
|
||||
|
||||
import io.ebean.core.type.ScalarType;
|
||||
import io.ebeaninternal.server.type.DataBind;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
package io.ebeaninternal.server.persist.platform;
|
||||
|
||||
import io.ebean.config.dbplatform.ExtraDbTypes;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
import io.ebean.core.type.ScalarType;
|
||||
|
||||
/**
|
||||
* Multi value binder that uses Postgres Array.
|
||||
|
||||
@@ -9,6 +9,7 @@ import io.ebean.bean.NodeUsageCollector;
|
||||
import io.ebean.bean.NodeUsageListener;
|
||||
import io.ebean.bean.ObjectGraphNode;
|
||||
import io.ebean.bean.PersistenceContext;
|
||||
import io.ebean.core.type.DataReader;
|
||||
import io.ebean.event.readaudit.ReadEvent;
|
||||
import io.ebean.util.JdbcClose;
|
||||
import io.ebeaninternal.api.SpiProfileTransactionEvent;
|
||||
@@ -24,7 +25,6 @@ import io.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
import io.ebeaninternal.server.deploy.BeanPropertyAssocOne;
|
||||
import io.ebeaninternal.server.deploy.DbReadContext;
|
||||
import io.ebeaninternal.server.type.DataBind;
|
||||
import io.ebeaninternal.server.type.DataReader;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
@@ -783,7 +783,7 @@ class CQueryBuilder {
|
||||
* Return the 'for update' FROM hint (sql server).
|
||||
*/
|
||||
String fromForUpdate(SpiQuery<?> query) {
|
||||
Query.ForUpdate mode = query.getForUpdateMode();
|
||||
Query.LockWait mode = query.getForUpdateLockWait();
|
||||
if (mode == null) {
|
||||
return null;
|
||||
} else {
|
||||
|
||||
@@ -237,6 +237,7 @@ public class CQueryEngine {
|
||||
|
||||
} catch (SQLException e) {
|
||||
try {
|
||||
cquery.close();
|
||||
throw cquery.createPersistenceException(e);
|
||||
} finally {
|
||||
request.rollbackTransIfRequired();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user