Skip to content

fix for BATCH-1691 allow to define groupBy for SqlPagingQueryProviderFactoryBean #5

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .project
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>spring-batch</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.maven.ide.eclipse.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.maven.ide.eclipse.maven2Nature</nature>
</natures>
</projectDescription>
8 changes: 8 additions & 0 deletions .settings/org.maven.ide.eclipse.prefs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#Mon Feb 07 12:03:26 CET 2011
activeProfiles=
eclipse.preferences.version=1
fullBuildGoals=process-test-resources
resolveWorkspaceProjects=true
resourceFilterGoals=process-resources resources\:testResources
skipCompilerPlugin=true
version=1
17 changes: 17 additions & 0 deletions archetypes/.project
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>spring-batch-archetype</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.maven.ide.eclipse.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.maven.ide.eclipse.maven2Nature</nature>
</natures>
</projectDescription>
8 changes: 8 additions & 0 deletions archetypes/.settings/org.maven.ide.eclipse.prefs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#Mon Feb 07 12:03:26 CET 2011
activeProfiles=
eclipse.preferences.version=1
fullBuildGoals=process-test-resources
resolveWorkspaceProjects=true
resourceFilterGoals=process-resources resources\:testResources
skipCompilerPlugin=true
version=1
Original file line number Diff line number Diff line change
Expand Up @@ -37,35 +37,30 @@
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;

/**
* <p>
* {@link org.springframework.batch.item.ItemReader} for reading database
* records using JDBC in a paging fashion.
* {@link org.springframework.batch.item.ItemReader} for reading database records using JDBC in a paging fashion.
* </p>
*
* <p>
* It executes the SQL built by the {@link PagingQueryProvider} to retrieve
* requested data. The query is executed using paged requests of a size
* specified in {@link #setPageSize(int)}. Additional pages are requested when
* needed as {@link #read()} method is called, returning an object corresponding
* to current position. On restart it uses the last sort key value to locate the
* first page to read (so it doesn't matter if the successfully processed itmes
* have been removed or modified).
* It executes the SQL built by the {@link PagingQueryProvider} to retrieve requested data. The query is executed using
* paged requests of a size specified in {@link #setPageSize(int)}. Additional pages are requested when needed as
* {@link #read()} method is called, returning an object corresponding to current position. On restart it uses the last
* sort key value to locate the first page to read (so it doesn't matter if the successfully processed itmes have been
* removed or modified).
* </p>
*
* <p>
* The performance of the paging depends on the database specific features
* available to limit the number of returned rows. Setting a fairly large page
* size and using a commit interval that matches the page size should provide
* better performance.
* The performance of the paging depends on the database specific features available to limit the number of returned
* rows. Setting a fairly large page size and using a commit interval that matches the page size should provide better
* performance.
* </p>
*
* <p>
* The implementation is thread-safe in between calls to
* {@link #open(ExecutionContext)}, but remember to use
* <code>saveState=false</code> if used in a multi-threaded client (no restart
* available).
* The implementation is thread-safe in between calls to {@link #open(ExecutionContext)}, but remember to use
* <code>saveState=false</code> if used in a multi-threaded client (no restart available).
* </p>
*
* @author Thomas Risberg
Expand Down Expand Up @@ -108,57 +103,55 @@ public void setDataSource(DataSource dataSource) {
}

/**
* Gives the JDBC driver a hint as to the number of rows that should be
* fetched from the database when more rows are needed for this
* <code>ResultSet</code> object. If the fetch size specified is zero, the
* JDBC driver ignores the value.
* Gives the JDBC driver a hint as to the number of rows that should be fetched from the database when more rows are
* needed for this <code>ResultSet</code> object. If the fetch size specified is zero, the JDBC driver ignores the
* value.
*
* @param fetchSize the number of rows to fetch
* @param fetchSize
* the number of rows to fetch
* @see ResultSet#setFetchSize(int)
*/
public void setFetchSize(int fetchSize) {
this.fetchSize = fetchSize;
}

/**
* A {@link PagingQueryProvider}. Supplies all the platform dependent query
* generation capabilities needed by the reader.
* A {@link PagingQueryProvider}. Supplies all the platform dependent query generation capabilities needed by the
* reader.
*
* @param queryProvider the {@link PagingQueryProvider} to use
* @param queryProvider
* the {@link PagingQueryProvider} to use
*/
public void setQueryProvider(PagingQueryProvider queryProvider) {
this.queryProvider = queryProvider;
}

/**
* The row mapper implementation to be used by this reader. The row mapper
* is used to convert result set rows into objects, which are then returned
* by the reader.
* The row mapper implementation to be used by this reader. The row mapper is used to convert result set rows into
* objects, which are then returned by the reader.
*
* @param rowMapper a
* {@link org.springframework.jdbc.core.simple.ParameterizedRowMapper}
* implementation
* @param rowMapper
* a {@link org.springframework.jdbc.core.simple.ParameterizedRowMapper} implementation
*/
public void setRowMapper(RowMapper rowMapper) {
this.rowMapper = rowMapper;
}

