Fix paging errors with descending keys

This commit is contained in:
dsyer
2009-01-02 16:03:11 +00:00
parent aee5ca3b85
commit d3e81b5b4d
18 changed files with 340 additions and 98 deletions

View File

@@ -27,17 +27,21 @@ import java.util.List;
import java.util.ArrayList;
/**
* Abstract SQL Paging Query Provider to serve as a base class for all provided SQL paging query providers.
*
* Any implementation must provide a way to specify the select clause, from clause and optionally a where clause.
* In addition a way to specify a single column sort key must also be provided. This sort key will be used to
* provide the paging functionality. It is recommended that there should be an index for the sort key to provide
* better performance.
*
* Provides properties and preparation for the mandatory "selectClause" and "fromClause" as well as for the
* optional "whereClause". Also provides property for the mandatory "sortKey".
*
* Abstract SQL Paging Query Provider to serve as a base class for all provided
* SQL paging query providers.
*
* Any implementation must provide a way to specify the select clause, from
* clause and optionally a where clause. In addition a way to specify a single
* column sort key must also be provided. This sort key will be used to provide
* the paging functionality. It is recommended that there should be an index for
* the sort key to provide better performance.
*
* Provides properties and preparation for the mandatory "selectClause" and
* "fromClause" as well as for the optional "whereClause". Also provides
* property for the mandatory "sortKey".
*
* @author Thomas Risberg
* @author Dave Syer
* @since 2.0
*/
public abstract class AbstractSqlPagingQueryProvider implements PagingQueryProvider {
@@ -50,11 +54,12 @@ public abstract class AbstractSqlPagingQueryProvider implements PagingQueryProvi
private String sortKey;
private boolean ascending = true;
private int parameterCount;
private boolean usingNamedParameters;
/**
* @param selectClause SELECT clause part of SQL query string
*/
@@ -63,7 +68,7 @@ public abstract class AbstractSqlPagingQueryProvider implements PagingQueryProvi
}
/**
*
*
* @return SQL SELECT clause part of SQL query string
*/
protected String getSelectClause() {
@@ -78,7 +83,7 @@ public abstract class AbstractSqlPagingQueryProvider implements PagingQueryProvi
}
/**
*
*
* @return SQL FROM clause part of SQL query string
*/
protected String getFromClause() {
@@ -93,12 +98,12 @@ public abstract class AbstractSqlPagingQueryProvider implements PagingQueryProvi
this.whereClause = removeKeyWord("where", whereClause);
}
else {
this.whereClause = null;
this.whereClause = null;
}
}
/**
*
*
* @return SQL WHERE clause part of SQL query string
*/
protected String getWhereClause() {
@@ -113,14 +118,32 @@ public abstract class AbstractSqlPagingQueryProvider implements PagingQueryProvi
}
/**
*
* Set the flag that signals that the sort key is applied ascending (default
* true).
*
* @param ascending the ascending value to set
*/
public void setAscending(boolean ascending) {
this.ascending = ascending;
}
/**
* Get the flag that signals that the sort key is applied ascending.
*
* @return the ascending flag
*/
public boolean isAscending() {
return ascending;
}
/**
*
* @return sortKey key to use to sort and limit page content
*/
protected String getSortKey() {
return sortKey;
}
public int getParameterCount() {
return parameterCount;
}
@@ -130,9 +153,9 @@ public abstract class AbstractSqlPagingQueryProvider implements PagingQueryProvi
}
/**
* The sort key placeholder will vary depending on whether named parameters or traditional placeholders
* are used in query strings.
*
* The sort key placeholder will vary depending on whether named parameters
* or traditional placeholders are used in query strings.
*
* @return place holder for sortKey.
*/
protected String getSortKeyPlaceHolder() {
@@ -158,41 +181,42 @@ public abstract class AbstractSqlPagingQueryProvider implements PagingQueryProvi
parameterCount = JdbcParameterUtils.countParameterPlaceholders(sql.toString(), namedParameters);
if (namedParameters.size() > 0) {
if (parameterCount != namedParameters.size()) {
throw new InvalidDataAccessApiUsageException("You can't use both named parameters and classic \"?\" placeholders: " + sql);
throw new InvalidDataAccessApiUsageException(
"You can't use both named parameters and classic \"?\" placeholders: " + sql);
}
usingNamedParameters = true;
}
}
/**
* Method generating the query string to be used for retrieving the first page.
* This method must be implemented in sub classes.
*
* Method generating the query string to be used for retrieving the first
* page. This method must be implemented in sub classes.
*
* @param pageSize number of rows to read per page
* @return query string
*/
public abstract String generateFirstPageQuery(int pageSize);
/**
* Method generating the query string to be used for retrieving the pages following the first page.
* This method must be implemented in sub classes.
*
* Method generating the query string to be used for retrieving the pages
* following the first page. This method must be implemented in sub classes.
*
* @param pageSize number of rows to read per page
* @return query string
*/
public abstract String generateRemainingPagesQuery(int pageSize);
/**
* Method generating the query string to be used for jumping to a specific item position.
* This method must be implemented in sub classes.
*
* Method generating the query string to be used for jumping to a specific
* item position. This method must be implemented in sub classes.
*
* @param itemIndex the index of the item to jump to
* @param pageSize number of rows to read per page
* @return query string
*/
public abstract String generateJumpToItemQuery(int itemIndex, int pageSize);
private String removeKeyWord(String keyWord, String clause) {
private String removeKeyWord(String keyWord, String clause) {
String temp = clause.trim();
String keyWordString = keyWord + " ";
if (temp.toLowerCase().startsWith(keyWordString) && temp.length() > keyWordString.length()) {

View File

@@ -42,6 +42,7 @@ public class HsqlPagingQueryProvider extends AbstractSqlPagingQueryProvider {
public String generateJumpToItemQuery(int itemIndex, int pageSize) {
int page = itemIndex / pageSize;
int offset = (page * pageSize) - 1;
offset = offset<0 ? 0 : offset;
String topClause = new StringBuilder().append("LIMIT ").append(offset).append(" 1").toString();
return SqlPagingQueryUtils.generateTopJumpToQuery(this, topClause);

View File

@@ -44,6 +44,7 @@ public class MySqlPagingQueryProvider extends AbstractSqlPagingQueryProvider {
public String generateJumpToItemQuery(int itemIndex, int pageSize) {
int page = itemIndex / pageSize;
int offset = (page * pageSize) - 1;
offset = offset<0 ? 0 : offset;
String limitClause = new StringBuilder().append("LIMIT ").append(offset).append(", 1").toString();
return SqlPagingQueryUtils.generateLimitJumpToQuery(this, limitClause);

View File

@@ -42,6 +42,7 @@ public class PostgresPagingQueryProvider extends AbstractSqlPagingQueryProvider
public String generateJumpToItemQuery(int itemIndex, int pageSize) {
int page = itemIndex / pageSize;
int offset = (page * pageSize) - 1;
offset = offset<0 ? 0 : offset;
String limitClause = new StringBuilder().append("LIMIT ").append(offset).append(" 1").toString();
return SqlPagingQueryUtils.generateLimitJumpToQuery(this, limitClause);

View File

@@ -59,6 +59,8 @@ public class SqlPagingQueryProviderFactoryBean implements FactoryBean {
private String sortKey;
private Map<DatabaseType, AbstractSqlPagingQueryProvider> providers = new HashMap<DatabaseType, AbstractSqlPagingQueryProvider>();
private boolean ascending;
{
providers.put(DB2, new Db2PagingQueryProvider());
providers.put(DB2ZOS, new Db2PagingQueryProvider());
@@ -113,6 +115,13 @@ public class SqlPagingQueryProviderFactoryBean implements FactoryBean {
this.sortKey = sortKey;
}
/**
* @param ascending
*/
public void setAscending(boolean ascending) {
this.ascending = ascending;
}
/**
* Get a {@link PagingQueryProvider} instance using the provided properties
* and appropriate for the given database type.
@@ -137,6 +146,7 @@ public class SqlPagingQueryProviderFactoryBean implements FactoryBean {
provider.setFromClause(fromClause);
provider.setWhereClause(whereClause);
provider.setSortKey(sortKey);
provider.setAscending(ascending);
if (StringUtils.hasText(selectClause)) {
provider.setSelectClause(selectClause);
}
@@ -163,4 +173,5 @@ public class SqlPagingQueryProviderFactoryBean implements FactoryBean {
public boolean isSingleton() {
return true;
}
}

View File

@@ -17,65 +17,79 @@
package org.springframework.batch.item.database.support;
/**
* Utility class that generates the actual SQL statements used by query providers.
*
* Utility class that generates the actual SQL statements used by query
* providers.
*
* @author Thomas Risberg
* @author Dave Syer
* @since 2.0
*/
public class SqlPagingQueryUtils {
/**
* Generate SQL query string using a LIMIT clause
*
* @param provider {@link AbstractSqlPagingQueryProvider} providing the implementation specifics
* @param remainingPageQuery is this query for the ramining pages (true) as opposed to the first page (false)
* @param limitClause the implementation specific limit clause to be used
*
* @param provider {@link AbstractSqlPagingQueryProvider} providing the
* implementation specifics
* @param remainingPageQuery is this query for the ramining pages (true) as
* opposed to the first page (false)
* @param limitClause the implementation specific limit clause to be used
* @return the generated query
*/
public static String generateLimitSqlQuery(AbstractSqlPagingQueryProvider provider, boolean remainingPageQuery, String limitClause) {
public static String generateLimitSqlQuery(AbstractSqlPagingQueryProvider provider, boolean remainingPageQuery,
String limitClause) {
StringBuilder sql = new StringBuilder();
sql.append("SELECT ").append(provider.getSelectClause());
sql.append(" FROM ").append(provider.getFromClause());
buildWhereClause(provider, remainingPageQuery, sql);
sql.append(" ORDER BY ").append(provider.getSortKey()).append(" ASC ");
sql.append(limitClause);
sql.append(" ORDER BY ").append(provider.getSortKey());
buildAscendingClause(provider, sql);
sql.append(" " + limitClause);
return sql.toString();
}
/**
* Generate SQL query string using a TOP clause
*
* @param provider {@link AbstractSqlPagingQueryProvider} providing the implementation specifics
* @param remainingPageQuery is this query for the ramining pages (true) as opposed to the first page (false)
*
* @param provider {@link AbstractSqlPagingQueryProvider} providing the
* implementation specifics
* @param remainingPageQuery is this query for the ramining pages (true) as
* opposed to the first page (false)
* @param topClause the implementation specific top clause to be used
* @return the generated query
*/
public static String generateTopSqlQuery(AbstractSqlPagingQueryProvider provider, boolean remainingPageQuery, String topClause) {
public static String generateTopSqlQuery(AbstractSqlPagingQueryProvider provider, boolean remainingPageQuery,
String topClause) {
StringBuilder sql = new StringBuilder();
sql.append("SELECT ").append(topClause).append(" ").append(provider.getSelectClause());
sql.append(" FROM ").append(provider.getFromClause());
buildWhereClause(provider, remainingPageQuery, sql);
sql.append(" ORDER BY ").append(provider.getSortKey()).append(" ASC");
sql.append(" ORDER BY ").append(provider.getSortKey());
buildAscendingClause(provider, sql);
return sql.toString();
}
/**
* Generate SQL query string using a ROW_NUM condition
*
* @param provider {@link AbstractSqlPagingQueryProvider} providing the implementation specifics
* @param remainingPageQuery is this query for the ramining pages (true) as opposed to the first page (false)
*
* @param provider {@link AbstractSqlPagingQueryProvider} providing the
* implementation specifics
* @param remainingPageQuery is this query for the ramining pages (true) as
* opposed to the first page (false)
* @param rowNumClause the implementation specific row num clause to be used
* @return the generated query
*/
public static String generateRowNumSqlQuery(AbstractSqlPagingQueryProvider provider, boolean remainingPageQuery, String rowNumClause) {
public static String generateRowNumSqlQuery(AbstractSqlPagingQueryProvider provider, boolean remainingPageQuery,
String rowNumClause) {
StringBuilder sql = new StringBuilder();
sql.append("SELECT ").append(provider.getSelectClause());
sql.append(" FROM ").append(provider.getFromClause());
buildWhereClause(provider, remainingPageQuery, sql);
sql.append(provider.getWhereClause() != null || remainingPageQuery ? " AND " : " WHERE ").append(rowNumClause);
sql.append(" ORDER BY ").append(provider.getSortKey()).append(" ASC");
sql.append(" ORDER BY ").append(provider.getSortKey());
buildAscendingClause(provider, sql);
return sql.toString();
@@ -83,8 +97,9 @@ public class SqlPagingQueryUtils {
/**
* Generate SQL query string using a LIMIT clause
*
* @param provider {@link AbstractSqlPagingQueryProvider} providing the implementation specifics
*
* @param provider {@link AbstractSqlPagingQueryProvider} providing the
* implementation specifics
* @param limitClause the implementation specific top clause to be used
* @return the generated query
*/
@@ -93,16 +108,18 @@ public class SqlPagingQueryUtils {
sql.append("SELECT ").append(provider.getSortKey()).append(" AS SORT_KEY");
sql.append(" FROM ").append(provider.getFromClause());
sql.append(provider.getWhereClause() == null ? "" : " WHERE " + provider.getWhereClause());
sql.append(" ORDER BY ").append(provider.getSortKey()).append(" ASC ");
sql.append( limitClause);
sql.append(" ORDER BY ").append(provider.getSortKey());
buildAscendingClause(provider, sql);
sql.append(" " + limitClause);
return sql.toString();
}
/**
* Generate SQL query string using a TOP clause
*
* @param provider {@link AbstractSqlPagingQueryProvider} providing the implementation specifics
*
* @param provider {@link AbstractSqlPagingQueryProvider} providing the
* implementation specifics
* @param topClause the implementation specific top clause to be used
* @return the generated query
*/
@@ -111,19 +128,37 @@ public class SqlPagingQueryUtils {
sql.append("SELECT ").append(topClause).append(" ").append(provider.getSortKey()).append(" AS SORT_KEY");
sql.append(" FROM ").append(provider.getFromClause());
sql.append(provider.getWhereClause() == null ? "" : " WHERE " + provider.getWhereClause());
sql.append(" ORDER BY ").append(provider.getSortKey()).append(" ASC");
sql.append(" ORDER BY ").append(provider.getSortKey());
buildAscendingClause(provider, sql);
return sql.toString();
}
private static void buildWhereClause(AbstractSqlPagingQueryProvider provider, boolean remainingPageQuery, StringBuilder sql) {
private static void buildAscendingClause(AbstractSqlPagingQueryProvider provider, StringBuilder sql) {
if (provider.isAscending()) {
sql.append(" ASC");
}
else {
sql.append(" DESC");
}
}
private static void buildWhereClause(AbstractSqlPagingQueryProvider provider, boolean remainingPageQuery,
StringBuilder sql) {
if (remainingPageQuery) {
sql.append(" WHERE ");
if (provider.getWhereClause() != null) {
sql.append(provider.getWhereClause());
sql.append(" AND ");
}
sql.append(provider.getSortKey()).append(" > ").append(provider.getSortKeyPlaceHolder());
sql.append(provider.getSortKey());
if (provider.isAscending()) {
sql.append(" > ");
}
else {
sql.append(" < ");
}
sql.append(provider.getSortKeyPlaceHolder());
}
else {
sql.append(provider.getWhereClause() == null ? "" : " WHERE " + provider.getWhereClause());

View File

@@ -30,7 +30,9 @@ public class SqlWindowingPagingQueryProvider extends AbstractSqlPagingQueryProvi
StringBuilder sql = new StringBuilder();
sql.append("SELECT * FROM ( ");
sql.append("SELECT ").append(getSelectClause()).append(", ");
sql.append("ROW_NUMBER() OVER (ORDER BY ").append(getSortKey()).append(" ASC) AS ROW_NUMBER");
sql.append("ROW_NUMBER() OVER (ORDER BY ").append(getSortKey());
buildAscendingClause(sql);
sql.append(") AS ROW_NUMBER");
sql.append(" FROM ").append(getFromClause()).append(getWhereClause() == null ? "" : " WHERE " + getWhereClause());
sql.append(") WHERE ROW_NUMBER <= ").append(pageSize);
@@ -42,14 +44,23 @@ public class SqlWindowingPagingQueryProvider extends AbstractSqlPagingQueryProvi
StringBuilder sql = new StringBuilder();
sql.append("SELECT * FROM ( ");
sql.append("SELECT ").append(getSelectClause()).append(", ");
sql.append("ROW_NUMBER() OVER (ORDER BY ").append(getSortKey()).append(" ASC) AS ROW_NUMBER");
sql.append("ROW_NUMBER() OVER (ORDER BY ").append(getSortKey());
buildAscendingClause(sql);
sql.append(") AS ROW_NUMBER");
sql.append(" FROM ").append(getFromClause());
sql.append(" WHERE ");
if (getWhereClause() != null) {
sql.append(getWhereClause());
sql.append(" AND ");
}
sql.append(getSortKey()).append(" > ").append(getSortKeyPlaceHolder());
sql.append(getSortKey());
if (isAscending()) {
sql.append(" > ");
}
else {
sql.append(" < ");
}
sql.append(getSortKeyPlaceHolder());
sql.append(") WHERE ROW_NUMBER <= ").append(pageSize);
return sql.toString();
@@ -59,15 +70,29 @@ public class SqlWindowingPagingQueryProvider extends AbstractSqlPagingQueryProvi
public String generateJumpToItemQuery(int itemIndex, int pageSize) {
int page = itemIndex / pageSize;
int lastRowNum = (page * pageSize);
if (lastRowNum<=0) {
lastRowNum = 1;
}
StringBuilder sql = new StringBuilder();
sql.append("SELECT SORT_KEY FROM ( ");
sql.append("SELECT ").append(getSortKey()).append(" AS SORT_KEY, ");
sql.append("ROW_NUMBER() OVER (ORDER BY ").append(getSortKey()).append(" ASC) AS ROW_NUMBER");
sql.append("ROW_NUMBER() OVER (ORDER BY ").append(getSortKey());
buildAscendingClause(sql);
sql.append(") AS ROW_NUMBER");
sql.append(" FROM ").append(getFromClause()).append(getWhereClause() == null ? "" : " WHERE " + getWhereClause());
sql.append(") WHERE ROW_NUMBER = ").append(lastRowNum);
return sql.toString();
}
private void buildAscendingClause(StringBuilder sql) {
if (isAscending()) {
sql.append(" ASC");
}
else {
sql.append(" DESC");
}
}
}

View File

@@ -15,6 +15,8 @@
*/
package org.springframework.batch.item.database.support;
import static org.junit.Assert.assertTrue;
import org.junit.Before;
import org.junit.Test;
@@ -40,6 +42,19 @@ public abstract class AbstractSqlPagingQueryProviderTests {
}
@Test
public void testQueryContainsSortKey(){
String s = pagingQueryProvider.generateFirstPageQuery(pageSize).toLowerCase();
assertTrue("Wrong query: "+s, s.contains("id asc"));
}
@Test
public void testQueryContainsSortKeyDesc(){
pagingQueryProvider.setAscending(false);
String s = pagingQueryProvider.generateFirstPageQuery(pageSize).toLowerCase();
assertTrue("Wrong query: "+s, s.contains("id desc"));
}
@Test
public abstract void testGenerateFirstPageQuery();
@@ -48,5 +63,8 @@ public abstract class AbstractSqlPagingQueryProviderTests {
@Test
public abstract void testGenerateJumpToItemQuery();
@Test
public abstract void testGenerateJumpToItemQueryForFirstPage();
}

View File

@@ -33,4 +33,12 @@ public class Db2PagingQueryProviderTests extends AbstractSqlPagingQueryProviderT
String s = pagingQueryProvider.generateJumpToItemQuery(145, pageSize);
Assert.assertEquals("", sql, s);
}
@Test @Override
public void testGenerateJumpToItemQueryForFirstPage() {
String sql = "SELECT SORT_KEY FROM ( SELECT id AS SORT_KEY, ROW_NUMBER() OVER (ORDER BY id ASC) AS ROW_NUMBER FROM foo WHERE bar = 1) WHERE ROW_NUMBER = 1";
String s = pagingQueryProvider.generateJumpToItemQuery(45, pageSize);
Assert.assertEquals("", sql, s);
}
}

View File

@@ -98,4 +98,12 @@ public class DerbyPagingQueryProviderTests extends AbstractSqlPagingQueryProvide
String s = pagingQueryProvider.generateJumpToItemQuery(145, pageSize);
Assert.assertEquals("", sql, s);
}
@Test @Override
public void testGenerateJumpToItemQueryForFirstPage() {
String sql = "SELECT SORT_KEY FROM ( SELECT id AS SORT_KEY, ROW_NUMBER() OVER (ORDER BY id ASC) AS ROW_NUMBER FROM foo WHERE bar = 1) WHERE ROW_NUMBER = 1";
String s = pagingQueryProvider.generateJumpToItemQuery(45, pageSize);
Assert.assertEquals("", sql, s);
}
}

View File

@@ -48,4 +48,11 @@ public class HsqlPagingQueryProviderTests extends AbstractSqlPagingQueryProvider
String s = pagingQueryProvider.generateJumpToItemQuery(145, pageSize);
Assert.assertEquals("", sql, s);
}
@Test @Override
public void testGenerateJumpToItemQueryForFirstPage() {
String sql = "SELECT LIMIT 0 1 id AS SORT_KEY FROM foo WHERE bar = 1 ORDER BY id ASC";
String s = pagingQueryProvider.generateJumpToItemQuery(45, pageSize);
Assert.assertEquals("", sql, s);
}
}

View File

@@ -48,4 +48,11 @@ public class MySqlPagingQueryProviderTests extends AbstractSqlPagingQueryProvide
String s = pagingQueryProvider.generateJumpToItemQuery(145, pageSize);
Assert.assertEquals("", sql, s);
}
@Test @Override
public void testGenerateJumpToItemQueryForFirstPage() {
String sql = "SELECT id AS SORT_KEY FROM foo WHERE bar = 1 ORDER BY id ASC LIMIT 0, 1";
String s = pagingQueryProvider.generateJumpToItemQuery(45, pageSize);
Assert.assertEquals("", sql, s);
}
}

View File

@@ -37,4 +37,11 @@ public class OraclePagingQueryProviderTests extends AbstractSqlPagingQueryProvid
String s = pagingQueryProvider.generateJumpToItemQuery(145, pageSize);
Assert.assertEquals("", sql, s);
}
@Test @Override
public void testGenerateJumpToItemQueryForFirstPage() {
String sql = "SELECT SORT_KEY FROM ( SELECT id AS SORT_KEY, ROW_NUMBER() OVER (ORDER BY id ASC) AS ROW_NUMBER FROM foo WHERE bar = 1) WHERE ROW_NUMBER = 1";
String s = pagingQueryProvider.generateJumpToItemQuery(45, pageSize);
Assert.assertEquals("", sql, s);
}
}

View File

@@ -33,4 +33,12 @@ public class PostgresPagingQueryProviderTests extends AbstractSqlPagingQueryProv
String s = pagingQueryProvider.generateJumpToItemQuery(145, pageSize);
Assert.assertEquals("", sql, s);
}
@Test @Override
public void testGenerateJumpToItemQueryForFirstPage() {
String sql = "SELECT id AS SORT_KEY FROM foo WHERE bar = 1 ORDER BY id ASC LIMIT 0 1";
String s = pagingQueryProvider.generateJumpToItemQuery(45, pageSize);
Assert.assertEquals("", sql, s);
}
}

View File

@@ -16,11 +16,15 @@
package org.springframework.batch.item.database.support;
import org.junit.Assert;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.springframework.util.StringUtils;
/**
* @author Thomas Risberg
* @author Dave Syer
* @since 2.0
*/
public class SqlPagingQueryUtilsTests {
@@ -28,65 +32,118 @@ public class SqlPagingQueryUtilsTests {
@Test
public void testGenerateLimitSqlQuery() {
AbstractSqlPagingQueryProvider qp = new TestSqlPagingQueryProvider("FOO", "BAR", "ID");
Assert.assertEquals("SELECT FOO FROM BAR ORDER BY ID ASC LIMIT 100", SqlPagingQueryUtils.generateLimitSqlQuery(
qp, false, "LIMIT 100"));
Assert.assertEquals("SELECT FOO FROM BAR WHERE ID > ? ORDER BY ID ASC LIMIT 100", SqlPagingQueryUtils.generateLimitSqlQuery(
qp, true, "LIMIT 100"));
assertEquals("SELECT FOO FROM BAR ORDER BY ID ASC LIMIT 100", SqlPagingQueryUtils.generateLimitSqlQuery(qp,
false, "LIMIT 100"));
assertEquals("SELECT FOO FROM BAR WHERE ID > ? ORDER BY ID ASC LIMIT 100", SqlPagingQueryUtils
.generateLimitSqlQuery(qp, true, "LIMIT 100"));
qp.setWhereClause("BAZ IS NOT NULL");
Assert.assertEquals("SELECT FOO FROM BAR WHERE BAZ IS NOT NULL ORDER BY ID ASC LIMIT 100", SqlPagingQueryUtils.generateLimitSqlQuery(
qp, false, "LIMIT 100"));
Assert.assertEquals("SELECT FOO FROM BAR WHERE BAZ IS NOT NULL AND ID > ? ORDER BY ID ASC LIMIT 100", SqlPagingQueryUtils.generateLimitSqlQuery(
qp, true, "LIMIT 100"));
assertEquals("SELECT FOO FROM BAR WHERE BAZ IS NOT NULL ORDER BY ID ASC LIMIT 100", SqlPagingQueryUtils
.generateLimitSqlQuery(qp, false, "LIMIT 100"));
assertEquals("SELECT FOO FROM BAR WHERE BAZ IS NOT NULL AND ID > ? ORDER BY ID ASC LIMIT 100",
SqlPagingQueryUtils.generateLimitSqlQuery(qp, true, "LIMIT 100"));
}
@Test
public void testGenerateTopSqlQuery() {
AbstractSqlPagingQueryProvider qp = new TestSqlPagingQueryProvider("FOO", "BAR", "ID");
Assert.assertEquals("SELECT TOP 100 FOO FROM BAR ORDER BY ID ASC", SqlPagingQueryUtils.generateTopSqlQuery(
qp, false, "TOP 100"));
Assert.assertEquals("SELECT TOP 100 FOO FROM BAR WHERE ID > ? ORDER BY ID ASC", SqlPagingQueryUtils.generateTopSqlQuery(
qp, true, "TOP 100"));
assertEquals("SELECT TOP 100 FOO FROM BAR ORDER BY ID ASC", SqlPagingQueryUtils.generateTopSqlQuery(qp, false,
"TOP 100"));
assertEquals("SELECT TOP 100 FOO FROM BAR WHERE ID > ? ORDER BY ID ASC", SqlPagingQueryUtils
.generateTopSqlQuery(qp, true, "TOP 100"));
qp.setWhereClause("BAZ IS NOT NULL");
Assert.assertEquals("SELECT TOP 100 FOO FROM BAR WHERE BAZ IS NOT NULL ORDER BY ID ASC", SqlPagingQueryUtils.generateTopSqlQuery(
qp, false, "TOP 100"));
Assert.assertEquals("SELECT TOP 100 FOO FROM BAR WHERE BAZ IS NOT NULL AND ID > ? ORDER BY ID ASC", SqlPagingQueryUtils.generateTopSqlQuery(
qp, true, "TOP 100"));
assertEquals("SELECT TOP 100 FOO FROM BAR WHERE BAZ IS NOT NULL ORDER BY ID ASC", SqlPagingQueryUtils
.generateTopSqlQuery(qp, false, "TOP 100"));
assertEquals("SELECT TOP 100 FOO FROM BAR WHERE BAZ IS NOT NULL AND ID > ? ORDER BY ID ASC",
SqlPagingQueryUtils.generateTopSqlQuery(qp, true, "TOP 100"));
}
@Test
public void testGenerateRowNumSqlQuery() {
AbstractSqlPagingQueryProvider qp = new TestSqlPagingQueryProvider("FOO", "BAR", "ID");
Assert.assertEquals("SELECT FOO FROM BAR WHERE ROWNUMBER <= 100 ORDER BY ID ASC", SqlPagingQueryUtils.generateRowNumSqlQuery(
qp, false, "ROWNUMBER <= 100"));
Assert.assertEquals("SELECT FOO FROM BAR WHERE ID > ? AND ROWNUMBER <= 100 ORDER BY ID ASC", SqlPagingQueryUtils.generateRowNumSqlQuery(
qp, true, "ROWNUMBER <= 100"));
assertEquals("SELECT FOO FROM BAR WHERE ROWNUMBER <= 100 ORDER BY ID ASC", SqlPagingQueryUtils
.generateRowNumSqlQuery(qp, false, "ROWNUMBER <= 100"));
assertEquals("SELECT FOO FROM BAR WHERE ID > ? AND ROWNUMBER <= 100 ORDER BY ID ASC", SqlPagingQueryUtils
.generateRowNumSqlQuery(qp, true, "ROWNUMBER <= 100"));
qp.setWhereClause("BAZ IS NOT NULL");
Assert.assertEquals("SELECT FOO FROM BAR WHERE BAZ IS NOT NULL AND ROWNUMBER <= 100 ORDER BY ID ASC", SqlPagingQueryUtils.generateRowNumSqlQuery(
qp, false, "ROWNUMBER <= 100"));
Assert.assertEquals("SELECT FOO FROM BAR WHERE BAZ IS NOT NULL AND ID > ? AND ROWNUMBER <= 100 ORDER BY ID ASC", SqlPagingQueryUtils.generateRowNumSqlQuery(
qp, true, "ROWNUMBER <= 100"));
assertEquals("SELECT FOO FROM BAR WHERE BAZ IS NOT NULL AND ROWNUMBER <= 100 ORDER BY ID ASC",
SqlPagingQueryUtils.generateRowNumSqlQuery(qp, false, "ROWNUMBER <= 100"));
assertEquals("SELECT FOO FROM BAR WHERE BAZ IS NOT NULL AND ID > ? AND ROWNUMBER <= 100 ORDER BY ID ASC",
SqlPagingQueryUtils.generateRowNumSqlQuery(qp, true, "ROWNUMBER <= 100"));
}
@Test
public void testGenerateTopSqlQueryDescending() {
AbstractSqlPagingQueryProvider qp = new TestSqlPagingQueryProvider("FOO", "BAR", "ID");
qp.setAscending(false);
assertEquals("SELECT TOP 100 FOO FROM BAR ORDER BY ID DESC", SqlPagingQueryUtils.generateTopSqlQuery(qp, false,
"TOP 100"));
assertEquals("SELECT TOP 100 FOO FROM BAR WHERE ID < ? ORDER BY ID DESC", SqlPagingQueryUtils
.generateTopSqlQuery(qp, true, "TOP 100"));
qp.setWhereClause("BAZ IS NOT NULL");
assertEquals("SELECT TOP 100 FOO FROM BAR WHERE BAZ IS NOT NULL ORDER BY ID DESC", SqlPagingQueryUtils
.generateTopSqlQuery(qp, false, "TOP 100"));
assertEquals("SELECT TOP 100 FOO FROM BAR WHERE BAZ IS NOT NULL AND ID < ? ORDER BY ID DESC",
SqlPagingQueryUtils.generateTopSqlQuery(qp, true, "TOP 100"));
}
@Test
public void testGenerateRowNumSqlQueryDescending() {
AbstractSqlPagingQueryProvider qp = new TestSqlPagingQueryProvider("FOO", "BAR", "ID");
qp.setAscending(false);
assertEquals("SELECT FOO FROM BAR WHERE ROWNUMBER <= 100 ORDER BY ID DESC", SqlPagingQueryUtils
.generateRowNumSqlQuery(qp, false, "ROWNUMBER <= 100"));
assertEquals("SELECT FOO FROM BAR WHERE ID < ? AND ROWNUMBER <= 100 ORDER BY ID DESC", SqlPagingQueryUtils
.generateRowNumSqlQuery(qp, true, "ROWNUMBER <= 100"));
qp.setWhereClause("BAZ IS NOT NULL");
assertEquals("SELECT FOO FROM BAR WHERE BAZ IS NOT NULL AND ROWNUMBER <= 100 ORDER BY ID DESC",
SqlPagingQueryUtils.generateRowNumSqlQuery(qp, false, "ROWNUMBER <= 100"));
assertEquals("SELECT FOO FROM BAR WHERE BAZ IS NOT NULL AND ID < ? AND ROWNUMBER <= 100 ORDER BY ID DESC",
SqlPagingQueryUtils.generateRowNumSqlQuery(qp, true, "ROWNUMBER <= 100"));
}
@Test
public void testGenerateLimitJumpToQuery() {
AbstractSqlPagingQueryProvider qp = new TestSqlPagingQueryProvider("FOO", "BAR", "ID");
Assert.assertEquals("SELECT ID AS SORT_KEY FROM BAR ORDER BY ID ASC LIMIT 100, 1", SqlPagingQueryUtils.generateLimitJumpToQuery(
qp, "LIMIT 100, 1"));
assertEquals("SELECT ID AS SORT_KEY FROM BAR ORDER BY ID ASC LIMIT 100, 1", SqlPagingQueryUtils
.generateLimitJumpToQuery(qp, "LIMIT 100, 1"));
qp.setWhereClause("BAZ IS NOT NULL");
Assert.assertEquals("SELECT ID AS SORT_KEY FROM BAR WHERE BAZ IS NOT NULL ORDER BY ID ASC LIMIT 100, 1", SqlPagingQueryUtils.generateLimitJumpToQuery(
qp, "LIMIT 100, 1"));
assertEquals("SELECT ID AS SORT_KEY FROM BAR WHERE BAZ IS NOT NULL ORDER BY ID ASC LIMIT 100, 1",
SqlPagingQueryUtils.generateLimitJumpToQuery(qp, "LIMIT 100, 1"));
}
@Test
public void testGenerateTopJumpToQuery() {
AbstractSqlPagingQueryProvider qp = new TestSqlPagingQueryProvider("FOO", "BAR", "ID");
Assert.assertEquals("SELECT TOP 100, 1 ID AS SORT_KEY FROM BAR ORDER BY ID ASC", SqlPagingQueryUtils.generateTopJumpToQuery(
qp, "TOP 100, 1"));
assertEquals("SELECT TOP 100, 1 ID AS SORT_KEY FROM BAR ORDER BY ID ASC", SqlPagingQueryUtils
.generateTopJumpToQuery(qp, "TOP 100, 1"));
qp.setWhereClause("BAZ IS NOT NULL");
Assert.assertEquals("SELECT TOP 100, 1 ID AS SORT_KEY FROM BAR WHERE BAZ IS NOT NULL ORDER BY ID ASC", SqlPagingQueryUtils.generateTopJumpToQuery(
qp, "TOP 100, 1"));
assertEquals("SELECT TOP 100, 1 ID AS SORT_KEY FROM BAR WHERE BAZ IS NOT NULL ORDER BY ID ASC",
SqlPagingQueryUtils.generateTopJumpToQuery(qp, "TOP 100, 1"));
}
@Test
public void testGenerateTopJumpQueryDescending() {
AbstractSqlPagingQueryProvider qp = new TestSqlPagingQueryProvider("FOO", "BAR", "ID");
qp.setAscending(false);
String query = SqlPagingQueryUtils.generateTopJumpToQuery(qp, "TOP 100, 1");
assertTrue("Wrong query: " + query, query.contains("ID DESC"));
assertEquals("Wrong query: " + query, 0, StringUtils.countOccurrencesOf(query, "ASC"));
assertEquals("Wrong query: " + query, 1, StringUtils.countOccurrencesOf(query, "DESC"));
qp.setWhereClause("BAZ IS NOT NULL");
assertTrue("Wrong query: " + query, query.contains("ID DESC"));
}
@Test
public void testGenerateLimtJumpQueryDescending() {
AbstractSqlPagingQueryProvider qp = new TestSqlPagingQueryProvider("FOO", "BAR", "ID");
qp.setAscending(false);
String query = SqlPagingQueryUtils.generateLimitJumpToQuery(qp, "LIMIT 100, 1");
assertTrue("Wrong query: " + query, query.contains("ID DESC"));
assertEquals("Wrong query: " + query, 0, StringUtils.countOccurrencesOf(query, "ASC"));
assertEquals("Wrong query: " + query, 1, StringUtils.countOccurrencesOf(query, "DESC"));
qp.setWhereClause("BAZ IS NOT NULL");
assertTrue("Wrong query: " + query, query.contains("ID DESC"));
}
private static class TestSqlPagingQueryProvider extends AbstractSqlPagingQueryProvider {

View File

@@ -33,4 +33,12 @@ public class SqlServerPagingQueryProviderTests extends AbstractSqlPagingQueryPro
String s = pagingQueryProvider.generateJumpToItemQuery(145, pageSize);
Assert.assertEquals("", sql, s);
}
@Test @Override
public void testGenerateJumpToItemQueryForFirstPage() {
String sql = "SELECT SORT_KEY FROM ( SELECT id AS SORT_KEY, ROW_NUMBER() OVER (ORDER BY id ASC) AS ROW_NUMBER FROM foo WHERE bar = 1) WHERE ROW_NUMBER = 1";
String s = pagingQueryProvider.generateJumpToItemQuery(45, pageSize);
Assert.assertEquals("", sql, s);
}
}

View File

@@ -17,6 +17,7 @@ package org.springframework.batch.item.database.support;
import static org.junit.Assert.*;
import org.junit.Assert;
import org.junit.Test;
/**
@@ -48,4 +49,12 @@ public class SqlWindowingPagingQueryProviderTests extends AbstractSqlPagingQuery
String s = pagingQueryProvider.generateJumpToItemQuery(145, pageSize);
assertEquals("", sql, s);
}
@Test @Override
public void testGenerateJumpToItemQueryForFirstPage() {
String sql = "SELECT SORT_KEY FROM ( SELECT id AS SORT_KEY, ROW_NUMBER() OVER (ORDER BY id ASC) AS ROW_NUMBER FROM foo WHERE bar = 1) WHERE ROW_NUMBER = 1";
String s = pagingQueryProvider.generateJumpToItemQuery(45, pageSize);
Assert.assertEquals("", sql, s);
}
}

View File

@@ -33,4 +33,11 @@ public class SybasePagingQueryProviderTests extends AbstractSqlPagingQueryProvid
String s = pagingQueryProvider.generateJumpToItemQuery(145, pageSize);
Assert.assertEquals("", sql, s);
}
@Test @Override
public void testGenerateJumpToItemQueryForFirstPage() {
String sql = "SELECT SORT_KEY FROM ( SELECT id AS SORT_KEY, ROW_NUMBER() OVER (ORDER BY id ASC) AS ROW_NUMBER FROM foo WHERE bar = 1) WHERE ROW_NUMBER = 1";
String s = pagingQueryProvider.generateJumpToItemQuery(45, pageSize);
Assert.assertEquals("", sql, s);
}
}