package org.nextprot.api.core.dao.impl.spring;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Set;
import javax.sql.DataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
/**
* Replaces NamedParameterJdbcTemplate when the list of ids it too big
* JDBC prepared statement has a limit of 32767, therefore if the number of ids is bigger a not so obvious exception is thrown: the PostgreSQL client/backend protocol dictates that the number of parameters be send from the client to the Postgres backend as a 2 byte integer (aaah, now the above message actually makes sense). You’ll find details of the protocol
* This class allows to send the request in batch of 32767 if the list of ids is bigger
* Don't use this class if your list of ids is not that big
*
* @author dteixeira
*
*/
public class BatchNamedParameterJdbcTemplate extends NamedParameterJdbcTemplate {
private static final int JDBC_PARAM_LIMIT = 32767;
private static final Log LOGGER = LogFactory.getLog(BatchNamedParameterJdbcTemplate.class);
public BatchNamedParameterJdbcTemplate(DataSource dataSource) {
super(dataSource);
}
/**
* Used to query in batch
* @param sql The sql
* @param paramIdsName the name of the bind variable
* @param paramIds the list of ids (bigger than 32767)
* @param rowMapper the row mapper
* @return
*/
public <T> List<T> query(String sql, String paramIdsName, List<Long> paramIds, RowMapper<T> rowMapper) {
Set<T> result = new HashSet<T>();
Queue<Long> keys = new LinkedList<Long>(paramIds);
int bcount = 0;
while (!keys.isEmpty()) {
List<Long> subIds = new ArrayList<Long>();
for (int i = 0; i < JDBC_PARAM_LIMIT && !keys.isEmpty(); i++) {
subIds.add(keys.remove());
}
MapSqlParameterSource subParams = new MapSqlParameterSource("ids", subIds);
LOGGER.debug("Sending batch" + bcount + " of " + subIds.size() + " size");
result.addAll(super.query(sql, subParams, rowMapper));
}
return new ArrayList<T>(result);
}
}