/**
* The parameter values to be used for the query execution. If you use named
* parameters then the key should be the name used in the query clause. If
* you use "?" placeholders then the key should be the relative index that
* the parameter appears in the query string built using the select, from
* and where clauses specified.
* The parameter values to be used for the query execution. If you use named parameters then the key should be the
* name used in the query clause. If you use "?" placeholders then the key should be the relative index that the
* parameter appears in the query string built using the select, from and where clauses specified.
*
* @param parameterValues the values keyed by the parameter named/index used
* in the query string.
* @param parameterValues
* the values keyed by the parameter named/index used in the query string.
*/
public void setParameterValues(Map<String, Object> parameterValues) {
this.parameterValues = parameterValues;
}

/**
* Check mandatory properties.
*
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
public void afterPropertiesSet() throws Exception {
Expand All @@ -181,8 +174,7 @@ protected void doReadPage() {

if (results == null) {
results = new CopyOnWriteArrayList<T>();
}
else {
} else {
results.clear();
}

Expand All @@ -198,31 +190,27 @@ protected void doReadPage() {
if (this.queryProvider.isUsingNamedParameters()) {
query = simpleJdbcTemplate.getNamedParameterJdbcOperations().query(firstPageSql,
getParameterMap(parameterValues, null), rowCallback);
}
else {
} else {
query = simpleJdbcTemplate.getJdbcOperations().query(firstPageSql,
getParameterList(parameterValues, null).toArray(), rowCallback);
}
}
else {
} else {
query = simpleJdbcTemplate.getJdbcOperations().query(firstPageSql, rowCallback);
}

}
else {
} else {
if (logger.isDebugEnabled()) {
logger.debug("SQL used for reading remaining pages: [" + remainingPagesSql + "]");
}
if (this.queryProvider.isUsingNamedParameters()) {
query = simpleJdbcTemplate.getNamedParameterJdbcOperations().query(remainingPagesSql,
getParameterMap(parameterValues, startAfterValue), rowCallback);
}
else {
} else {
query = simpleJdbcTemplate.getJdbcOperations().query(remainingPagesSql,
getParameterList(parameterValues, startAfterValue).toArray(), rowCallback);
}
}

@SuppressWarnings("unchecked")
Collection<T> result = (Collection<T>) query;
results.addAll(result);
Expand All @@ -248,8 +236,7 @@ public void open(ExecutionContext executionContext) {
@Override
protected void doJumpToPage(int itemIndex) {
/*
* Normally this would be false (the startAfterValue is enough
* information to restart from.
* Normally this would be false (the startAfterValue is enough information to restart from.
*/
if (startAfterValue == null && getPage() > 0) {

Expand All @@ -268,8 +255,7 @@ public Object mapRow(ResultSet rs, int i) throws SQLException {
if (this.queryProvider.isUsingNamedParameters()) {
startAfterValue = simpleJdbcTemplate.getNamedParameterJdbcOperations().queryForObject(jumpToItemSql,
getParameterMap(parameterValues, startAfterValue), startMapper);
}
else {
} else {
startAfterValue = simpleJdbcTemplate.getJdbcOperations().queryForObject(jumpToItemSql,
getParameterList(parameterValues, startAfterValue).toArray(), startMapper);
}
Expand Down Expand Up @@ -309,7 +295,11 @@ private List<Object> getParameterList(Map<String, Object> values, Object sortKey

private class PagingRowMapper implements RowMapper {
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
startAfterValue = rs.getObject(queryProvider.getSortKey());
if (StringUtils.hasText(queryProvider.getSortKeyAlias())) {
startAfterValue = rs.getObject(queryProvider.getSortKeyAlias());
} else {
startAfterValue = rs.getObject(queryProvider.getSortKey());
}
return rowMapper.mapRow(rs, rowNum);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,5 +81,7 @@ public interface PagingQueryProvider {
* @return the sort key used to order the query
*/
String getSortKey();

String getSortKeyAlias();

}
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,12 @@ public abstract class AbstractSqlPagingQueryProvider implements PagingQueryProvi
private String fromClause;

private String whereClause;

private String groupClause;

private String sortKey;

private String sortKeyAlias;

private boolean ascending = true;

Expand Down Expand Up @@ -178,6 +182,9 @@ public void init(DataSource dataSource) throws Exception {
if (whereClause != null) {
sql.append(" WHERE ").append(whereClause);
}
if (groupClause != null) {
sql.append(" GROUP BY ").append(groupClause);
}
List<String> namedParameters = new ArrayList<String>();
parameterCount = JdbcParameterUtils.countParameterPlaceholders(sql.toString(), namedParameters);
if (namedParameters.size() > 0) {
Expand Down Expand Up @@ -228,4 +235,21 @@ private String removeKeyWord(String keyWord, String clause) {
}
}

public void setGroupClause(String groupClause) {
this.groupClause = groupClause;
}

public String getGroupClause() {
return groupClause;
}

public void setSortKeyAlias(String sortKeyAlias) {
this.sortKeyAlias = sortKeyAlias;
}

public String getSortKeyAlias() {
return sortKeyAlias;
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,16 @@ protected String getOverClause() {

@Override
protected String getAfterWhereClause() {
StringBuilder sql = new StringBuilder();
if (getGroupClause() != null) {
sql.append(" GROUP BY ").append(getGroupClause());
}
if (version!=null && "10.6.1".compareTo(version) > 0) {
// Old behaviour retained, even though it is broken
return "";
return sql.toString();
}
return " " + super.getOverClause();
sql.append(" ").append(super.getOverClause());
return sql.toString();
}

}
Loading