diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/AbstractHANADialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/AbstractHANADialect.java index e55f772894..da5943b447 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/AbstractHANADialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/AbstractHANADialect.java @@ -41,9 +41,13 @@ import org.hibernate.dialect.function.NoArgSQLFunction; import org.hibernate.dialect.function.SQLFunctionTemplate; import org.hibernate.dialect.function.StandardSQLFunction; import org.hibernate.dialect.function.VarArgsSQLFunction; +import org.hibernate.dialect.pagination.AbstractLimitHandler; +import org.hibernate.dialect.pagination.LimitHandler; +import org.hibernate.dialect.pagination.LimitHelper; import org.hibernate.engine.jdbc.CharacterStream; import org.hibernate.engine.jdbc.ClobImplementer; import org.hibernate.engine.jdbc.NClobImplementer; +import org.hibernate.engine.spi.RowSelection; import org.hibernate.exception.ConstraintViolationException; import org.hibernate.exception.LockAcquisitionException; import org.hibernate.exception.LockTimeoutException; @@ -306,11 +310,6 @@ public abstract class AbstractHANADialect extends Dialect { getDefaultProperties().setProperty( AvailableSettings.NON_CONTEXTUAL_LOB_CREATION, "true" ); } - @Override - public boolean bindLimitParametersInReverseOrder() { - return true; - } - @Override public SQLExceptionConversionDelegate buildSQLExceptionConversionDelegate() { return new SQLExceptionConversionDelegate() { @@ -430,12 +429,6 @@ public abstract class AbstractHANADialect extends Dialect { return getForUpdateString( lockMode ) + " of " + aliases; } - @Override - public String getLimitString(final String sql, final boolean hasOffset) { - return new StringBuilder( sql.length() + 20 ).append( sql ) - .append( hasOffset ? " limit ? offset ?" : " limit ?" ).toString(); - } - @Override public String getNotExpression(final String expression) { return "not (" + expression + ")"; @@ -604,11 +597,6 @@ public abstract class AbstractHANADialect extends Dialect { return false; } - @Override - public boolean supportsLimit() { - return true; - } - @Override public boolean supportsPooledSequences() { return true; @@ -670,4 +658,26 @@ public abstract class AbstractHANADialect extends Dialect { final String referencedTable, final String[] primaryKey, final boolean referencesPrimaryKey) { return super.getAddForeignKeyConstraintString(constraintName, foreignKey, referencedTable, primaryKey, referencesPrimaryKey) + " on update cascade"; } + + @Override + public LimitHandler buildLimitHandler(String sql, RowSelection selection) { + return new AbstractLimitHandler(sql, selection) { + @Override + public String getProcessedSql() { + boolean hasOffset = LimitHelper.hasFirstRow(selection); + return new StringBuilder( sql.length() + 20 ).append( sql ) + .append( hasOffset ? " limit ? offset ?" : " limit ?" ).toString(); + } + + @Override + public boolean supportsLimit() { + return true; + } + + @Override + public boolean bindLimitParametersInReverseOrder() { + return true; + } + }; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/Cache71Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/Cache71Dialect.java index 747fe4b4e2..c3958d5e57 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/Cache71Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/Cache71Dialect.java @@ -46,6 +46,9 @@ import org.hibernate.dialect.lock.PessimisticReadUpdateLockingStrategy; import org.hibernate.dialect.lock.PessimisticWriteUpdateLockingStrategy; import org.hibernate.dialect.lock.SelectLockingStrategy; import org.hibernate.dialect.lock.UpdateLockingStrategy; +import org.hibernate.dialect.pagination.LimitHandler; +import org.hibernate.dialect.pagination.TopLimitHandler; +import org.hibernate.engine.spi.RowSelection; import org.hibernate.exception.internal.CacheSQLExceptionConversionDelegate; import org.hibernate.exception.spi.SQLExceptionConversionDelegate; import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtracter; @@ -583,53 +586,9 @@ public class Cache71Dialect extends Dialect { // LIMIT support (ala TOP) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @Override - @SuppressWarnings("deprecation") - public boolean supportsLimit() { - return true; - } - - @Override - @SuppressWarnings("deprecation") - public boolean supportsLimitOffset() { - return false; - } - - @Override - @SuppressWarnings("deprecation") - public boolean supportsVariableLimit() { - return true; - } - - @Override - @SuppressWarnings("deprecation") - public boolean bindLimitParametersFirst() { - // Does the LIMIT clause come at the start of the SELECT statement, rather than at the end? - return true; - } - - @Override - @SuppressWarnings("deprecation") - public boolean useMaxForLimit() { - // Does the LIMIT clause take a "maximum" row number instead of a total number of returned rows? - return true; - } - - @Override - @SuppressWarnings("deprecation") - public String getLimitString(String sql, boolean hasOffset) { - if ( hasOffset ) { - throw new UnsupportedOperationException( "query result offset is not supported" ); - } - - // This does not support the Cache SQL 'DISTINCT BY (comma-list)' extensions, - // but this extension is not supported through Hibernate anyway. - final int insertionPoint = sql.startsWith( "select distinct" ) ? 15 : 6; - - return new StringBuilder( sql.length() + 8 ) - .append( sql ) - .insert( insertionPoint, " TOP ? " ) - .toString(); - } + public LimitHandler buildLimitHandler(String sql, RowSelection selection) { + return new TopLimitHandler(sql, selection, true, true); + } // callable statement support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/DB2390Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/DB2390Dialect.java index d4fdf523a0..f320ca8948 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/DB2390Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/DB2390Dialect.java @@ -23,6 +23,11 @@ */ package org.hibernate.dialect; +import org.hibernate.dialect.pagination.AbstractLimitHandler; +import org.hibernate.dialect.pagination.LimitHandler; +import org.hibernate.dialect.pagination.LimitHelper; +import org.hibernate.engine.spi.RowSelection; + /** * An SQL dialect for DB2/390. This class provides support for @@ -42,35 +47,31 @@ public class DB2390Dialect extends DB2Dialect { } @Override - public boolean supportsLimit() { - return true; - } + public LimitHandler buildLimitHandler(String sql, RowSelection selection) { + return new AbstractLimitHandler(sql, selection) { + @Override + public String getProcessedSql() { + if ( LimitHelper.hasFirstRow(selection) ) { + throw new UnsupportedOperationException( "query result offset is not supported" ); + } + return sql + " fetch first ? rows only"; + } - @Override - @SuppressWarnings("deprecation") - public boolean supportsLimitOffset() { - return false; - } + @Override + public boolean supportsLimit() { + return true; + } - @Override - public boolean useMaxForLimit() { - return true; - } + @Override + public boolean useMaxForLimit() { + return true; + } - @Override - public boolean supportsVariableLimit() { - return false; - } - - @Override - public String getLimitString(String sql, int offset, int limit) { - if ( offset > 0 ) { - throw new UnsupportedOperationException( "query result offset is not supported" ); - } - if ( limit == 0 ) { - return sql; - } - return sql + " fetch first " + limit + " rows only "; - } + @Override + public boolean supportsVariableLimit() { + return false; + } + }; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/DB2400Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/DB2400Dialect.java index 5aa87d9d7c..cfdff08c7e 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/DB2400Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/DB2400Dialect.java @@ -23,6 +23,11 @@ */ package org.hibernate.dialect; +import org.hibernate.dialect.pagination.AbstractLimitHandler; +import org.hibernate.dialect.pagination.LimitHandler; +import org.hibernate.dialect.pagination.LimitHelper; +import org.hibernate.engine.spi.RowSelection; + /** * An SQL dialect for DB2/400. This class provides support for DB2 Universal Database for iSeries, * also known as DB2/400. @@ -41,36 +46,32 @@ public class DB2400Dialect extends DB2Dialect { } @Override - public boolean supportsLimit() { - return true; - } + public LimitHandler buildLimitHandler(String sql, RowSelection selection) { + return new AbstractLimitHandler(sql, selection) { + @Override + public String getProcessedSql() { + if ( LimitHelper.hasFirstRow(selection) ) { + throw new UnsupportedOperationException( "query result offset is not supported" ); + } + return sql + " fetch first ? rows only"; + } - @Override - @SuppressWarnings("deprecation") - public boolean supportsLimitOffset() { - return false; - } + @Override + public boolean supportsLimit() { + return true; + } - @Override - public boolean useMaxForLimit() { - return true; - } + @Override + public boolean useMaxForLimit() { + return true; + } - @Override - public boolean supportsVariableLimit() { - return false; - } - - @Override - public String getLimitString(String sql, int offset, int limit) { - if ( offset > 0 ) { - throw new UnsupportedOperationException( "query result offset is not supported" ); - } - if ( limit == 0 ) { - return sql; - } - return sql + " fetch first " + limit + " rows only "; - } + @Override + public boolean supportsVariableLimit() { + return false; + } + }; + } @Override public String getForUpdateString() { diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/DB2Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/DB2Dialect.java index 717bae4910..782e233426 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/DB2Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/DB2Dialect.java @@ -36,6 +36,10 @@ import org.hibernate.dialect.function.NoArgSQLFunction; import org.hibernate.dialect.function.SQLFunctionTemplate; import org.hibernate.dialect.function.StandardSQLFunction; import org.hibernate.dialect.function.VarArgsSQLFunction; +import org.hibernate.dialect.pagination.AbstractLimitHandler; +import org.hibernate.dialect.pagination.LimitHandler; +import org.hibernate.dialect.pagination.LimitHelper; +import org.hibernate.engine.spi.RowSelection; import org.hibernate.exception.LockTimeoutException; import org.hibernate.exception.spi.SQLExceptionConversionDelegate; import org.hibernate.internal.util.JdbcExceptionHelper; @@ -249,55 +253,12 @@ public class DB2Dialect extends Dialect { return "select seqname from sysibm.syssequences"; } - @Override - @SuppressWarnings("deprecation") - public boolean supportsLimit() { - return true; - } - - @Override - @SuppressWarnings("deprecation") - public boolean supportsVariableLimit() { - return false; - } - - @Override - @SuppressWarnings("deprecation") - public String getLimitString(String sql, int offset, int limit) { - if ( offset == 0 ) { - return sql + " fetch first " + limit + " rows only"; - } - //nest the main query in an outer select - return "select * from ( select inner2_.*, rownumber() over(order by order of inner2_) as rownumber_ from ( " - + sql + " fetch first " + limit + " rows only ) as inner2_ ) as inner1_ where rownumber_ > " - + offset + " order by rownumber_"; - } - - /** - * {@inheritDoc} - *
- * - * DB2 does have a one-based offset, however this was actually already handled in the limit string building - * (the '?+1' bit). To not mess up inheritors, I'll leave that part alone and not touch the offset here. - */ - @Override - @SuppressWarnings("deprecation") - public int convertToFirstRowValue(int zeroBasedFirstResult) { - return zeroBasedFirstResult; - } - @Override @SuppressWarnings("deprecation") public String getForUpdateString() { return " for read only with rs use and keep update locks"; } - @Override - @SuppressWarnings("deprecation") - public boolean useMaxForLimit() { - return true; - } - @Override public boolean supportsOuterJoinForUpdate() { return false; @@ -484,5 +445,36 @@ public class DB2Dialect extends Dialect { public String getNotExpression( String expression ) { return "not (" + expression + ")"; } + + @Override + public LimitHandler buildLimitHandler(String sql, RowSelection selection) { + return new AbstractLimitHandler(sql, selection) { + @Override + public String getProcessedSql() { + if ( LimitHelper.hasFirstRow(selection) ) { + //nest the main query in an outer select + return "select * from ( select inner2_.*, rownumber() over(order by order of inner2_) as rownumber_ from ( " + + sql + " fetch first ? rows only ) as inner2_ ) as inner1_ where rownumber_ > " + + "? order by rownumber_"; + } + return sql + " fetch first ? rows only"; + } + + @Override + public boolean supportsLimit() { + return true; + } + + @Override + public boolean useMaxForLimit() { + return true; + } + + @Override + public boolean supportsVariableLimit() { + return false; + } + }; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/DerbyDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/DerbyDialect.java index c6ed38aba3..f2a860f423 100755 --- a/hibernate-core/src/main/java/org/hibernate/dialect/DerbyDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/DerbyDialect.java @@ -29,11 +29,14 @@ import java.sql.Types; import org.hibernate.MappingException; import org.hibernate.dialect.function.AnsiTrimFunction; import org.hibernate.dialect.function.DerbyConcatFunction; +import org.hibernate.dialect.pagination.AbstractLimitHandler; +import org.hibernate.dialect.pagination.LimitHandler; +import org.hibernate.dialect.pagination.LimitHelper; +import org.hibernate.engine.spi.RowSelection; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.ReflectHelper; import org.hibernate.sql.CaseFragment; import org.hibernate.sql.DerbyCaseFragment; - import org.jboss.logging.Logger; /** @@ -134,23 +137,12 @@ public abstract class DerbyDialect extends DB2Dialect { } } - @Override - public boolean supportsLimit() { - return isTenPointFiveReleaseOrNewer(); - } - @Override public boolean supportsCommentOn() { //HHH-4531 return false; } - @Override - @SuppressWarnings("deprecation") - public boolean supportsLimitOffset() { - return isTenPointFiveReleaseOrNewer(); - } - @Override public String getForUpdateString() { return " for update with rs"; @@ -166,61 +158,6 @@ public abstract class DerbyDialect extends DB2Dialect { return " for read only with rs"; } - - /** - * {@inheritDoc} - * - * From Derby 10.5 Docs: - *- * Query - * [ORDER BY clause] - * [result offset clause] - * [fetch first clause] - * [FOR UPDATE clause] - * [WITH {RR|RS|CS|UR}] - *- */ - @Override - public String getLimitString(String query, final int offset, final int limit) { - final StringBuilder sb = new StringBuilder(query.length() + 50); - final String normalizedSelect = query.toLowerCase().trim(); - final int forUpdateIndex = normalizedSelect.lastIndexOf( "for update") ; - - if ( hasForUpdateClause( forUpdateIndex ) ) { - sb.append( query.substring( 0, forUpdateIndex-1 ) ); - } - else if ( hasWithClause( normalizedSelect ) ) { - sb.append( query.substring( 0, getWithIndex( query ) - 1 ) ); - } - else { - sb.append( query ); - } - - if ( offset == 0 ) { - sb.append( " fetch first " ); - } - else { - sb.append( " offset " ).append( offset ).append( " rows fetch next " ); - } - - sb.append( limit ).append( " rows only" ); - - if ( hasForUpdateClause( forUpdateIndex ) ) { - sb.append( ' ' ); - sb.append( query.substring( forUpdateIndex ) ); - } - else if ( hasWithClause( normalizedSelect ) ) { - sb.append( ' ' ).append( query.substring( getWithIndex( query ) ) ); - } - return sb.toString(); - } - - @Override - public boolean supportsVariableLimit() { - // we bind the limit and offset values directly into the sql... - return false; - } - private boolean hasForUpdateClause(int forUpdateIndex) { return forUpdateIndex >= 0; } @@ -242,6 +179,75 @@ public abstract class DerbyDialect extends DB2Dialect { return null ; } + @Override + public LimitHandler buildLimitHandler(String sql, RowSelection selection) { + return new AbstractLimitHandler(sql, selection) { + /** + * {@inheritDoc} + * + * From Derby 10.5 Docs: + *
+ * Query + * [ORDER BY clause] + * [result offset clause] + * [fetch first clause] + * [FOR UPDATE clause] + * [WITH {RR|RS|CS|UR}] + *+ */ + @Override + public String getProcessedSql() { + final StringBuilder sb = new StringBuilder(sql.length() + 50); + final String normalizedSelect = sql.toLowerCase().trim(); + final int forUpdateIndex = normalizedSelect.lastIndexOf( "for update") ; + + if ( hasForUpdateClause( forUpdateIndex ) ) { + sb.append( sql.substring( 0, forUpdateIndex-1 ) ); + } + else if ( hasWithClause( normalizedSelect ) ) { + sb.append( sql.substring( 0, getWithIndex( sql ) - 1 ) ); + } + else { + sb.append( sql ); + } + + if ( LimitHelper.hasFirstRow(selection) ) { + sb.append( " offset ? rows fetch next " ); + } + else { + sb.append( " fetch first " ); + } + + sb.append( "? rows only" ); + + if ( hasForUpdateClause( forUpdateIndex ) ) { + sb.append( ' ' ); + sb.append( sql.substring( forUpdateIndex ) ); + } + else if ( hasWithClause( normalizedSelect ) ) { + sb.append( ' ' ).append( sql.substring( getWithIndex( sql ) ) ); + } + return sb.toString(); + } + + @Override + public boolean supportsLimit() { + return isTenPointFiveReleaseOrNewer(); + } + + @Override + @SuppressWarnings("deprecation") + public boolean supportsLimitOffset() { + return isTenPointFiveReleaseOrNewer(); + } + + @Override + public boolean supportsVariableLimit() { + return false; + } + }; + } + // Overridden informational metadata ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/DerbyTenFiveDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/DerbyTenFiveDialect.java index 8cfc26f40f..3b6230e6ff 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/DerbyTenFiveDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/DerbyTenFiveDialect.java @@ -36,7 +36,6 @@ import org.hibernate.dialect.function.DerbyConcatFunction; * @author Simon Johnston * @author Scott Marlow */ -@SuppressWarnings("deprecation") public class DerbyTenFiveDialect extends DerbyDialect { /** * Constructs a DerbyTenFiveDialect @@ -51,14 +50,4 @@ public class DerbyTenFiveDialect extends DerbyDialect { public boolean supportsSequences() { return false; } - - @Override - public boolean supportsLimit() { - return true; - } - - @Override - public boolean supportsLimitOffset() { - return true; - } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/FirebirdDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/FirebirdDialect.java index c45d30b515..6be4dba763 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/FirebirdDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/FirebirdDialect.java @@ -23,6 +23,11 @@ */ package org.hibernate.dialect; +import org.hibernate.dialect.pagination.AbstractLimitHandler; +import org.hibernate.dialect.pagination.LimitHandler; +import org.hibernate.dialect.pagination.LimitHelper; +import org.hibernate.engine.spi.RowSelection; + /** * An SQL dialect for Firebird. * @@ -35,20 +40,31 @@ public class FirebirdDialect extends InterbaseDialect { } @Override - public String getLimitString(String sql, boolean hasOffset) { - return new StringBuilder( sql.length() + 20 ) + public LimitHandler buildLimitHandler(String sql, RowSelection selection) { + return new AbstractLimitHandler(sql, selection) { + @Override + public String getProcessedSql() { + boolean hasOffset = LimitHelper.hasFirstRow(selection); + return new StringBuilder( sql.length() + 20 ) .append( sql ) .insert( 6, hasOffset ? " first ? skip ?" : " first ?" ) .toString(); - } + } - @Override - public boolean bindLimitParametersFirst() { - return true; - } + @Override + public boolean supportsLimit() { + return true; + } - @Override - public boolean bindLimitParametersInReverseOrder() { - return true; - } + @Override + public boolean bindLimitParametersFirst() { + return true; + } + + @Override + public boolean bindLimitParametersInReverseOrder() { + return true; + } + }; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java index 3a3d78142a..719e5e4c30 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java @@ -33,6 +33,10 @@ import org.hibernate.dialect.function.AvgWithArgumentCastFunction; import org.hibernate.dialect.function.NoArgSQLFunction; import org.hibernate.dialect.function.StandardSQLFunction; import org.hibernate.dialect.function.VarArgsSQLFunction; +import org.hibernate.dialect.pagination.AbstractLimitHandler; +import org.hibernate.dialect.pagination.LimitHandler; +import org.hibernate.dialect.pagination.LimitHelper; +import org.hibernate.engine.spi.RowSelection; import org.hibernate.exception.ConstraintViolationException; import org.hibernate.exception.LockAcquisitionException; import org.hibernate.exception.spi.SQLExceptionConversionDelegate; @@ -42,7 +46,6 @@ import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.JdbcExceptionHelper; import org.hibernate.internal.util.ReflectHelper; import org.hibernate.type.StandardBasicTypes; - import org.jboss.logging.Logger; /** @@ -232,24 +235,25 @@ public class H2Dialect extends Dialect { } @Override - public boolean supportsLimit() { - return true; - } + public LimitHandler buildLimitHandler(String sql, RowSelection selection) { + return new AbstractLimitHandler(sql, selection) { + @Override + public String getProcessedSql() { + boolean hasOffset = LimitHelper.hasFirstRow(selection); + return sql + (hasOffset ? " limit ? offset ?" : " limit ?"); + } - @Override - public String getLimitString(String sql, boolean hasOffset) { - return sql + (hasOffset ? " limit ? offset ?" : " limit ?"); - } + @Override + public boolean supportsLimit() { + return true; + } - @Override - public boolean bindLimitParametersInReverseOrder() { - return true; - } - - @Override - public boolean bindLimitParametersFirst() { - return false; - } + @Override + public boolean bindLimitParametersInReverseOrder() { + return true; + } + }; + } @Override public boolean supportsIfExistsAfterTableName() { diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/HSQLDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/HSQLDialect.java index 85245005e3..3f879fb363 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/HSQLDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/HSQLDialect.java @@ -44,6 +44,10 @@ import org.hibernate.dialect.lock.PessimisticForceIncrementLockingStrategy; import org.hibernate.dialect.lock.PessimisticReadSelectLockingStrategy; import org.hibernate.dialect.lock.PessimisticWriteSelectLockingStrategy; import org.hibernate.dialect.lock.SelectLockingStrategy; +import org.hibernate.dialect.pagination.AbstractLimitHandler; +import org.hibernate.dialect.pagination.LimitHandler; +import org.hibernate.dialect.pagination.LimitHelper; +import org.hibernate.engine.spi.RowSelection; import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtracter; import org.hibernate.exception.spi.ViolatedConstraintNameExtracter; @@ -52,7 +56,6 @@ import org.hibernate.internal.util.JdbcExceptionHelper; import org.hibernate.internal.util.ReflectHelper; import org.hibernate.persister.entity.Lockable; import org.hibernate.type.StandardBasicTypes; - import org.jboss.logging.Logger; /** @@ -67,7 +70,6 @@ import org.jboss.logging.Logger; * @author Phillip Baird * @author Fred Toussi */ -@SuppressWarnings("deprecation") public class HSQLDialect extends Dialect { private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, @@ -268,30 +270,36 @@ public class HSQLDialect extends Dialect { } @Override - public boolean supportsLimit() { - return true; - } + public LimitHandler buildLimitHandler(String sql, RowSelection selection) { + return new AbstractLimitHandler(sql, selection) { + @Override + public String getProcessedSql() { + boolean hasOffset = LimitHelper.hasFirstRow(selection); + if ( hsqldbVersion < 20 ) { + return new StringBuilder( sql.length() + 10 ) + .append( sql ) + .insert( + sql.toLowerCase().indexOf( "select" ) + 6, + hasOffset ? " limit ? ?" : " top ?" + ) + .toString(); + } + else { + return sql + (hasOffset ? " offset ? limit ?" : " limit ?"); + } + } - @Override - public String getLimitString(String sql, boolean hasOffset) { - if ( hsqldbVersion < 20 ) { - return new StringBuilder( sql.length() + 10 ) - .append( sql ) - .insert( - sql.toLowerCase().indexOf( "select" ) + 6, - hasOffset ? " limit ? ?" : " top ?" - ) - .toString(); - } - else { - return sql + (hasOffset ? " offset ? limit ?" : " limit ?"); - } - } + @Override + public boolean supportsLimit() { + return true; + } - @Override - public boolean bindLimitParametersFirst() { - return hsqldbVersion < 20; - } + @Override + public boolean bindLimitParametersFirst() { + return hsqldbVersion < 20; + } + }; + } @Override public boolean supportsIfExistsAfterTableName() { diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/InformixDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/InformixDialect.java index 0fb1885f76..6c6f8dbc82 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/InformixDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/InformixDialect.java @@ -29,6 +29,9 @@ import java.sql.Types; import org.hibernate.MappingException; import org.hibernate.dialect.constraint.InformixUniqueKeyExporter; import org.hibernate.dialect.function.VarArgsSQLFunction; +import org.hibernate.dialect.pagination.FirstLimitHandler; +import org.hibernate.dialect.pagination.LimitHandler; +import org.hibernate.engine.spi.RowSelection; import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtracter; import org.hibernate.exception.spi.ViolatedConstraintNameExtracter; import org.hibernate.internal.util.JdbcExceptionHelper; @@ -190,35 +193,9 @@ public class InformixDialect extends Dialect { } @Override - public boolean supportsLimit() { - return true; - } - - @Override - public boolean useMaxForLimit() { - return true; - } - - @Override - public boolean supportsLimitOffset() { - return false; - } - - @Override - public String getLimitString(String querySelect, int offset, int limit) { - if ( offset > 0 ) { - throw new UnsupportedOperationException( "query result offset is not supported" ); - } - return new StringBuilder( querySelect.length() + 8 ) - .append( querySelect ) - .insert( querySelect.toLowerCase().indexOf( "select" ) + 6, " first " + limit ) - .toString(); - } - - @Override - public boolean supportsVariableLimit() { - return false; - } + public LimitHandler buildLimitHandler(String sql, RowSelection selection) { + return new FirstLimitHandler(sql, selection); + } @Override public ViolatedConstraintNameExtracter getViolatedConstraintNameExtracter() { diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/Ingres9Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/Ingres9Dialect.java index b335bdf50e..737d716efb 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/Ingres9Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/Ingres9Dialect.java @@ -27,6 +27,10 @@ import java.sql.Types; import org.hibernate.dialect.function.NoArgSQLFunction; import org.hibernate.dialect.function.VarArgsSQLFunction; +import org.hibernate.dialect.pagination.AbstractLimitHandler; +import org.hibernate.dialect.pagination.LimitHandler; +import org.hibernate.dialect.pagination.LimitHelper; +import org.hibernate.engine.spi.RowSelection; import org.hibernate.type.StandardBasicTypes; /** @@ -153,32 +157,32 @@ public class Ingres9Dialect extends IngresDialect { // limit/offset support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @Override - public boolean supportsLimitOffset() { - return true; - } + public LimitHandler buildLimitHandler(String sql, RowSelection selection) { + return new AbstractLimitHandler(sql, selection) { + @Override + public String getProcessedSql() { + final StringBuilder soff = new StringBuilder( " offset ?" ); + final StringBuilder slim = new StringBuilder( " fetch first ? rows only" ); + final StringBuilder sb = new StringBuilder( sql.length() + soff.length() + slim.length() ) + .append( sql ); + if ( LimitHelper.hasFirstRow(selection) ) { + sb.append( soff ); + } + if ( LimitHelper.hasMaxRows(selection) ) { + sb.append( slim ); + } + return sb.toString(); + } - @Override - public boolean supportsVariableLimit() { - return false; - } + @Override + public boolean supportsLimit() { + return true; + } - @Override - public boolean useMaxForLimit() { - return false; - } - - @Override - public String getLimitString(String querySelect, int offset, int limit) { - final StringBuilder soff = new StringBuilder( " offset " + offset ); - final StringBuilder slim = new StringBuilder( " fetch first " + limit + " rows only" ); - final StringBuilder sb = new StringBuilder( querySelect.length() + soff.length() + slim.length() ) - .append( querySelect ); - if ( offset > 0 ) { - sb.append( soff ); - } - if ( limit > 0 ) { - sb.append( slim ); - } - return sb.toString(); - } + @Override + public boolean supportsVariableLimit() { + return false; + } + }; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/IngresDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/IngresDialect.java index c58c01ee25..840f50514b 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/IngresDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/IngresDialect.java @@ -30,6 +30,9 @@ import org.hibernate.dialect.function.NoArgSQLFunction; import org.hibernate.dialect.function.SQLFunctionTemplate; import org.hibernate.dialect.function.StandardSQLFunction; import org.hibernate.dialect.function.VarArgsSQLFunction; +import org.hibernate.dialect.pagination.FirstLimitHandler; +import org.hibernate.dialect.pagination.LimitHandler; +import org.hibernate.engine.spi.RowSelection; import org.hibernate.type.StandardBasicTypes; /** @@ -56,7 +59,6 @@ import org.hibernate.type.StandardBasicTypes; * @author Max Rydahl Andersen * @author Raymond Fan */ -@SuppressWarnings("deprecation") public class IngresDialect extends Dialect { /** * Constructs a IngresDialect @@ -230,35 +232,9 @@ public class IngresDialect extends Dialect { } @Override - public boolean supportsLimit() { - return true; - } - - @Override - public boolean supportsLimitOffset() { - return false; - } - - @Override - public String getLimitString(String querySelect, int offset, int limit) { - if ( offset > 0 ) { - throw new UnsupportedOperationException( "query result offset is not supported" ); - } - return new StringBuilder( querySelect.length() + 16 ) - .append( querySelect ) - .insert( 6, " first " + limit ) - .toString(); - } - - @Override - public boolean supportsVariableLimit() { - return false; - } - - @Override - public boolean useMaxForLimit() { - return true; - } + public LimitHandler buildLimitHandler(String sql, RowSelection selection) { + return new FirstLimitHandler(sql, selection); + } @Override public boolean supportsTemporaryTables() { diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/InterbaseDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/InterbaseDialect.java index 746f42c17b..7cd2e38891 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/InterbaseDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/InterbaseDialect.java @@ -27,6 +27,10 @@ import java.sql.Types; import org.hibernate.cfg.Environment; import org.hibernate.dialect.function.NoArgSQLFunction; import org.hibernate.dialect.function.VarArgsSQLFunction; +import org.hibernate.dialect.pagination.AbstractLimitHandler; +import org.hibernate.dialect.pagination.LimitHandler; +import org.hibernate.dialect.pagination.LimitHelper; +import org.hibernate.engine.spi.RowSelection; import org.hibernate.type.StandardBasicTypes; /** @@ -34,7 +38,6 @@ import org.hibernate.type.StandardBasicTypes; * * @author Gavin King */ -@SuppressWarnings("deprecation") public class InterbaseDialect extends Dialect { /** @@ -112,24 +115,20 @@ public class InterbaseDialect extends Dialect { } @Override - public boolean supportsLimit() { - return true; - } + public LimitHandler buildLimitHandler(String sql, RowSelection selection) { + return new AbstractLimitHandler(sql, selection) { + @Override + public String getProcessedSql() { + final boolean hasOffset = LimitHelper.hasFirstRow(selection); + return hasOffset ? sql + " rows ? to ?" : sql + " rows ?"; + } - @Override - public String getLimitString(String sql, boolean hasOffset) { - return hasOffset ? sql + " rows ? to ?" : sql + " rows ?"; - } - - @Override - public boolean bindLimitParametersFirst() { - return false; - } - - @Override - public boolean bindLimitParametersInReverseOrder() { - return false; - } + @Override + public boolean supportsLimit() { + return true; + } + }; + } @Override public String getCurrentTimestampSelectString() { diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java index a0ff52bd55..ea70243990 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java @@ -33,6 +33,10 @@ import org.hibernate.NullPrecedence; import org.hibernate.cfg.Environment; import org.hibernate.dialect.function.NoArgSQLFunction; import org.hibernate.dialect.function.StandardSQLFunction; +import org.hibernate.dialect.pagination.AbstractLimitHandler; +import org.hibernate.dialect.pagination.LimitHandler; +import org.hibernate.dialect.pagination.LimitHelper; +import org.hibernate.engine.spi.RowSelection; import org.hibernate.exception.LockAcquisitionException; import org.hibernate.exception.LockTimeoutException; import org.hibernate.exception.spi.SQLExceptionConversionDelegate; @@ -45,7 +49,6 @@ import org.hibernate.type.StandardBasicTypes; * * @author Gavin King */ -@SuppressWarnings("deprecation") public class MySQLDialect extends Dialect { /** @@ -241,20 +244,26 @@ public class MySQLDialect extends Dialect { ); } - @Override - public boolean supportsLimit() { - return true; - } - @Override public String getDropForeignKeyString() { return " drop foreign key "; } @Override - public String getLimitString(String sql, boolean hasOffset) { - return sql + (hasOffset ? " limit ?, ?" : " limit ?"); - } + public LimitHandler buildLimitHandler(String sql, RowSelection selection) { + return new AbstractLimitHandler(sql, selection) { + @Override + public String getProcessedSql() { + final boolean hasOffset = LimitHelper.hasFirstRow(selection); + return sql + (hasOffset ? " limit ?, ?" : " limit ?"); + } + + @Override + public boolean supportsLimit() { + return true; + } + }; + } @Override public char closeQuote() { diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/Oracle8iDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/Oracle8iDialect.java index fe0e179f40..8f971e03ff 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/Oracle8iDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/Oracle8iDialect.java @@ -38,6 +38,10 @@ import org.hibernate.dialect.function.NvlFunction; import org.hibernate.dialect.function.SQLFunctionTemplate; import org.hibernate.dialect.function.StandardSQLFunction; import org.hibernate.dialect.function.VarArgsSQLFunction; +import org.hibernate.dialect.pagination.AbstractLimitHandler; +import org.hibernate.dialect.pagination.LimitHandler; +import org.hibernate.dialect.pagination.LimitHelper; +import org.hibernate.engine.spi.RowSelection; import org.hibernate.exception.ConstraintViolationException; import org.hibernate.exception.LockAcquisitionException; import org.hibernate.exception.LockTimeoutException; @@ -60,7 +64,6 @@ import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; * * @author Steve Ebersole */ -@SuppressWarnings("deprecation") public class Oracle8iDialect extends Dialect { private static final int PARAM_LIST_SIZE_LIMIT = 1000; @@ -244,35 +247,56 @@ public class Oracle8iDialect extends Dialect { } @Override - public String getLimitString(String sql, boolean hasOffset) { - sql = sql.trim(); - boolean isForUpdate = false; - if ( sql.toLowerCase().endsWith( " for update" ) ) { - sql = sql.substring( 0, sql.length()-11 ); - isForUpdate = true; - } + public LimitHandler buildLimitHandler(String sql, RowSelection selection) { + return new AbstractLimitHandler(sql, selection) { + @Override + public String getProcessedSql() { + boolean hasOffset = LimitHelper.hasFirstRow(selection); + sql = sql.trim(); + boolean isForUpdate = false; + if ( sql.toLowerCase().endsWith( " for update" ) ) { + sql = sql.substring( 0, sql.length()-11 ); + isForUpdate = true; + } - final StringBuilder pagingSelect = new StringBuilder( sql.length()+100 ); - if (hasOffset) { - pagingSelect.append( "select * from ( select row_.*, rownum rownum_ from ( " ); - } - else { - pagingSelect.append( "select * from ( " ); - } - pagingSelect.append( sql ); - if (hasOffset) { - pagingSelect.append( " ) row_ ) where rownum_ <= ? and rownum_ > ?" ); - } - else { - pagingSelect.append( " ) where rownum <= ?" ); - } + final StringBuilder pagingSelect = new StringBuilder( sql.length()+100 ); + if (hasOffset) { + pagingSelect.append( "select * from ( select row_.*, rownum rownum_ from ( " ); + } + else { + pagingSelect.append( "select * from ( " ); + } + pagingSelect.append( sql ); + if (hasOffset) { + pagingSelect.append( " ) row_ ) where rownum_ <= ? and rownum_ > ?" ); + } + else { + pagingSelect.append( " ) where rownum <= ?" ); + } - if ( isForUpdate ) { - pagingSelect.append( " for update" ); - } + if ( isForUpdate ) { + pagingSelect.append( " for update" ); + } - return pagingSelect.toString(); - } + return pagingSelect.toString(); + } + + @Override + public boolean supportsLimit() { + return true; + } + + @Override + public boolean bindLimitParametersInReverseOrder() { + return true; + } + + @Override + public boolean useMaxForLimit() { + return true; + } + }; + } /** * Allows access to the basic {@link Dialect#getSelectClauseNullString} @@ -364,11 +388,6 @@ public class Oracle8iDialect extends Dialect { return true; } - @Override - public boolean supportsLimit() { - return true; - } - @Override public String getForUpdateString(String aliases) { return getForUpdateString() + " of " + aliases; @@ -379,16 +398,6 @@ public class Oracle8iDialect extends Dialect { return getForUpdateString() + " of " + aliases + " nowait"; } - @Override - public boolean bindLimitParametersInReverseOrder() { - return true; - } - - @Override - public boolean useMaxForLimit() { - return true; - } - @Override public boolean forUpdateOfColumns() { return true; diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/Oracle9iDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/Oracle9iDialect.java index 687d23bdaa..4a8798c8d7 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/Oracle9iDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/Oracle9iDialect.java @@ -26,6 +26,10 @@ package org.hibernate.dialect; import java.sql.Types; import org.hibernate.LockOptions; +import org.hibernate.dialect.pagination.AbstractLimitHandler; +import org.hibernate.dialect.pagination.LimitHandler; +import org.hibernate.dialect.pagination.LimitHelper; +import org.hibernate.engine.spi.RowSelection; import org.hibernate.sql.ANSICaseFragment; import org.hibernate.sql.CaseFragment; @@ -58,40 +62,61 @@ public class Oracle9iDialect extends Oracle8iDialect { } @Override - public String getLimitString(String sql, boolean hasOffset) { - sql = sql.trim(); - String forUpdateClause = null; - boolean isForUpdate = false; - final int forUpdateIndex = sql.toLowerCase().lastIndexOf( "for update") ; - if ( forUpdateIndex > -1 ) { - // save 'for update ...' and then remove it - forUpdateClause = sql.substring( forUpdateIndex ); - sql = sql.substring( 0, forUpdateIndex-1 ); - isForUpdate = true; - } + public LimitHandler buildLimitHandler(String sql, RowSelection selection) { + return new AbstractLimitHandler(sql, selection) { + @Override + public String getProcessedSql() { + boolean hasOffset = LimitHelper.hasFirstRow(selection); + sql = sql.trim(); + String forUpdateClause = null; + boolean isForUpdate = false; + final int forUpdateIndex = sql.toLowerCase().lastIndexOf( "for update") ; + if ( forUpdateIndex > -1 ) { + // save 'for update ...' and then remove it + forUpdateClause = sql.substring( forUpdateIndex ); + sql = sql.substring( 0, forUpdateIndex-1 ); + isForUpdate = true; + } - final StringBuilder pagingSelect = new StringBuilder( sql.length() + 100 ); - if (hasOffset) { - pagingSelect.append( "select * from ( select row_.*, rownum rownum_ from ( " ); - } - else { - pagingSelect.append( "select * from ( " ); - } - pagingSelect.append( sql ); - if (hasOffset) { - pagingSelect.append( " ) row_ where rownum <= ?) where rownum_ > ?" ); - } - else { - pagingSelect.append( " ) where rownum <= ?" ); - } + final StringBuilder pagingSelect = new StringBuilder( sql.length() + 100 ); + if (hasOffset) { + pagingSelect.append( "select * from ( select row_.*, rownum rownum_ from ( " ); + } + else { + pagingSelect.append( "select * from ( " ); + } + pagingSelect.append( sql ); + if (hasOffset) { + pagingSelect.append( " ) row_ where rownum <= ?) where rownum_ > ?" ); + } + else { + pagingSelect.append( " ) where rownum <= ?" ); + } - if ( isForUpdate ) { - pagingSelect.append( " " ); - pagingSelect.append( forUpdateClause ); - } + if ( isForUpdate ) { + pagingSelect.append( " " ); + pagingSelect.append( forUpdateClause ); + } - return pagingSelect.toString(); - } + return pagingSelect.toString(); + } + + @Override + public boolean supportsLimit() { + return true; + } + + @Override + public boolean bindLimitParametersInReverseOrder() { + return true; + } + + @Override + public boolean useMaxForLimit() { + return true; + } + }; + } @Override public String getSelectClauseNullString(int sqlType) { diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL81Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL81Dialect.java index 703ab34102..41b0284452 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL81Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL81Dialect.java @@ -37,6 +37,10 @@ import org.hibernate.dialect.function.PositionSubstringFunction; import org.hibernate.dialect.function.SQLFunctionTemplate; import org.hibernate.dialect.function.StandardSQLFunction; import org.hibernate.dialect.function.VarArgsSQLFunction; +import org.hibernate.dialect.pagination.AbstractLimitHandler; +import org.hibernate.dialect.pagination.LimitHandler; +import org.hibernate.dialect.pagination.LimitHelper; +import org.hibernate.engine.spi.RowSelection; import org.hibernate.exception.LockAcquisitionException; import org.hibernate.exception.spi.SQLExceptionConversionDelegate; import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtracter; @@ -233,19 +237,25 @@ public class PostgreSQL81Dialect extends Dialect { } @Override - public boolean supportsLimit() { - return true; - } + public LimitHandler buildLimitHandler(String sql, RowSelection selection) { + return new AbstractLimitHandler(sql, selection) { + @Override + public String getProcessedSql() { + boolean hasOffset = LimitHelper.hasFirstRow(selection); + return sql + (hasOffset ? " limit ? offset ?" : " limit ?"); + } - @Override - public String getLimitString(String sql, boolean hasOffset) { - return sql + (hasOffset ? " limit ? offset ?" : " limit ?"); - } + @Override + public boolean supportsLimit() { + return true; + } - @Override - public boolean bindLimitParametersInReverseOrder() { - return true; - } + @Override + public boolean bindLimitParametersInReverseOrder() { + return true; + } + }; + } @Override public boolean supportsIdentityColumns() { diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/RDMSOS2200Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/RDMSOS2200Dialect.java index 3e13a521fe..b2b8bd9985 100755 --- a/hibernate-core/src/main/java/org/hibernate/dialect/RDMSOS2200Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/RDMSOS2200Dialect.java @@ -37,12 +37,15 @@ import org.hibernate.dialect.lock.PessimisticReadUpdateLockingStrategy; import org.hibernate.dialect.lock.PessimisticWriteUpdateLockingStrategy; import org.hibernate.dialect.lock.SelectLockingStrategy; import org.hibernate.dialect.lock.UpdateLockingStrategy; +import org.hibernate.dialect.pagination.AbstractLimitHandler; +import org.hibernate.dialect.pagination.LimitHandler; +import org.hibernate.dialect.pagination.LimitHelper; +import org.hibernate.engine.spi.RowSelection; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.persister.entity.Lockable; import org.hibernate.sql.CaseFragment; import org.hibernate.sql.DecodeCaseFragment; import org.hibernate.type.StandardBasicTypes; - import org.jboss.logging.Logger; /** @@ -57,7 +60,6 @@ import org.jboss.logging.Logger; * * @author Ploski and Hanson */ -@SuppressWarnings("deprecation") public class RDMSOS2200Dialect extends Dialect { private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, @@ -329,27 +331,33 @@ public class RDMSOS2200Dialect extends Dialect { } @Override - public boolean supportsLimit() { - return true; - } + public LimitHandler buildLimitHandler(String sql, RowSelection selection) { + return new AbstractLimitHandler(sql, selection) { + @Override + public String getProcessedSql() { + boolean hasOffset = LimitHelper.hasFirstRow(selection); + if ( hasOffset ) { + throw new UnsupportedOperationException( "query result offset is not supported" ); + } + return sql + " fetch first ? rows only "; + } - @Override - public boolean supportsLimitOffset() { - return false; - } + @Override + public boolean supportsLimit() { + return true; + } - @Override - public String getLimitString(String sql, int offset, int limit) { - if ( offset > 0 ) { - throw new UnsupportedOperationException( "query result offset is not supported" ); - } - return sql + " fetch first " + limit + " rows only "; - } + @Override + public boolean supportsLimitOffset() { + return false; + } - @Override - public boolean supportsVariableLimit() { - return false; - } + @Override + public boolean supportsVariableLimit() { + return false; + } + }; + } @Override public boolean supportsUnionAll() { diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java index c8dba6137c..bbb2154a1c 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java @@ -30,6 +30,9 @@ import org.hibernate.LockOptions; import org.hibernate.dialect.function.AnsiTrimEmulationFunction; import org.hibernate.dialect.function.SQLFunctionTemplate; import org.hibernate.dialect.function.StandardSQLFunction; +import org.hibernate.dialect.pagination.LimitHandler; +import org.hibernate.dialect.pagination.TopLimitHandler; +import org.hibernate.engine.spi.RowSelection; import org.hibernate.type.StandardBasicTypes; import org.hibernate.type.descriptor.sql.SmallIntTypeDescriptor; import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; @@ -72,23 +75,6 @@ public class SQLServerDialect extends AbstractTransactSQLDialect { return "default values"; } - static int getAfterSelectInsertPoint(String sql) { - final int selectIndex = sql.toLowerCase().indexOf( "select" ); - final int selectDistinctIndex = sql.toLowerCase().indexOf( "select distinct" ); - return selectIndex + (selectDistinctIndex == selectIndex ? 15 : 6); - } - - @Override - public String getLimitString(String querySelect, int offset, int limit) { - if ( offset > 0 ) { - throw new UnsupportedOperationException( "query result offset is not supported" ); - } - return new StringBuilder( querySelect.length() + 8 ) - .append( querySelect ) - .insert( getAfterSelectInsertPoint( querySelect ), " top " + limit ) - .toString(); - } - /** * Use insert table(...) values(...) select SCOPE_IDENTITY() * @@ -98,26 +84,11 @@ public class SQLServerDialect extends AbstractTransactSQLDialect { public String appendIdentitySelectToInsert(String insertSQL) { return insertSQL + " select scope_identity()"; } - + @Override - public boolean supportsLimit() { - return true; - } - - @Override - public boolean useMaxForLimit() { - return true; - } - - @Override - public boolean supportsLimitOffset() { - return false; - } - - @Override - public boolean supportsVariableLimit() { - return false; - } + public LimitHandler buildLimitHandler(String sql, RowSelection selection) { + return new TopLimitHandler(sql, selection, false, false); + } @Override public char closeQuote() { diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/TimesTenDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/TimesTenDialect.java index bbd6545dab..06f3c8ff36 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/TimesTenDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/TimesTenDialect.java @@ -37,6 +37,9 @@ import org.hibernate.dialect.lock.PessimisticReadUpdateLockingStrategy; import org.hibernate.dialect.lock.PessimisticWriteUpdateLockingStrategy; import org.hibernate.dialect.lock.SelectLockingStrategy; import org.hibernate.dialect.lock.UpdateLockingStrategy; +import org.hibernate.dialect.pagination.FirstLimitHandler; +import org.hibernate.dialect.pagination.LimitHandler; +import org.hibernate.engine.spi.RowSelection; import org.hibernate.persister.entity.Lockable; import org.hibernate.sql.JoinFragment; import org.hibernate.sql.OracleJoinFragment; @@ -169,35 +172,9 @@ public class TimesTenDialect extends Dialect { } @Override - public boolean supportsLimitOffset() { - return false; - } - - @Override - public boolean supportsVariableLimit() { - return false; - } - - @Override - public boolean supportsLimit() { - return true; - } - - @Override - public boolean useMaxForLimit() { - return true; - } - - @Override - public String getLimitString(String querySelect, int offset, int limit) { - if ( offset > 0 ) { - throw new UnsupportedOperationException( "query result offset is not supported" ); - } - return new StringBuilder( querySelect.length() + 8 ) - .append( querySelect ) - .insert( 6, " first " + limit ) - .toString(); - } + public LimitHandler buildLimitHandler(String sql, RowSelection selection) { + return new FirstLimitHandler(sql, selection); + } @Override public boolean supportsCurrentTimestampSelection() { diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/pagination/AbstractLimitHandler.java b/hibernate-core/src/main/java/org/hibernate/dialect/pagination/AbstractLimitHandler.java index 8b80ea170b..87248071c3 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/pagination/AbstractLimitHandler.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/pagination/AbstractLimitHandler.java @@ -11,7 +11,7 @@ import org.hibernate.engine.spi.RowSelection; * @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com) */ public abstract class AbstractLimitHandler implements LimitHandler { - protected final String sql; + protected String sql; protected final RowSelection selection; /** diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/pagination/FirstLimitHandler.java b/hibernate-core/src/main/java/org/hibernate/dialect/pagination/FirstLimitHandler.java new file mode 100644 index 0000000000..a49d6d6d19 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/dialect/pagination/FirstLimitHandler.java @@ -0,0 +1,66 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * JBoss, Home of Professional Open Source + * Copyright 2014 Red Hat Inc. and/or its affiliates and other contributors + * as indicated by the @authors tag. All rights reserved. + * See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU Lesser General Public License, v. 2.1. + * This program is distributed in the hope that it will be useful, but WITHOUT A + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License, + * v.2.1 along with this distribution; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +package org.hibernate.dialect.pagination; + +import org.hibernate.engine.spi.RowSelection; + + +/** + * @author Brett Meyer + */ +public class FirstLimitHandler extends AbstractLimitHandler { + + public FirstLimitHandler(String sql, RowSelection selection) { + super(sql, selection); + } + + @Override + public String getProcessedSql() { + boolean hasOffset = LimitHelper.hasFirstRow(selection); + if ( hasOffset ) { + throw new UnsupportedOperationException( "query result offset is not supported" ); + } + return new StringBuilder( sql.length() + 16 ) + .append( sql ) + .insert( sql.toLowerCase().indexOf( "select" ) + 6, " first ?" ) + .toString(); + } + + @Override + public boolean supportsLimit() { + return true; + } + + @Override + public boolean useMaxForLimit() { + return true; + } + + @Override + public boolean supportsLimitOffset() { + return false; + } + + @Override + public boolean supportsVariableLimit() { + return false; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/pagination/SQL2008StandardLimitHandler.java b/hibernate-core/src/main/java/org/hibernate/dialect/pagination/SQL2008StandardLimitHandler.java index c9f75cd9e7..20fed29e2c 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/pagination/SQL2008StandardLimitHandler.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/pagination/SQL2008StandardLimitHandler.java @@ -52,9 +52,8 @@ public class SQL2008StandardLimitHandler extends AbstractLimitHandler { @Override public String getProcessedSql() { if (LimitHelper.useLimit(this, selection)) { - return sql - + (LimitHelper.hasFirstRow(selection) ? " offset ? rows fetch next ? rows only" - : " fetch first ? rows only"); + return sql + (LimitHelper.hasFirstRow(selection) ? + " offset ? rows fetch next ? rows only" : " fetch first ? rows only"); } else { // or return unaltered SQL return sql; diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/pagination/TopLimitHandler.java b/hibernate-core/src/main/java/org/hibernate/dialect/pagination/TopLimitHandler.java new file mode 100644 index 0000000000..2515dce822 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/dialect/pagination/TopLimitHandler.java @@ -0,0 +1,76 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * JBoss, Home of Professional Open Source + * Copyright 2014 Red Hat Inc. and/or its affiliates and other contributors + * as indicated by the @authors tag. All rights reserved. + * See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU Lesser General Public License, v. 2.1. + * This program is distributed in the hope that it will be useful, but WITHOUT A + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License, + * v.2.1 along with this distribution; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +package org.hibernate.dialect.pagination; + +import org.hibernate.engine.spi.RowSelection; + + +/** + * @author Brett Meyer + */ +public class TopLimitHandler extends AbstractLimitHandler { + + private final boolean supportsVariableLimit; + + private final boolean bindLimitParametersFirst; + + public TopLimitHandler(String sql, RowSelection selection, + boolean supportsVariableLimit, boolean bindLimitParametersFirst) { + super(sql, selection); + this.supportsVariableLimit = supportsVariableLimit; + this.bindLimitParametersFirst = bindLimitParametersFirst; + } + + @Override + public boolean supportsLimit() { + return true; + } + + @Override + public boolean useMaxForLimit() { + return true; + } + + @Override + public boolean supportsLimitOffset() { + return supportsVariableLimit; + } + + public boolean bindLimitParametersFirst() { + return bindLimitParametersFirst; + } + + @Override + public String getProcessedSql() { + if ( LimitHelper.hasFirstRow(selection) ) { + throw new UnsupportedOperationException( "query result offset is not supported" ); + } + + final int selectIndex = sql.toLowerCase().indexOf( "select" ); + final int selectDistinctIndex = sql.toLowerCase().indexOf( "select distinct" ); + final int insertionPoint = selectIndex + (selectDistinctIndex == selectIndex ? 15 : 6); + + return new StringBuilder( sql.length() + 8 ) + .append( sql ) + .insert( insertionPoint, " TOP ? " ) + .toString(); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/dialect/DerbyDialectTestCase.java b/hibernate-core/src/test/java/org/hibernate/dialect/DerbyDialectTestCase.java index b38f4e2fbc..919c26363b 100644 --- a/hibernate-core/src/test/java/org/hibernate/dialect/DerbyDialectTestCase.java +++ b/hibernate-core/src/test/java/org/hibernate/dialect/DerbyDialectTestCase.java @@ -23,12 +23,12 @@ */ package org.hibernate.dialect; -import org.junit.Test; +import static org.junit.Assert.assertEquals; +import org.hibernate.engine.spi.RowSelection; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.junit4.BaseUnitTestCase; - -import static org.junit.Assert.assertEquals; +import org.junit.Test; /** * Testing of patched support for Derby limit and offset queries; see HHH-3972 @@ -48,9 +48,12 @@ public class DerbyDialectTestCase extends BaseUnitTestCase { public void testInsertLimitClause() { final int limit = 50; final String input = "select * from tablename t where t.cat = 5"; - final String expected = "select * from tablename t where t.cat = 5 fetch first " + limit + " rows only"; + final String expected = "select * from tablename t where t.cat = 5 fetch first ? rows only"; - final String actual = new LocalDerbyDialect().getLimitString( input, 0, limit ); + RowSelection rowSelection = new RowSelection(); + rowSelection.setFirstRow( 0 ); + rowSelection.setMaxRows( limit ); + final String actual = new LocalDerbyDialect().buildLimitHandler( input, rowSelection ).getProcessedSql(); assertEquals( expected, actual ); } @@ -59,9 +62,12 @@ public class DerbyDialectTestCase extends BaseUnitTestCase { final int limit = 50; final int offset = 200; final String input = "select * from tablename t where t.cat = 5"; - final String expected = "select * from tablename t where t.cat = 5 offset " + offset + " rows fetch next " + limit + " rows only"; + final String expected = "select * from tablename t where t.cat = 5 offset ? rows fetch next ? rows only"; - final String actual = new LocalDerbyDialect().getLimitString( input, offset, limit ); + RowSelection rowSelection = new RowSelection(); + rowSelection.setFirstRow( offset ); + rowSelection.setMaxRows( limit ); + final String actual = new LocalDerbyDialect().buildLimitHandler( input, rowSelection ).getProcessedSql(); assertEquals( expected, actual ); } @@ -70,10 +76,12 @@ public class DerbyDialectTestCase extends BaseUnitTestCase { final int limit = 50; final int offset = 200; final String input = "select c11 as col1, c12 as col2, c13 as col13 from t1 for update of c11, c13"; - final String expected = "select c11 as col1, c12 as col2, c13 as col13 from t1 offset " + offset - + " rows fetch next " + limit + " rows only for update of c11, c13"; + final String expected = "select c11 as col1, c12 as col2, c13 as col13 from t1 offset ? rows fetch next ? rows only for update of c11, c13"; - final String actual = new LocalDerbyDialect().getLimitString( input, offset, limit ); + RowSelection rowSelection = new RowSelection(); + rowSelection.setFirstRow( offset ); + rowSelection.setMaxRows( limit ); + final String actual = new LocalDerbyDialect().buildLimitHandler( input, rowSelection ).getProcessedSql(); assertEquals( expected, actual ); } @@ -82,10 +90,12 @@ public class DerbyDialectTestCase extends BaseUnitTestCase { final int limit = 50; final int offset = 200; final String input = "select c11 as col1, c12 as col2, c13 as col13 from t1 where flight_id between 'AA1111' and 'AA1112' with rr"; - final String expected = "select c11 as col1, c12 as col2, c13 as col13 from t1 where flight_id between 'AA1111' and 'AA1112' offset " + offset - + " rows fetch next " + limit + " rows only with rr"; + final String expected = "select c11 as col1, c12 as col2, c13 as col13 from t1 where flight_id between 'AA1111' and 'AA1112' offset ? rows fetch next ? rows only with rr"; - final String actual = new LocalDerbyDialect().getLimitString( input, offset, limit ); + RowSelection rowSelection = new RowSelection(); + rowSelection.setFirstRow( offset ); + rowSelection.setMaxRows( limit ); + final String actual = new LocalDerbyDialect().buildLimitHandler( input, rowSelection ).getProcessedSql(); assertEquals( expected, actual ); } @@ -94,10 +104,12 @@ public class DerbyDialectTestCase extends BaseUnitTestCase { final int limit = 50; final int offset = 200; final String input = "select c11 as col1, c12 as col2, c13 as col13 from t1 where flight_id between 'AA1111' and 'AA1112' for update of c11,c13 with rr"; - final String expected = "select c11 as col1, c12 as col2, c13 as col13 from t1 where flight_id between 'AA1111' and 'AA1112' offset " + offset - + " rows fetch next " + limit + " rows only for update of c11,c13 with rr"; + final String expected = "select c11 as col1, c12 as col2, c13 as col13 from t1 where flight_id between 'AA1111' and 'AA1112' offset ? rows fetch next ? rows only for update of c11,c13 with rr"; - final String actual = new LocalDerbyDialect().getLimitString( input, offset, limit ); + RowSelection rowSelection = new RowSelection(); + rowSelection.setFirstRow( offset ); + rowSelection.setMaxRows( limit ); + final String actual = new LocalDerbyDialect().buildLimitHandler( input, rowSelection ).getProcessedSql(); assertEquals( expected, actual ); } } diff --git a/hibernate-core/src/test/java/org/hibernate/dialect/resolver/DialectFactoryTest.java b/hibernate-core/src/test/java/org/hibernate/dialect/resolver/DialectFactoryTest.java index 2f12c72f8e..c5872a4785 100644 --- a/hibernate-core/src/test/java/org/hibernate/dialect/resolver/DialectFactoryTest.java +++ b/hibernate-core/src/test/java/org/hibernate/dialect/resolver/DialectFactoryTest.java @@ -23,7 +23,10 @@ */ package org.hibernate.dialect.resolver; -import java.sql.Connection; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; + import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -38,7 +41,6 @@ import org.hibernate.boot.registry.selector.spi.StrategySelectionException; import org.hibernate.cfg.Environment; import org.hibernate.dialect.DB2400Dialect; import org.hibernate.dialect.DB2Dialect; -import org.hibernate.dialect.DerbyDialect; import org.hibernate.dialect.DerbyTenFiveDialect; import org.hibernate.dialect.DerbyTenSevenDialect; import org.hibernate.dialect.DerbyTenSixDialect; @@ -47,7 +49,6 @@ import org.hibernate.dialect.H2Dialect; import org.hibernate.dialect.HSQLDialect; import org.hibernate.dialect.InformixDialect; import org.hibernate.dialect.IngresDialect; -import org.hibernate.dialect.Mocks; import org.hibernate.dialect.MySQL5Dialect; import org.hibernate.dialect.MySQLDialect; import org.hibernate.dialect.Oracle10gDialect; @@ -68,16 +69,10 @@ import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo; import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfoSource; import org.hibernate.engine.jdbc.dialect.spi.DialectResolver; import org.hibernate.service.spi.ServiceRegistryImplementor; - +import org.hibernate.testing.junit4.BaseUnitTestCase; import org.junit.Before; import org.junit.Test; -import org.hibernate.testing.junit4.BaseUnitTestCase; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; - /** * @author Steve Ebersole */ @@ -158,7 +153,7 @@ public class DialectFactoryTest extends BaseUnitTestCase { testDetermination( "PostgreSQL", 8, 2, PostgreSQL82Dialect.class, resolver ); testDetermination( "PostgreSQL", 9, 0, PostgreSQL9Dialect.class, resolver ); testDetermination( "EnterpriseDB", 9, 2, PostgresPlusDialect.class, resolver ); - testDetermination( "Apache Derby", 10, 4, DerbyDialect.class, resolver ); + testDetermination( "Apache Derby", 10, 4, DB2Dialect.class, resolver ); testDetermination( "Apache Derby", 10, 5, DerbyTenFiveDialect.class, resolver ); testDetermination( "Apache Derby", 10, 6, DerbyTenSixDialect.class, resolver ); testDetermination( "Apache Derby", 11, 5, DerbyTenSevenDialect.class, resolver ); diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/DialectChecks.java b/hibernate-testing/src/main/java/org/hibernate/testing/DialectChecks.java index 3616d96d18..8a84aa4e84 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/DialectChecks.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/DialectChecks.java @@ -24,6 +24,7 @@ package org.hibernate.testing; import org.hibernate.dialect.Dialect; +import org.hibernate.engine.spi.RowSelection; /** * Container class for different implementation of the {@link DialectCheck} interface. @@ -106,13 +107,15 @@ abstract public class DialectChecks { public static class SupportLimitCheck implements DialectCheck { public boolean isMatch(Dialect dialect) { - return dialect.supportsLimit(); + // TODO: Stupid -- better way? + return dialect.buildLimitHandler( "", new RowSelection() ).supportsLimit(); } } public static class SupportLimitAndOffsetCheck implements DialectCheck { public boolean isMatch(Dialect dialect) { - return dialect.supportsLimit() && dialect.supportsLimitOffset(); + // TODO: Stupid -- better way? + return dialect.buildLimitHandler( "", new RowSelection() ).supportsLimitOffset(); } }