diff --git a/src/main/java/com/avaje/ebean/config/dbplatform/DatabasePlatform.java b/src/main/java/com/avaje/ebean/config/dbplatform/DatabasePlatform.java
index 7885bfda0..d1516895a 100644
--- a/src/main/java/com/avaje/ebean/config/dbplatform/DatabasePlatform.java
+++ b/src/main/java/com/avaje/ebean/config/dbplatform/DatabasePlatform.java
@@ -1,388 +1,427 @@
-package com.avaje.ebean.config.dbplatform;
-
-import java.sql.Types;
-
-import javax.sql.DataSource;
-
-import com.avaje.ebean.BackgroundExecutor;
-import com.avaje.ebean.Query;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Database platform specific settings.
- */
-public class DatabasePlatform {
-
- private static final Logger logger = LoggerFactory.getLogger(DatabasePlatform.class);
-
- /**
- * The open quote used by quoted identifiers.
- */
- protected String openQuote = "\"";
-
- /**
- * The close quote used by quoted identifiers.
- */
- protected String closeQuote = "\"";
-
- /**
- * For limit/offset, row_number etc limiting of SQL queries.
- */
- protected SqlLimiter sqlLimiter = new LimitOffsetSqlLimiter();
-
- /**
- * Mapping of JDBC to Database types.
- */
- protected DbTypeMap dbTypeMap = new DbTypeMap();
-
- /**
- * DB specific DDL syntax.
- */
- protected DbDdlSyntax dbDdlSyntax = new DbDdlSyntax();
-
- /**
- * Defines DB identity/sequence features.
- */
- protected DbIdentity dbIdentity = new DbIdentity();
-
- /**
- * The JDBC type to map booleans to (by default).
- */
- protected int booleanDbType = Types.BOOLEAN;
-
- /**
- * The JDBC type to map Blob to.
- */
- protected int blobDbType = Types.BLOB;
-
- /**
- * The JDBC type to map Clob to.
- */
- protected int clobDbType = Types.CLOB;
-
- /**
- * For Oracle treat empty strings as null.
- */
- protected boolean treatEmptyStringsAsNull;
-
- /**
- * The database platform name.
- */
- protected String name = "generic";
-
- protected String columnAliasPrefix = "c";
-
- protected String tableAliasPlaceHolder = "${ta}";
-
- /**
- * Use a BackTick ` at the beginning and end of table or column names that you
- * want to use quoted identifiers for. The backticks get converted to the
- * appropriate characters in convertQuotedIdentifiers
- */
- private static final char BACK_TICK = '`';
-
- /**
- * The like clause. Can be overridden to disable default escape character.
- */
- protected String likeClause = "like ?";
-
- protected DbEncrypt dbEncrypt;
-
- protected boolean idInExpandedForm;
-
- protected boolean selectCountWithAlias;
-
- /**
- * If set then use the FORWARD ONLY hint when creating ResultSets for
- * findIterate() and findVisit().
- */
- protected boolean forwardOnlyHintOnFindIterate;
-
- /**
- * Flag set for SQL Server due to lack of support of getGeneratedKeys in
- * batch mode (meaning for batch inserts you should explicitly turn off
- * getGeneratedKeys - joy).
- */
- protected boolean disallowBatchOnCascade;
-
- /**
- * Instantiates a new database platform.
- */
- public DatabasePlatform() {
- }
-
- /**
- * Return the name of the DatabasePlatform.
- *
- * "generic" is returned when no specific database platform has been set or
- * found.
- *
- *
- * @return the name
- */
- public String getName() {
- return name;
- }
-
- /**
- * Return a DB Sequence based IdGenerator.
- *
- * @param be
- * the BackgroundExecutor that can be used to load the sequence if
- * desired
- * @param ds
- * the DataSource
- * @param seqName
- * the name of the sequence
- * @param batchSize
- * the number of sequences that should be loaded
- */
- public IdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds,
- String seqName, int batchSize) {
-
- return null;
- }
-
- /**
- * Return the DbEncrypt handler for this DB platform.
- */
- public DbEncrypt getDbEncrypt() {
- return dbEncrypt;
- }
-
- /**
- * Set the DbEncrypt handler for this DB platform.
- */
- public void setDbEncrypt(DbEncrypt dbEncrypt) {
- this.dbEncrypt = dbEncrypt;
- }
-
- /**
- * Return the mapping of JDBC to DB types.
- *
- * @return the db type map
- */
- public DbTypeMap getDbTypeMap() {
- return dbTypeMap;
- }
-
- /**
- * Return the DDL syntax for this platform.
- *
- * @return the db ddl syntax
- */
- public DbDdlSyntax getDbDdlSyntax() {
- return dbDdlSyntax;
- }
-
- /**
- * Return the column alias prefix.
- */
- public String getColumnAliasPrefix() {
- return columnAliasPrefix;
- }
-
- /**
- * Set the column alias prefix.
- */
- public void setColumnAliasPrefix(String columnAliasPrefix) {
- this.columnAliasPrefix = columnAliasPrefix;
- }
-
- /**
- * Return the table alias placeholder.
- */
- public String getTableAliasPlaceHolder() {
- return tableAliasPlaceHolder;
- }
-
- /**
- * Set the table alias placeholder.
- */
- public void setTableAliasPlaceHolder(String tableAliasPlaceHolder) {
- this.tableAliasPlaceHolder = tableAliasPlaceHolder;
- }
-
- /**
- * Return the close quote for quoted identifiers.
- *
- * @return the close quote
- */
- public String getCloseQuote() {
- return closeQuote;
- }
-
- /**
- * Return the open quote for quoted identifiers.
- *
- * @return the open quote
- */
- public String getOpenQuote() {
- return openQuote;
- }
-
- /**
- * Return the JDBC type used to store booleans.
- *
- * @return the boolean db type
- */
- public int getBooleanDbType() {
- return booleanDbType;
- }
-
- /**
- * Return the data type that should be used for Blob.
- *
- * This is typically Types.BLOB but for Postgres is Types.LONGVARBINARY for
- * example.
- *
- */
- public int getBlobDbType() {
- return blobDbType;
- }
-
- /**
- * Return the data type that should be used for Clob.
- *
- * This is typically Types.CLOB but for Postgres is Types.VARCHAR.
- *
- */
- public int getClobDbType() {
- return clobDbType;
- }
-
- /**
- * Return true if empty strings should be treated as null.
- *
- * @return true, if checks if is treat empty strings as null
- */
- public boolean isTreatEmptyStringsAsNull() {
- return treatEmptyStringsAsNull;
- }
-
- /**
- * Return true if a compound ID in (...) type expression needs to be in
- * expanded form of (a=? and b=?) or (a=? and b=?) or ... rather than (a,b) in
- * ((?,?),(?,?),...);
- */
- public boolean isIdInExpandedForm() {
- return idInExpandedForm;
- }
-
- /**
- * Return true if the ResultSet TYPE_FORWARD_ONLY Hint should be used on
- * findIterate() and findVisit() PreparedStatements.
- *
- * This specifically is required for MySql when processing large results.
- *
- */
- public boolean isForwardOnlyHintOnFindIterate() {
- return forwardOnlyHintOnFindIterate;
- }
-
- /**
- * Set to true if the ResultSet TYPE_FORWARD_ONLY Hint should be used by default on findIterate PreparedStatements.
- */
- public void setForwardOnlyHintOnFindIterate(boolean forwardOnlyHintOnFindIterate) {
- this.forwardOnlyHintOnFindIterate = forwardOnlyHintOnFindIterate;
- }
-
- /**
- * Return the DB identity/sequence features for this platform.
- *
- * @return the db identity
- */
- public DbIdentity getDbIdentity() {
- return dbIdentity;
- }
-
- /**
- * Return the SqlLimiter used to apply additional sql around a query to limit
- * its results.
- *
- * Basically add the clauses for limit/offset, rownum, row_number().
- *
- *
- * @return the sql limiter
- */
- public SqlLimiter getSqlLimiter() {
- return sqlLimiter;
- }
-
- /**
- * Convert backticks to the platform specific open quote and close quote
- *
- *
- * Specific plugins may implement this method to cater for platform specific
- * naming rules.
- *
- *
- * @param dbName
- * the db name
- *
- * @return the string
- */
- public String convertQuotedIdentifiers(String dbName) {
- // Ignore null values e.g. schema name or catalog
- if (dbName != null && dbName.length() > 0) {
- if (dbName.charAt(0) == BACK_TICK) {
- if (dbName.charAt(dbName.length() - 1) == BACK_TICK) {
-
- String quotedName = getOpenQuote();
- quotedName += dbName.substring(1, dbName.length() - 1);
- quotedName += getCloseQuote();
-
- return quotedName;
-
- } else {
- logger.error("Missing backquote on [" + dbName + "]");
- }
- }
- }
- return dbName;
- }
-
- /**
- * Set to true if select count against anonymous view requires an alias.
- */
- public boolean isSelectCountWithAlias() {
- return selectCountWithAlias;
- }
-
- public String completeSql(String sql, Query> query) {
- if (Boolean.TRUE.equals(query.isForUpdate())) {
- sql = withForUpdate(sql);
- }
-
- return sql;
- }
-
- protected String withForUpdate(String sql) {
- // 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;
- }
-
- /**
- * Returns the like clause used by this database platform.
- *
- * This may include an escape clause to disable a default escape character.
- */
- public String getLikeClause() {
- return likeClause;
- }
-
- /**
- * Return true if the persistBatchOnCascade setting should be ignored.
- *
- * This is primarily for SQL Server which does not support getGeneratedKeys with jdbc batch mode
- * so can't really be transparently used.
- *
- */
- public boolean isDisallowBatchOnCascade() {
- return disallowBatchOnCascade;
- }
-}
+package com.avaje.ebean.config.dbplatform;
+
+import java.sql.Types;
+
+import javax.sql.DataSource;
+
+import com.avaje.ebean.BackgroundExecutor;
+import com.avaje.ebean.Query;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Database platform specific settings.
+ */
+public class DatabasePlatform {
+
+ private static final Logger logger = LoggerFactory.getLogger(DatabasePlatform.class);
+
+ /**
+ * Behavior used when ending a query only transaction (at read committed isolation level).
+ */
+ public enum OnQueryOnly {
+
+ /**
+ * Rollback the transaction.
+ */
+ ROLLBACK,
+
+ /**
+ * Just close the transaction. Valid at READ_COMMITTED isolation and preferred on some Databases
+ * as a performance optimisation.
+ */
+ CLOSE,
+
+ /**
+ * Commit the transaction
+ */
+ COMMIT
+ }
+
+ /**
+ * The behaviour used when ending a read only transaction at read committed isolation level.
+ */
+ protected OnQueryOnly onQueryOnly = OnQueryOnly.ROLLBACK;
+
+ /**
+ * The open quote used by quoted identifiers.
+ */
+ protected String openQuote = "\"";
+
+ /**
+ * The close quote used by quoted identifiers.
+ */
+ protected String closeQuote = "\"";
+
+ /**
+ * For limit/offset, row_number etc limiting of SQL queries.
+ */
+ protected SqlLimiter sqlLimiter = new LimitOffsetSqlLimiter();
+
+ /**
+ * Mapping of JDBC to Database types.
+ */
+ protected DbTypeMap dbTypeMap = new DbTypeMap();
+
+ /**
+ * DB specific DDL syntax.
+ */
+ protected DbDdlSyntax dbDdlSyntax = new DbDdlSyntax();
+
+ /**
+ * Defines DB identity/sequence features.
+ */
+ protected DbIdentity dbIdentity = new DbIdentity();
+
+ /**
+ * The JDBC type to map booleans to (by default).
+ */
+ protected int booleanDbType = Types.BOOLEAN;
+
+ /**
+ * The JDBC type to map Blob to.
+ */
+ protected int blobDbType = Types.BLOB;
+
+ /**
+ * The JDBC type to map Clob to.
+ */
+ protected int clobDbType = Types.CLOB;
+
+ /**
+ * For Oracle treat empty strings as null.
+ */
+ protected boolean treatEmptyStringsAsNull;
+
+ /**
+ * The database platform name.
+ */
+ protected String name = "generic";
+
+ protected String columnAliasPrefix = "c";
+
+ protected String tableAliasPlaceHolder = "${ta}";
+
+ /**
+ * Use a BackTick ` at the beginning and end of table or column names that you
+ * want to use quoted identifiers for. The backticks get converted to the
+ * appropriate characters in convertQuotedIdentifiers
+ */
+ private static final char BACK_TICK = '`';
+
+ /**
+ * The like clause. Can be overridden to disable default escape character.
+ */
+ protected String likeClause = "like ?";
+
+ protected DbEncrypt dbEncrypt;
+
+ protected boolean idInExpandedForm;
+
+ protected boolean selectCountWithAlias;
+
+ /**
+ * If set then use the FORWARD ONLY hint when creating ResultSets for
+ * findIterate() and findVisit().
+ */
+ protected boolean forwardOnlyHintOnFindIterate;
+
+ /**
+ * Flag set for SQL Server due to lack of support of getGeneratedKeys in
+ * batch mode (meaning for batch inserts you should explicitly turn off
+ * getGeneratedKeys - joy).
+ */
+ protected boolean disallowBatchOnCascade;
+
+ /**
+ * Instantiates a new database platform.
+ */
+ public DatabasePlatform() {
+ }
+
+ /**
+ * Return the name of the DatabasePlatform.
+ *
+ * "generic" is returned when no specific database platform has been set or
+ * found.
+ *
+ *
+ * @return the name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Return a DB Sequence based IdGenerator.
+ *
+ * @param be
+ * the BackgroundExecutor that can be used to load the sequence if
+ * desired
+ * @param ds
+ * the DataSource
+ * @param seqName
+ * the name of the sequence
+ * @param batchSize
+ * the number of sequences that should be loaded
+ */
+ public IdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds, String seqName, int batchSize) {
+ return null;
+ }
+
+ /**
+ * Return the behaviour to use when ending a read only transaction.
+ */
+ public OnQueryOnly getOnQueryOnly() {
+ return onQueryOnly;
+ }
+
+ /**
+ * Set the behaviour to use when ending a read only transaction.
+ */
+ public void setOnQueryOnly(OnQueryOnly onQueryOnly) {
+ this.onQueryOnly = onQueryOnly;
+ }
+
+ /**
+ * Return the DbEncrypt handler for this DB platform.
+ */
+ public DbEncrypt getDbEncrypt() {
+ return dbEncrypt;
+ }
+
+ /**
+ * Set the DbEncrypt handler for this DB platform.
+ */
+ public void setDbEncrypt(DbEncrypt dbEncrypt) {
+ this.dbEncrypt = dbEncrypt;
+ }
+
+ /**
+ * Return the mapping of JDBC to DB types.
+ *
+ * @return the db type map
+ */
+ public DbTypeMap getDbTypeMap() {
+ return dbTypeMap;
+ }
+
+ /**
+ * Return the DDL syntax for this platform.
+ *
+ * @return the db ddl syntax
+ */
+ public DbDdlSyntax getDbDdlSyntax() {
+ return dbDdlSyntax;
+ }
+
+ /**
+ * Return the column alias prefix.
+ */
+ public String getColumnAliasPrefix() {
+ return columnAliasPrefix;
+ }
+
+ /**
+ * Set the column alias prefix.
+ */
+ public void setColumnAliasPrefix(String columnAliasPrefix) {
+ this.columnAliasPrefix = columnAliasPrefix;
+ }
+
+ /**
+ * Return the table alias placeholder.
+ */
+ public String getTableAliasPlaceHolder() {
+ return tableAliasPlaceHolder;
+ }
+
+ /**
+ * Set the table alias placeholder.
+ */
+ public void setTableAliasPlaceHolder(String tableAliasPlaceHolder) {
+ this.tableAliasPlaceHolder = tableAliasPlaceHolder;
+ }
+
+ /**
+ * Return the close quote for quoted identifiers.
+ *
+ * @return the close quote
+ */
+ public String getCloseQuote() {
+ return closeQuote;
+ }
+
+ /**
+ * Return the open quote for quoted identifiers.
+ *
+ * @return the open quote
+ */
+ public String getOpenQuote() {
+ return openQuote;
+ }
+
+ /**
+ * Return the JDBC type used to store booleans.
+ *
+ * @return the boolean db type
+ */
+ public int getBooleanDbType() {
+ return booleanDbType;
+ }
+
+ /**
+ * Return the data type that should be used for Blob.
+ *
+ * This is typically Types.BLOB but for Postgres is Types.LONGVARBINARY for
+ * example.
+ *
+ */
+ public int getBlobDbType() {
+ return blobDbType;
+ }
+
+ /**
+ * Return the data type that should be used for Clob.
+ *
+ * This is typically Types.CLOB but for Postgres is Types.VARCHAR.
+ *
+ */
+ public int getClobDbType() {
+ return clobDbType;
+ }
+
+ /**
+ * Return true if empty strings should be treated as null.
+ *
+ * @return true, if checks if is treat empty strings as null
+ */
+ public boolean isTreatEmptyStringsAsNull() {
+ return treatEmptyStringsAsNull;
+ }
+
+ /**
+ * Return true if a compound ID in (...) type expression needs to be in
+ * expanded form of (a=? and b=?) or (a=? and b=?) or ... rather than (a,b) in
+ * ((?,?),(?,?),...);
+ */
+ public boolean isIdInExpandedForm() {
+ return idInExpandedForm;
+ }
+
+ /**
+ * Return true if the ResultSet TYPE_FORWARD_ONLY Hint should be used on
+ * findIterate() and findVisit() PreparedStatements.
+ *
+ * This specifically is required for MySql when processing large results.
+ *
+ */
+ public boolean isForwardOnlyHintOnFindIterate() {
+ return forwardOnlyHintOnFindIterate;
+ }
+
+ /**
+ * Set to true if the ResultSet TYPE_FORWARD_ONLY Hint should be used by default on findIterate PreparedStatements.
+ */
+ public void setForwardOnlyHintOnFindIterate(boolean forwardOnlyHintOnFindIterate) {
+ this.forwardOnlyHintOnFindIterate = forwardOnlyHintOnFindIterate;
+ }
+
+ /**
+ * Return the DB identity/sequence features for this platform.
+ *
+ * @return the db identity
+ */
+ public DbIdentity getDbIdentity() {
+ return dbIdentity;
+ }
+
+ /**
+ * Return the SqlLimiter used to apply additional sql around a query to limit
+ * its results.
+ *
+ * Basically add the clauses for limit/offset, rownum, row_number().
+ *
+ *
+ * @return the sql limiter
+ */
+ public SqlLimiter getSqlLimiter() {
+ return sqlLimiter;
+ }
+
+ /**
+ * Convert backticks to the platform specific open quote and close quote
+ *
+ *
+ * Specific plugins may implement this method to cater for platform specific
+ * naming rules.
+ *
+ *
+ * @param dbName
+ * the db name
+ *
+ * @return the string
+ */
+ public String convertQuotedIdentifiers(String dbName) {
+ // Ignore null values e.g. schema name or catalog
+ if (dbName != null && dbName.length() > 0) {
+ if (dbName.charAt(0) == BACK_TICK) {
+ if (dbName.charAt(dbName.length() - 1) == BACK_TICK) {
+
+ String quotedName = getOpenQuote();
+ quotedName += dbName.substring(1, dbName.length() - 1);
+ quotedName += getCloseQuote();
+
+ return quotedName;
+
+ } else {
+ logger.error("Missing backquote on [" + dbName + "]");
+ }
+ }
+ }
+ return dbName;
+ }
+
+ /**
+ * Set to true if select count against anonymous view requires an alias.
+ */
+ public boolean isSelectCountWithAlias() {
+ return selectCountWithAlias;
+ }
+
+ public String completeSql(String sql, Query> query) {
+ if (Boolean.TRUE.equals(query.isForUpdate())) {
+ sql = withForUpdate(sql);
+ }
+
+ return sql;
+ }
+
+ protected String withForUpdate(String sql) {
+ // 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;
+ }
+
+ /**
+ * Returns the like clause used by this database platform.
+ *
+ * This may include an escape clause to disable a default escape character.
+ */
+ public String getLikeClause() {
+ return likeClause;
+ }
+
+ /**
+ * Return true if the persistBatchOnCascade setting should be ignored.
+ *
+ * This is primarily for SQL Server which does not support getGeneratedKeys with jdbc batch mode
+ * so can't really be transparently used.
+ *
+ */
+ public boolean isDisallowBatchOnCascade() {
+ return disallowBatchOnCascade;
+ }
+}
diff --git a/src/main/java/com/avaje/ebean/config/dbplatform/Oracle10Platform.java b/src/main/java/com/avaje/ebean/config/dbplatform/Oracle10Platform.java
index 796e69327..fa1731de9 100644
--- a/src/main/java/com/avaje/ebean/config/dbplatform/Oracle10Platform.java
+++ b/src/main/java/com/avaje/ebean/config/dbplatform/Oracle10Platform.java
@@ -1,67 +1,68 @@
-package com.avaje.ebean.config.dbplatform;
-
-import com.avaje.ebean.BackgroundExecutor;
-
-import javax.sql.DataSource;
-import java.sql.Types;
-
-/**
- * Oracle10 and greater specific platform.
- */
-public class Oracle10Platform extends DatabasePlatform {
-
- public Oracle10Platform() {
- super();
- this.name = "oracle";
- this.dbEncrypt = new Oracle10DbEncrypt();
-
- this.sqlLimiter = new RownumSqlLimiter();
-
- // Not using getGeneratedKeys as instead we will
- // batch load sequences which enables JDBC batch execution
- dbIdentity.setSupportsGetGeneratedKeys(false);
- dbIdentity.setIdType(IdType.SEQUENCE);
- dbIdentity.setSupportsSequence(true);
-
- this.treatEmptyStringsAsNull = true;
-
- this.openQuote = "\"";
- this.closeQuote = "\"";
-
- booleanDbType = Types.INTEGER;
- dbTypeMap.put(Types.BOOLEAN, new DbType("number(1) default 0"));
-
- dbTypeMap.put(Types.INTEGER, new DbType("number", 10));
- dbTypeMap.put(Types.BIGINT, new DbType("number", 19));
- dbTypeMap.put(Types.REAL, new DbType("number", 19, 4));
- dbTypeMap.put(Types.DOUBLE, new DbType("number", 19, 4));
- dbTypeMap.put(Types.SMALLINT, new DbType("number", 5));
- dbTypeMap.put(Types.TINYINT, new DbType("number", 3));
- dbTypeMap.put(Types.DECIMAL, new DbType("number", 38));
-
- dbTypeMap.put(Types.VARCHAR, new DbType("varchar2", 255));
-
- dbTypeMap.put(Types.LONGVARBINARY, new DbType("blob"));
- dbTypeMap.put(Types.LONGVARCHAR, new DbType("clob"));
- dbTypeMap.put(Types.VARBINARY, new DbType("raw", 255));
- dbTypeMap.put(Types.BINARY, new DbType("raw", 255));
-
- dbTypeMap.put(Types.TIME, new DbType("timestamp"));
-
- dbDdlSyntax.setDropTableCascade("cascade constraints purge");
- dbDdlSyntax.setIdentity(null);
- dbDdlSyntax.setMaxConstraintNameLength(30);
- }
-
- @Override
- public IdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds,
- String seqName, int batchSize) {
-
- return new OracleSequenceIdGenerator(be, ds, seqName, batchSize);
- }
-
- @Override
- protected String withForUpdate(String sql) {
- return sql + " for update";
- }
-}
+package com.avaje.ebean.config.dbplatform;
+
+import com.avaje.ebean.BackgroundExecutor;
+
+import javax.sql.DataSource;
+import java.sql.Types;
+
+/**
+ * Oracle10 and greater specific platform.
+ */
+public class Oracle10Platform extends DatabasePlatform {
+
+ public Oracle10Platform() {
+ super();
+ this.name = "oracle";
+ // OnQueryOnly.CLOSE as a performance optimisation on Oracle
+ this.onQueryOnly = OnQueryOnly.CLOSE;
+ this.dbEncrypt = new Oracle10DbEncrypt();
+ this.sqlLimiter = new RownumSqlLimiter();
+
+ // Not using getGeneratedKeys as instead we will
+ // batch load sequences which enables JDBC batch execution
+ dbIdentity.setSupportsGetGeneratedKeys(false);
+ dbIdentity.setIdType(IdType.SEQUENCE);
+ dbIdentity.setSupportsSequence(true);
+
+ this.treatEmptyStringsAsNull = true;
+
+ this.openQuote = "\"";
+ this.closeQuote = "\"";
+
+ booleanDbType = Types.INTEGER;
+ dbTypeMap.put(Types.BOOLEAN, new DbType("number(1) default 0"));
+
+ dbTypeMap.put(Types.INTEGER, new DbType("number", 10));
+ dbTypeMap.put(Types.BIGINT, new DbType("number", 19));
+ dbTypeMap.put(Types.REAL, new DbType("number", 19, 4));
+ dbTypeMap.put(Types.DOUBLE, new DbType("number", 19, 4));
+ dbTypeMap.put(Types.SMALLINT, new DbType("number", 5));
+ dbTypeMap.put(Types.TINYINT, new DbType("number", 3));
+ dbTypeMap.put(Types.DECIMAL, new DbType("number", 38));
+
+ dbTypeMap.put(Types.VARCHAR, new DbType("varchar2", 255));
+
+ dbTypeMap.put(Types.LONGVARBINARY, new DbType("blob"));
+ dbTypeMap.put(Types.LONGVARCHAR, new DbType("clob"));
+ dbTypeMap.put(Types.VARBINARY, new DbType("raw", 255));
+ dbTypeMap.put(Types.BINARY, new DbType("raw", 255));
+
+ dbTypeMap.put(Types.TIME, new DbType("timestamp"));
+
+ dbDdlSyntax.setDropTableCascade("cascade constraints purge");
+ dbDdlSyntax.setIdentity(null);
+ dbDdlSyntax.setMaxConstraintNameLength(30);
+ }
+
+ @Override
+ public IdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds,
+ String seqName, int batchSize) {
+
+ return new OracleSequenceIdGenerator(be, ds, seqName, batchSize);
+ }
+
+ @Override
+ protected String withForUpdate(String sql) {
+ return sql + " for update";
+ }
+}
diff --git a/src/main/java/com/avaje/ebean/config/dbplatform/PostgresPlatform.java b/src/main/java/com/avaje/ebean/config/dbplatform/PostgresPlatform.java
index 08fa91546..021e30bb4 100644
--- a/src/main/java/com/avaje/ebean/config/dbplatform/PostgresPlatform.java
+++ b/src/main/java/com/avaje/ebean/config/dbplatform/PostgresPlatform.java
@@ -1,78 +1,80 @@
-package com.avaje.ebean.config.dbplatform;
-
-import com.avaje.ebean.BackgroundExecutor;
-
-import javax.sql.DataSource;
-import java.sql.Types;
-
-/**
- * Postgres v9 specific platform.
- *
- * Uses serial types and getGeneratedKeys.
- *
- */
-public class PostgresPlatform extends DatabasePlatform {
-
- /**
- * Unique jdbc type id defined for hstore type.
- */
- public static final int TYPE_HSTORE = 4001;
-
- public PostgresPlatform() {
- super();
- this.name = "postgres";
- this.likeClause = "like ? escape''";
-
- this.dbDdlSyntax = new PostgresDdlSyntax();
-
- this.selectCountWithAlias = true;
- this.blobDbType = Types.LONGVARBINARY;
- this.clobDbType = Types.VARCHAR;
-
- this.dbEncrypt = new PostgresDbEncrypt();
-
- // Use Identity and getGeneratedKeys
- this.dbIdentity.setIdType(IdType.IDENTITY);
- this.dbIdentity.setSupportsGetGeneratedKeys(true);
- this.dbIdentity.setSupportsSequence(true);
-
- this.columnAliasPrefix = "as c";
-
- this.openQuote = "\"";
- this.closeQuote = "\"";
-
- dbTypeMap.put(TYPE_HSTORE, new DbType("hstore"));
-
- dbTypeMap.put(Types.INTEGER, new DbType("integer", false));
- dbTypeMap.put(Types.DOUBLE, new DbType("float"));
- dbTypeMap.put(Types.TINYINT, new DbType("smallint"));
- dbTypeMap.put(Types.DECIMAL, new DbType("decimal", 38));
-
- dbTypeMap.put(Types.BINARY, new DbType("bytea", false));
- dbTypeMap.put(Types.VARBINARY, new DbType("bytea", false));
-
- dbTypeMap.put(Types.BLOB, new DbType("bytea", false));
- dbTypeMap.put(Types.CLOB, new DbType("text"));
- dbTypeMap.put(Types.LONGVARBINARY, new DbType("bytea", false));
- dbTypeMap.put(Types.LONGVARCHAR, new DbType("text"));
-
- dbDdlSyntax.setDropTableCascade("cascade");
- dbDdlSyntax.setDropIfExists("if exists");
-
- }
-
- /**
- * Create a Postgres specific sequence IdGenerator.
- */
- @Override
- public IdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds,
- String seqName, int batchSize) {
-
- return new PostgresSequenceIdGenerator(be, ds, seqName, batchSize);
- }
-
- @Override
- protected String withForUpdate(String sql) {
- return sql + " for update";
- }
-}
+package com.avaje.ebean.config.dbplatform;
+
+import com.avaje.ebean.BackgroundExecutor;
+
+import javax.sql.DataSource;
+import java.sql.Types;
+
+/**
+ * Postgres v9 specific platform.
+ *
+ * Uses serial types and getGeneratedKeys.
+ *
+ */
+public class PostgresPlatform extends DatabasePlatform {
+
+ /**
+ * Unique jdbc type id defined for hstore type.
+ */
+ public static final int TYPE_HSTORE = 4001;
+
+ public PostgresPlatform() {
+ super();
+ this.name = "postgres";
+ // OnQueryOnly.CLOSE as a performance optimisation on Postgres
+ this.onQueryOnly = OnQueryOnly.CLOSE;
+ this.likeClause = "like ? escape''";
+
+ this.dbDdlSyntax = new PostgresDdlSyntax();
+
+ this.selectCountWithAlias = true;
+ this.blobDbType = Types.LONGVARBINARY;
+ this.clobDbType = Types.VARCHAR;
+
+ this.dbEncrypt = new PostgresDbEncrypt();
+
+ // Use Identity and getGeneratedKeys
+ this.dbIdentity.setIdType(IdType.IDENTITY);
+ this.dbIdentity.setSupportsGetGeneratedKeys(true);
+ this.dbIdentity.setSupportsSequence(true);
+
+ this.columnAliasPrefix = "as c";
+
+ this.openQuote = "\"";
+ this.closeQuote = "\"";
+
+ dbTypeMap.put(TYPE_HSTORE, new DbType("hstore"));
+
+ dbTypeMap.put(Types.INTEGER, new DbType("integer", false));
+ dbTypeMap.put(Types.DOUBLE, new DbType("float"));
+ dbTypeMap.put(Types.TINYINT, new DbType("smallint"));
+ dbTypeMap.put(Types.DECIMAL, new DbType("decimal", 38));
+
+ dbTypeMap.put(Types.BINARY, new DbType("bytea", false));
+ dbTypeMap.put(Types.VARBINARY, new DbType("bytea", false));
+
+ dbTypeMap.put(Types.BLOB, new DbType("bytea", false));
+ dbTypeMap.put(Types.CLOB, new DbType("text"));
+ dbTypeMap.put(Types.LONGVARBINARY, new DbType("bytea", false));
+ dbTypeMap.put(Types.LONGVARCHAR, new DbType("text"));
+
+ dbDdlSyntax.setDropTableCascade("cascade");
+ dbDdlSyntax.setDropIfExists("if exists");
+
+ }
+
+ /**
+ * Create a Postgres specific sequence IdGenerator.
+ */
+ @Override
+ public IdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds,
+ String seqName, int batchSize) {
+
+ return new PostgresSequenceIdGenerator(be, ds, seqName, batchSize);
+ }
+
+ @Override
+ protected String withForUpdate(String sql) {
+ return sql + " for update";
+ }
+}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/transaction/JdbcTransaction.java b/src/main/java/com/avaje/ebeaninternal/server/transaction/JdbcTransaction.java
index 39812210a..64ea8167e 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/transaction/JdbcTransaction.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/transaction/JdbcTransaction.java
@@ -1,956 +1,956 @@
-package com.avaje.ebeaninternal.server.transaction;
-
-import com.avaje.ebean.TransactionCallback;
-import com.avaje.ebean.bean.PersistenceContext;
-import com.avaje.ebean.config.PersistBatch;
-import com.avaje.ebeaninternal.api.DerivedRelationshipData;
-import com.avaje.ebeaninternal.api.SpiTransaction;
-import com.avaje.ebeaninternal.api.TransactionEvent;
-import com.avaje.ebeaninternal.server.core.PersistRequest;
-import com.avaje.ebeaninternal.server.core.PersistRequestBean;
-import com.avaje.ebeaninternal.server.lib.util.Str;
-import com.avaje.ebeaninternal.server.persist.BatchControl;
-import com.avaje.ebeaninternal.server.transaction.TransactionManager.OnQueryOnly;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.persistence.PersistenceException;
-import javax.persistence.RollbackException;
-import java.io.IOException;
-import java.sql.Connection;
-import java.sql.SQLException;
-import java.util.*;
-
-/**
- * JDBC Connection based transaction.
- */
-public class JdbcTransaction implements SpiTransaction {
-
- private static final Logger logger = LoggerFactory.getLogger(JdbcTransaction.class);
-
- private static final Object PLACEHOLDER = new Object();
-
- private static final String illegalStateMessage = "Transaction is Inactive";
-
- /**
- * The associated TransactionManager.
- */
- protected final TransactionManager manager;
-
- /**
- * The transaction id.
- */
- protected final String id;
-
- /**
- * Flag to indicate if this was an explicitly created Transaction.
- */
- protected final boolean explicit;
-
- /**
- * Behaviour for ending query only transactions.
- */
- protected final OnQueryOnly onQueryOnly;
-
- /**
- * The status of the transaction.
- */
- protected boolean active;
-
- /**
- * The underlying Connection.
- */
- protected Connection connection;
-
- /**
- * Used to queue up persist requests for batch execution.
- */
- protected BatchControl batchControl;
-
- /**
- * The event which holds persisted beans.
- */
- protected TransactionEvent event;
-
- /**
- * Holder of the objects fetched to ensure unique objects are used.
- */
- protected PersistenceContext persistenceContext;
-
- /**
- * Used to give developers more control over the insert update and delete
- * functionality.
- */
- protected boolean persistCascade = true;
-
- /**
- * Flag used for performance to skip commit or rollback of query only
- * transactions in read committed transaction isolation.
- */
- protected boolean queryOnly = true;
-
- protected boolean localReadOnly;
-
- protected PersistBatch oldBatchMode;
-
- protected PersistBatch batchMode;
-
- protected PersistBatch batchOnCascadeMode;
-
- protected int batchSize = -1;
-
- protected boolean batchFlushOnQuery = true;
-
- protected Boolean batchGetGeneratedKeys;
-
- protected Boolean batchFlushOnMixed;
-
- protected String logPrefix;
-
- /**
- * The depth used by batch processing to help the ordering of statements.
- */
- protected int depth;
-
- /**
- * Set to true if the connection has autoCommit=true initially.
- */
- protected final boolean autoCommit;
-
- protected IdentityHashMap