diff --git a/src/main/java/com/avaje/ebean/config/dbplatform/DbHistorySupport.java b/src/main/java/com/avaje/ebean/config/dbplatform/DbHistorySupport.java index c61cd0bc6..a8127ac4f 100644 --- a/src/main/java/com/avaje/ebean/config/dbplatform/DbHistorySupport.java +++ b/src/main/java/com/avaje/ebean/config/dbplatform/DbHistorySupport.java @@ -5,6 +5,14 @@ package com.avaje.ebean.config.dbplatform; */ public interface DbHistorySupport { + /** + * Return the number of columns bound in a 'As Of' predicate. + *
+ * Typically this is 2 but 1 for postgres using it's range type. + *
+ */ + int getBindCount(); + /** * Return the 'as of' predicate added for the given table alias. * diff --git a/src/main/java/com/avaje/ebean/config/dbplatform/MySqlHistorySupport.java b/src/main/java/com/avaje/ebean/config/dbplatform/MySqlHistorySupport.java new file mode 100644 index 000000000..cc36972ef --- /dev/null +++ b/src/main/java/com/avaje/ebean/config/dbplatform/MySqlHistorySupport.java @@ -0,0 +1,35 @@ +package com.avaje.ebean.config.dbplatform; + +/** + * Runtime support for @History with MySql. + */ +public class MySqlHistorySupport implements DbHistorySupport { + + @Override + public int getBindCount() { + return 2; + } + + @Override + public String getAsOfPredicate(String asOfTableAlias, String asOfSysPeriod) { + + StringBuilder sb = new StringBuilder(90); + sb.append("("); + sb.append(asOfTableAlias).append(".").append(asOfSysPeriod).append("_start").append(" < ? and ("); + sb.append(asOfTableAlias).append(".").append(asOfSysPeriod).append("_end").append(" is null or "); + sb.append(asOfTableAlias).append(".").append(asOfSysPeriod).append("_end").append(" > ?))"); + + // (sys_period_start < ? and (sys_period_end is null or sys_period_end > ?)); + return sb.toString(); + } + + @Override + public String getSysPeriodLower(String tableAlias, String sysPeriod) { + return tableAlias+"."+sysPeriod+"_start"; + } + + @Override + public String getSysPeriodUpper(String tableAlias, String sysPeriod) { + return tableAlias+"."+sysPeriod+"_end"; + } +} diff --git a/src/main/java/com/avaje/ebean/config/dbplatform/MySqlPlatform.java b/src/main/java/com/avaje/ebean/config/dbplatform/MySqlPlatform.java index 1948c617d..54edd3d7b 100644 --- a/src/main/java/com/avaje/ebean/config/dbplatform/MySqlPlatform.java +++ b/src/main/java/com/avaje/ebean/config/dbplatform/MySqlPlatform.java @@ -26,6 +26,7 @@ public class MySqlPlatform extends DatabasePlatform { this.selectCountWithAlias = true; this.dbEncrypt = new MySqlDbEncrypt(); this.platformDdl = new MySqlDdl(this.dbTypeMap, this.dbIdentity); + this.historySupport = new MySqlHistorySupport(); this.dbIdentity.setIdType(IdType.IDENTITY); this.dbIdentity.setSupportsGetGeneratedKeys(true); @@ -45,7 +46,6 @@ public class MySqlPlatform extends DatabasePlatform { dbTypeMap.put(Types.BLOB, new MySqlBlob()); dbTypeMap.put(Types.BINARY, new DbType("binary", 255)); dbTypeMap.put(Types.VARBINARY, new DbType("varbinary", 255)); - } /** diff --git a/src/main/java/com/avaje/ebean/config/dbplatform/PostgresHistorySupport.java b/src/main/java/com/avaje/ebean/config/dbplatform/PostgresHistorySupport.java index 5a99fdb5d..5357a7fe8 100644 --- a/src/main/java/com/avaje/ebean/config/dbplatform/PostgresHistorySupport.java +++ b/src/main/java/com/avaje/ebean/config/dbplatform/PostgresHistorySupport.java @@ -5,6 +5,14 @@ package com.avaje.ebean.config.dbplatform; */ public class PostgresHistorySupport implements DbHistorySupport { + /** + * Return 1 as we are using the range type and hence don't need 2 bind variables. + */ + @Override + public int getBindCount() { + return 1; + } + /** * Build and return the 'as of' predicate for a given table alias. *diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/InternalConfiguration.java b/src/main/java/com/avaje/ebeaninternal/server/core/InternalConfiguration.java index d14059375..ec63c87a0 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/core/InternalConfiguration.java +++ b/src/main/java/com/avaje/ebeaninternal/server/core/InternalConfiguration.java @@ -2,6 +2,7 @@ package com.avaje.ebeaninternal.server.core; import javax.sql.DataSource; +import com.avaje.ebean.config.dbplatform.DbHistorySupport; import com.avaje.ebeaninternal.server.deploy.generatedproperty.GeneratedPropertyFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -106,7 +107,6 @@ public class InternalConfiguration { this.expressionFactory = new DefaultExpressionFactory(serverConfig.isExpressionEqualsWithNullAsNoop()); this.typeManager = new DefaultTypeManager(serverConfig, bootupClasses); - this.binder = new Binder(typeManager); this.resourceManager = ResourceManagerFactory.createResourceManager(serverConfig); this.deployOrmXml = new DeployOrmXml(resourceManager.getResourceSource()); @@ -120,7 +120,10 @@ public class InternalConfiguration { this.transactionManager = createTransactionManager(); - this.cQueryEngine = new CQueryEngine(serverConfig.getDatabasePlatform(), binder, asOfTableMapping, serverConfig.getAsOfSysPeriod()); + DatabasePlatform databasePlatform = serverConfig.getDatabasePlatform(); + + this.binder = new Binder(typeManager, getAsOfBindCount(databasePlatform)); + this.cQueryEngine = new CQueryEngine(databasePlatform, binder, asOfTableMapping, serverConfig.getAsOfSysPeriod()); ExternalTransactionManager externalTransactionManager = serverConfig.getExternalTransactionManager(); if (externalTransactionManager == null && serverConfig.isUseJtaTransactionManager()) { @@ -135,7 +138,15 @@ public class InternalConfiguration { } } - + + /** + * For 'As Of' queries return the number of bind variables per predicate. + */ + private int getAsOfBindCount(DatabasePlatform databasePlatform) { + DbHistorySupport historySupport = databasePlatform.getHistorySupport(); + return historySupport == null ? 0 : historySupport.getBindCount(); + } + /** * Create the TransactionManager taking into account autoCommit mode. */ diff --git a/src/main/java/com/avaje/ebeaninternal/server/persist/Binder.java b/src/main/java/com/avaje/ebeaninternal/server/persist/Binder.java index d88c5cd88..ea28fd606 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/persist/Binder.java +++ b/src/main/java/com/avaje/ebeaninternal/server/persist/Binder.java @@ -26,11 +26,21 @@ public class Binder { private final TypeManager typeManager; + private final int asOfBindCount; + /** * Set the PreparedStatement with which to bind variables to. */ - public Binder(TypeManager typeManager) { + public Binder(TypeManager typeManager, int asOfBindCount) { this.typeManager = typeManager; + this.asOfBindCount = asOfBindCount; + } + + /** + * Return the bind count per predicate for 'As Of' query predicates. + */ + public int getAsOfBindCount() { + return asOfBindCount; } /** diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryPredicates.java b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryPredicates.java index 59889aea2..55532cd7b 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryPredicates.java +++ b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryPredicates.java @@ -172,7 +172,7 @@ public class CQueryPredicates { // there is one effective date predicate per table alias Timestamp asOf = query.getAsOf(); bindLog.append(" asOf ").append(asOf); - for (int i = 0; i < historyTableAlias.size(); i++) { + for (int i = 0; i < historyTableAlias.size() * binder.getAsOfBindCount(); i++) { binder.bindObject(dataBind, asOf); } }