mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
#802 - Find generics on findIds() - refactor internals of find ids to use find single attribute
This commit is contained in:
@@ -757,9 +757,9 @@ public interface EbeanServer {
|
||||
/**
|
||||
* Return the Id values of the query as a List.
|
||||
*
|
||||
* @see com.avaje.ebean.Query#findIds()
|
||||
* @see Query#findIds()
|
||||
*/
|
||||
<T> List<Object> findIds(Query<T> query, Transaction transaction);
|
||||
<A> List<A> findIds(Query<?> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute the query visiting the each bean one at a time.
|
||||
|
||||
@@ -174,7 +174,7 @@ public interface ExpressionList<T> {
|
||||
*
|
||||
* @see Query#findIds()
|
||||
*/
|
||||
List<Object> findIds();
|
||||
<A> List<A> findIds();
|
||||
|
||||
/**
|
||||
* Return the count of entities this query should return.
|
||||
|
||||
@@ -9,8 +9,6 @@ import java.util.concurrent.Future;
|
||||
* It extends the java.util.concurrent.Future with the ability to get the Id's
|
||||
* while the query is still executing in the background.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public interface FutureIds<T> extends Future<List<Object>> {
|
||||
|
||||
@@ -19,16 +17,4 @@ public interface FutureIds<T> extends Future<List<Object>> {
|
||||
*/
|
||||
Query<T> getQuery();
|
||||
|
||||
/**
|
||||
* Return the list of Id's which could be partially populated.
|
||||
* <p>
|
||||
* That is the query getting the id's could still be running and adding id's
|
||||
* to this list.
|
||||
* </p>
|
||||
* <p>
|
||||
* To get the list of Id's ensuring the query has finished use the
|
||||
* {@link Future#get()} method instead of this one.
|
||||
* </p>
|
||||
*/
|
||||
List<Object> getPartialIds();
|
||||
}
|
||||
|
||||
@@ -598,7 +598,7 @@ public abstract class Model {
|
||||
* <p>
|
||||
* Equivalent to {@link Query#findIds()}
|
||||
*/
|
||||
public List<Object> findIds() {
|
||||
public <A> List<A> findIds() {
|
||||
return query().findIds();
|
||||
}
|
||||
|
||||
|
||||
@@ -542,7 +542,7 @@ public interface Query<T> {
|
||||
*
|
||||
* @see EbeanServer#findIds(Query, Transaction)
|
||||
*/
|
||||
List<Object> findIds();
|
||||
<A> List<A> findIds();
|
||||
|
||||
/**
|
||||
* Execute the query processing the beans one at a time.
|
||||
|
||||
@@ -145,7 +145,7 @@ public interface SpiEbeanServer extends EbeanServer, BeanLoader, BeanCollectionL
|
||||
* the query has finished (if executing in a background thread).
|
||||
* </p>
|
||||
*/
|
||||
<T> List<Object> findIdsWithCopy(Query<T> query, Transaction t);
|
||||
<A> List<A> findIdsWithCopy(Query<?> query, Transaction t);
|
||||
|
||||
/**
|
||||
* Execute the findRowCount query but without copying the query.
|
||||
|
||||
@@ -251,21 +251,6 @@ public interface SpiQuery<T> extends Query<T> {
|
||||
|
||||
List<String> getSoftDeletePredicates();
|
||||
|
||||
/**
|
||||
* Set the list of Id's that is being populated.
|
||||
* <p>
|
||||
* This is a mutating list of id's and we are setting this so that other
|
||||
* threads have access to the id's before the id query has finished.
|
||||
* </p>
|
||||
*/
|
||||
void setIdList(List<Object> ids);
|
||||
|
||||
/**
|
||||
* Return the list of Id's that is currently being fetched by a background
|
||||
* thread.
|
||||
*/
|
||||
List<Object> getIdList();
|
||||
|
||||
/**
|
||||
* Return a copy of the query.
|
||||
*/
|
||||
|
||||
@@ -1191,16 +1191,14 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
}
|
||||
}
|
||||
|
||||
public <T> List<Object> findIds(Query<T> query, Transaction t) {
|
||||
public <A> List<A> findIds(Query<?> query, Transaction t) {
|
||||
|
||||
SpiQuery<T> copy = ((SpiQuery<T>) query).copy();
|
||||
|
||||
return findIdsWithCopy(copy, t);
|
||||
return findIdsWithCopy(((SpiQuery<?>) query).copy(), t);
|
||||
}
|
||||
|
||||
public <T> List<Object> findIdsWithCopy(Query<T> query, Transaction t) {
|
||||
public <A> List<A> findIdsWithCopy(Query<?> query, Transaction t) {
|
||||
|
||||
SpiOrmQueryRequest<T> request = createQueryRequest(Type.ID_LIST, query, t);
|
||||
SpiOrmQueryRequest<?> request = createQueryRequest(Type.ID_LIST, query, t);
|
||||
try {
|
||||
request.initTransIfRequired();
|
||||
return request.findIds();
|
||||
@@ -1258,12 +1256,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
SpiQuery<T> copy = ((SpiQuery<T>) query).copy();
|
||||
copy.setFutureFetch(true);
|
||||
|
||||
// this is the list we will put the id's in ... create it now so
|
||||
// it is available for other threads to read while the id query
|
||||
// is still executing (we don't need to wait for it to finish)
|
||||
List<Object> idList = Collections.synchronizedList(new ArrayList<Object>());
|
||||
copy.setIdList(idList);
|
||||
|
||||
Transaction newTxn = createTransaction();
|
||||
|
||||
CallableQueryIds<T> call = new CallableQueryIds<T>(this, copy, newTxn);
|
||||
|
||||
@@ -44,7 +44,7 @@ public interface OrmQueryEngine {
|
||||
/**
|
||||
* Execute the find id's query.
|
||||
*/
|
||||
<T> BeanIdList findIds(OrmQueryRequest<T> request);
|
||||
<A> List<A> findIds(OrmQueryRequest<?> request);
|
||||
|
||||
/**
|
||||
* Execute the query as a delete statement.
|
||||
|
||||
@@ -304,9 +304,8 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
return queryEngine.findRowCount(this);
|
||||
}
|
||||
|
||||
public List<Object> findIds() {
|
||||
BeanIdList idList = queryEngine.findIds(this);
|
||||
return idList.getIdList();
|
||||
public <A> List<A> findIds() {
|
||||
return queryEngine.findIds(this);
|
||||
}
|
||||
|
||||
public void findEach(QueryEachConsumer<T> consumer) {
|
||||
|
||||
@@ -70,7 +70,7 @@ public interface SpiOrmQueryRequest<T> extends DocQueryRequest<T> {
|
||||
/**
|
||||
* Execute the find ids query.
|
||||
*/
|
||||
List<Object> findIds();
|
||||
<A> List<A> findIds();
|
||||
|
||||
/**
|
||||
* Execute the find returning a QueryIterator and visitor pattern.
|
||||
|
||||
@@ -354,7 +354,7 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Object> findIds() {
|
||||
public <A> List<A> findIds() {
|
||||
return query.findIds();
|
||||
}
|
||||
|
||||
|
||||
@@ -189,33 +189,12 @@ public class CQueryBuilder {
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the row count query.
|
||||
* Build the find ids query.
|
||||
*/
|
||||
public <T> CQueryFetchIds buildFetchIdsQuery(OrmQueryRequest<T> request) {
|
||||
public <T> CQueryFetchSingleAttribute buildFetchIdsQuery(OrmQueryRequest<T> request) {
|
||||
|
||||
SpiQuery<T> query = request.getQuery();
|
||||
query.setSelectId();
|
||||
|
||||
CQueryPredicates predicates = new CQueryPredicates(binder, request);
|
||||
CQueryPlan queryPlan = request.getQueryPlan();
|
||||
if (queryPlan != null) {
|
||||
// skip building the SqlTree and Sql string
|
||||
predicates.prepare(false);
|
||||
return new CQueryFetchIds(request, predicates, queryPlan.getSql());
|
||||
}
|
||||
|
||||
// use RawSql or generated Sql
|
||||
predicates.prepare(true);
|
||||
|
||||
SqlTree sqlTree = createSqlTree(request, predicates, getHistorySupport(query), getDraftSupport(query));
|
||||
SqlLimitResponse s = buildSql(null, request, predicates, sqlTree);
|
||||
String sql = s.getSql();
|
||||
|
||||
// cache the query plan
|
||||
queryPlan = new CQueryPlan(request, sql, sqlTree, false, s.isIncludesRowNumberColumn(), predicates.getLogWhereSql());
|
||||
|
||||
request.putQueryPlan(queryPlan);
|
||||
return new CQueryFetchIds(request, predicates, sql);
|
||||
request.getQuery().setSelectId();
|
||||
return buildFetchAttributeQuery(request);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
package com.avaje.ebeaninternal.server.query;
|
||||
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebeaninternal.server.core.QueryIterator;
|
||||
import com.avaje.ebean.ValuePair;
|
||||
import com.avaje.ebean.Version;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.bean.ObjectGraphNode;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebeaninternal.api.BeanIdList;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
import com.avaje.ebeaninternal.server.core.DiffHelp;
|
||||
import com.avaje.ebeaninternal.server.core.OrmQueryRequest;
|
||||
import com.avaje.ebeaninternal.server.core.QueryIterator;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.lib.util.Str;
|
||||
import com.avaje.ebeaninternal.server.persist.Binder;
|
||||
@@ -94,8 +93,13 @@ public class CQueryEngine {
|
||||
public <A> List<A> findSingleAttributeList(OrmQueryRequest<?> request) {
|
||||
|
||||
CQueryFetchSingleAttribute rcQuery = queryBuilder.buildFetchAttributeQuery(request);
|
||||
return findAttributeList(request, rcQuery);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <A> List<A> findAttributeList(OrmQueryRequest<?> request, CQueryFetchSingleAttribute rcQuery) {
|
||||
try {
|
||||
List list = rcQuery.findList();
|
||||
List<A> list = (List<A>)rcQuery.findList();
|
||||
if (request.isLogSql()) {
|
||||
logGeneratedSql(request, rcQuery.getGeneratedSql(), rcQuery.getBindLog());
|
||||
}
|
||||
@@ -112,29 +116,10 @@ public class CQueryEngine {
|
||||
/**
|
||||
* Build and execute the find Id's query.
|
||||
*/
|
||||
public <T> BeanIdList findIds(OrmQueryRequest<T> request) {
|
||||
public <A> List<A> findIds(OrmQueryRequest<?> request) {
|
||||
|
||||
CQueryFetchIds rcQuery = queryBuilder.buildFetchIdsQuery(request);
|
||||
try {
|
||||
|
||||
BeanIdList list = rcQuery.findIds();
|
||||
if (request.isLogSql()) {
|
||||
logGeneratedSql(request, rcQuery.getGeneratedSql(), rcQuery.getBindLog());
|
||||
}
|
||||
if (request.isLogSummary()) {
|
||||
request.getTransaction().logSummary(rcQuery.getSummary());
|
||||
}
|
||||
if (request.getQuery().isFutureFetch()) {
|
||||
// end the transaction for futureFindIds (it had it's own one)
|
||||
logger.debug("Future findIds completed!");
|
||||
request.getTransaction().end();
|
||||
}
|
||||
|
||||
return list;
|
||||
|
||||
} catch (SQLException e) {
|
||||
throw CQuery.createPersistenceException(e, request.getTransaction(), rcQuery.getBindLog(), rcQuery.getGeneratedSql());
|
||||
}
|
||||
CQueryFetchSingleAttribute rcQuery = queryBuilder.buildFetchIdsQuery(request);
|
||||
return findAttributeList(request, rcQuery);
|
||||
}
|
||||
|
||||
private <T> void logGeneratedSql(OrmQueryRequest<T> request, String sql, String bindLog) {
|
||||
|
||||
@@ -1,208 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.query;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.bean.EntityBeanIntercept;
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery.Mode;
|
||||
import com.avaje.ebeaninternal.api.SpiTransaction;
|
||||
import com.avaje.ebeaninternal.server.core.OrmQueryRequest;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
import com.avaje.ebeaninternal.server.deploy.DbReadContext;
|
||||
import com.avaje.ebeaninternal.server.type.DataReader;
|
||||
import com.avaje.ebeaninternal.server.type.RsetDataReader;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Base compiled query request for single attribute queries.
|
||||
*/
|
||||
public abstract class CQueryFetchBase {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(CQueryFetchBase.class);
|
||||
|
||||
/**
|
||||
* The overall find request wrapper object.
|
||||
*/
|
||||
protected final OrmQueryRequest<?> request;
|
||||
|
||||
protected final BeanDescriptor<?> desc;
|
||||
|
||||
protected final SpiQuery<?> query;
|
||||
|
||||
/**
|
||||
* Where clause predicates.
|
||||
*/
|
||||
protected final CQueryPredicates predicates;
|
||||
|
||||
/**
|
||||
* The final sql that is generated.
|
||||
*/
|
||||
protected final String sql;
|
||||
|
||||
protected RsetDataReader dataReader;
|
||||
|
||||
/**
|
||||
* The statement used to create the resultSet.
|
||||
*/
|
||||
protected PreparedStatement pstmt;
|
||||
|
||||
protected String bindLog;
|
||||
|
||||
protected int executionTimeMicros;
|
||||
|
||||
protected int rowCount;
|
||||
|
||||
protected final int maxRows;
|
||||
|
||||
/**
|
||||
* Create the Sql select based on the request.
|
||||
*/
|
||||
public CQueryFetchBase(OrmQueryRequest<?> request, CQueryPredicates predicates, String sql) {
|
||||
|
||||
this.request = request;
|
||||
this.query = request.getQuery();
|
||||
this.sql = sql;
|
||||
this.maxRows = query.getMaxRows();
|
||||
|
||||
query.setGeneratedSql(sql);
|
||||
|
||||
this.desc = request.getBeanDescriptor();
|
||||
this.predicates = predicates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bind log.
|
||||
*/
|
||||
public String getBindLog() {
|
||||
return bindLog;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the generated sql.
|
||||
*/
|
||||
public String getGeneratedSql() {
|
||||
return sql;
|
||||
}
|
||||
|
||||
protected ResultSet prepareExecute() throws SQLException {
|
||||
|
||||
SpiTransaction t = request.getTransaction();
|
||||
Connection conn = t.getInternalConnection();
|
||||
pstmt = conn.prepareStatement(sql);
|
||||
|
||||
if (query.getBufferFetchSizeHint() > 0) {
|
||||
pstmt.setFetchSize(query.getBufferFetchSizeHint());
|
||||
}
|
||||
if (query.getTimeout() > 0) {
|
||||
pstmt.setQueryTimeout(query.getTimeout());
|
||||
}
|
||||
|
||||
bindLog = predicates.bind(pstmt, conn);
|
||||
|
||||
ResultSet rset = pstmt.executeQuery();
|
||||
dataReader = new RsetDataReader(request.getDataTimeZone(), rset);
|
||||
return rset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the resources.
|
||||
* <p>
|
||||
* The jdbc resultSet and statement need to be closed. Its important that
|
||||
* this method is called.
|
||||
* </p>
|
||||
*/
|
||||
protected void close() {
|
||||
try {
|
||||
if (dataReader != null) {
|
||||
dataReader.close();
|
||||
dataReader = null;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
logger.error("Error closing DataReader", e);
|
||||
}
|
||||
try {
|
||||
if (pstmt != null) {
|
||||
pstmt.close();
|
||||
pstmt = null;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
logger.error("Error closing PreparedStatement", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected class DbContext implements DbReadContext {
|
||||
|
||||
public void propagateState(Object e) {
|
||||
throw new RuntimeException("Not Called");
|
||||
}
|
||||
|
||||
public Mode getQueryMode() {
|
||||
return Mode.NORMAL;
|
||||
}
|
||||
|
||||
public DataReader getDataReader() {
|
||||
return dataReader;
|
||||
}
|
||||
|
||||
public Boolean isReadOnly() {
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDisableLazyLoading() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isRawSql() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void register(String path, EntityBeanIntercept ebi) {
|
||||
}
|
||||
|
||||
public void register(String path, BeanCollection<?> bc) {
|
||||
}
|
||||
|
||||
public BeanPropertyAssocMany<?> getManyProperty() {
|
||||
// always null
|
||||
return null;
|
||||
}
|
||||
|
||||
public PersistenceContext getPersistenceContext() {
|
||||
// always null
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isAutoTuneProfiling() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void profileBean(EntityBeanIntercept ebi, String prefix) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
public void setCurrentPrefix(String currentPrefix, Map<String, String> pathMap) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
public void setLazyLoadedChildBean(EntityBean loadedBean, Object lazyLoadParentId) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDraftQuery() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.query;
|
||||
|
||||
import com.avaje.ebeaninternal.api.BeanIdList;
|
||||
import com.avaje.ebeaninternal.server.core.OrmQueryRequest;
|
||||
import com.avaje.ebeaninternal.server.deploy.DbReadContext;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Executes the select row count query.
|
||||
*/
|
||||
public class CQueryFetchIds extends CQueryFetchBase {
|
||||
|
||||
/**
|
||||
* Create the Sql select based on the request.
|
||||
*/
|
||||
public CQueryFetchIds(OrmQueryRequest<?> request, CQueryPredicates predicates, String sql) {
|
||||
super(request, predicates, sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a summary description of this query.
|
||||
*/
|
||||
public String getSummary() {
|
||||
StringBuilder sb = new StringBuilder(80);
|
||||
sb.append("FindIds exeMicros[").append(executionTimeMicros)
|
||||
.append("] rows[").append(rowCount)
|
||||
.append("] type[").append(desc.getName())
|
||||
.append("] predicates[").append(predicates.getLogWhereSql())
|
||||
.append("] bind[").append(bindLog).append("]");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the query returning the row count.
|
||||
*/
|
||||
public BeanIdList findIds() throws SQLException {
|
||||
|
||||
long startNano = System.nanoTime();
|
||||
|
||||
try {
|
||||
// get the list that we are going to put the id's into.
|
||||
// This was already set so that it is available to be
|
||||
// read by other threads (it is a synchronised list)
|
||||
List<Object> idList = query.getIdList();
|
||||
if (idList == null) {
|
||||
// running in foreground thread (not FutureIds query)
|
||||
idList = Collections.synchronizedList(new ArrayList<Object>());
|
||||
query.setIdList(idList);
|
||||
}
|
||||
|
||||
BeanIdList result = new BeanIdList(idList);
|
||||
|
||||
ResultSet rset = prepareExecute();
|
||||
|
||||
boolean hitMaxRows = false;
|
||||
boolean hasMoreRows = false;
|
||||
rowCount = 0;
|
||||
|
||||
DbReadContext ctx = new DbContext();
|
||||
|
||||
while (rset.next()) {
|
||||
Object idValue = desc.getIdBinder().read(ctx);
|
||||
idList.add(idValue);
|
||||
// reset back to 0
|
||||
dataReader.resetColumnPosition();
|
||||
rowCount++;
|
||||
|
||||
if (maxRows > 0 && rowCount == maxRows) {
|
||||
hitMaxRows = true;
|
||||
hasMoreRows = rset.next();
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (hitMaxRows) {
|
||||
result.setHasMore(hasMoreRows);
|
||||
}
|
||||
|
||||
long exeNano = System.nanoTime() - startNano;
|
||||
executionTimeMicros = (int) exeNano / 1000;
|
||||
|
||||
return result;
|
||||
|
||||
} finally {
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+113
-12
@@ -1,20 +1,58 @@
|
||||
package com.avaje.ebeaninternal.server.query;
|
||||
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
import com.avaje.ebeaninternal.api.SpiTransaction;
|
||||
import com.avaje.ebeaninternal.server.core.OrmQueryRequest;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.type.RsetDataReader;
|
||||
import com.avaje.ebeaninternal.server.type.ScalarType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Executes the select row count query.
|
||||
* Base compiled query request for single attribute queries.
|
||||
*/
|
||||
public class CQueryFetchSingleAttribute extends CQueryFetchBase {
|
||||
class CQueryFetchSingleAttribute {
|
||||
|
||||
private final BeanProperty property;
|
||||
private static final Logger logger = LoggerFactory.getLogger(CQueryFetchSingleAttribute.class);
|
||||
|
||||
/**
|
||||
* The overall find request wrapper object.
|
||||
*/
|
||||
private final OrmQueryRequest<?> request;
|
||||
|
||||
private final BeanDescriptor<?> desc;
|
||||
|
||||
private final SpiQuery<?> query;
|
||||
|
||||
/**
|
||||
* Where clause predicates.
|
||||
*/
|
||||
private final CQueryPredicates predicates;
|
||||
|
||||
/**
|
||||
* The final sql that is generated.
|
||||
*/
|
||||
private final String sql;
|
||||
|
||||
private RsetDataReader dataReader;
|
||||
|
||||
/**
|
||||
* The statement used to create the resultSet.
|
||||
*/
|
||||
private PreparedStatement pstmt;
|
||||
|
||||
private String bindLog;
|
||||
|
||||
private int executionTimeMicros;
|
||||
|
||||
private int rowCount;
|
||||
|
||||
private final ScalarType<Object> scalarType;
|
||||
|
||||
@@ -22,15 +60,20 @@ public class CQueryFetchSingleAttribute extends CQueryFetchBase {
|
||||
* Create the Sql select based on the request.
|
||||
*/
|
||||
public CQueryFetchSingleAttribute(OrmQueryRequest<?> request, CQueryPredicates predicates, CQueryPlan plan) {
|
||||
super(request, predicates, plan.getSql());
|
||||
this.property = plan.getSingleProperty();
|
||||
this.scalarType = property.getScalarType();
|
||||
this.request = request;
|
||||
this.query = request.getQuery();
|
||||
this.sql = plan.getSql();
|
||||
this.desc = request.getBeanDescriptor();
|
||||
this.predicates = predicates;
|
||||
this.scalarType = plan.getSingleProperty().getScalarType();
|
||||
|
||||
query.setGeneratedSql(sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a summary description of this query.
|
||||
*/
|
||||
public String getSummary() {
|
||||
protected String getSummary() {
|
||||
StringBuilder sb = new StringBuilder(80);
|
||||
sb.append("FindAttr exeMicros[").append(executionTimeMicros)
|
||||
.append("] rows[").append(rowCount)
|
||||
@@ -44,15 +87,16 @@ public class CQueryFetchSingleAttribute extends CQueryFetchBase {
|
||||
/**
|
||||
* Execute the query returning the row count.
|
||||
*/
|
||||
public List<Object> findList() throws SQLException {
|
||||
protected List<Object> findList() throws SQLException {
|
||||
|
||||
long startNano = System.nanoTime();
|
||||
try {
|
||||
|
||||
prepareExecute();
|
||||
|
||||
List<Object> result = new ArrayList<Object>();
|
||||
|
||||
ResultSet rset = prepareExecute();
|
||||
while (rset.next()) {
|
||||
while (dataReader.next()) {
|
||||
result.add(scalarType.read(dataReader));
|
||||
dataReader.resetColumnPosition();
|
||||
rowCount++;
|
||||
@@ -68,4 +112,61 @@ public class CQueryFetchSingleAttribute extends CQueryFetchBase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bind log.
|
||||
*/
|
||||
protected String getBindLog() {
|
||||
return bindLog;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the generated sql.
|
||||
*/
|
||||
protected String getGeneratedSql() {
|
||||
return sql;
|
||||
}
|
||||
|
||||
private void prepareExecute() throws SQLException {
|
||||
|
||||
SpiTransaction t = request.getTransaction();
|
||||
Connection conn = t.getInternalConnection();
|
||||
pstmt = conn.prepareStatement(sql);
|
||||
|
||||
if (query.getBufferFetchSizeHint() > 0) {
|
||||
pstmt.setFetchSize(query.getBufferFetchSizeHint());
|
||||
}
|
||||
if (query.getTimeout() > 0) {
|
||||
pstmt.setQueryTimeout(query.getTimeout());
|
||||
}
|
||||
|
||||
bindLog = predicates.bind(pstmt, conn);
|
||||
dataReader = new RsetDataReader(request.getDataTimeZone(), pstmt.executeQuery());
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the resources.
|
||||
* <p>
|
||||
* The jdbc resultSet and statement need to be closed. Its important that
|
||||
* this method is called.
|
||||
* </p>
|
||||
*/
|
||||
private void close() {
|
||||
try {
|
||||
if (dataReader != null) {
|
||||
dataReader.close();
|
||||
dataReader = null;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
logger.error("Error closing DataReader", e);
|
||||
}
|
||||
try {
|
||||
if (pstmt != null) {
|
||||
pstmt.close();
|
||||
pstmt = null;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
logger.error("Error closing PreparedStatement", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ public class DefaultOrmQueryEngine implements OrmQueryEngine {
|
||||
return queryEngine.findRowCount(request);
|
||||
}
|
||||
|
||||
public <T> BeanIdList findIds(OrmQueryRequest<T> request) {
|
||||
public <A> List<A> findIds(OrmQueryRequest<?> request) {
|
||||
|
||||
flushJdbcBatchOnQuery(request);
|
||||
return queryEngine.findIds(request);
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package com.avaje.ebeaninternal.server.query;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.FutureTask;
|
||||
|
||||
import com.avaje.ebean.FutureIds;
|
||||
import com.avaje.ebean.Query;
|
||||
import com.avaje.ebean.Transaction;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.FutureTask;
|
||||
|
||||
/**
|
||||
* Default implementation of FutureIds.
|
||||
*/
|
||||
@@ -31,10 +31,6 @@ public class QueryFutureIds<T> extends BaseFuture<List<Object>> implements Futur
|
||||
return call.query;
|
||||
}
|
||||
|
||||
public List<Object> getPartialIds() {
|
||||
return call.query.getIdList();
|
||||
}
|
||||
|
||||
public boolean cancel(boolean mayInterruptIfRunning) {
|
||||
call.query.cancel();
|
||||
return super.cancel(mayInterruptIfRunning);
|
||||
|
||||
@@ -123,8 +123,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
*/
|
||||
private ReadEvent futureFetchAudit;
|
||||
|
||||
private List<Object> partialIds;
|
||||
|
||||
private int timeout;
|
||||
|
||||
/**
|
||||
@@ -1509,16 +1507,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
return disableReadAudit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Object> getIdList() {
|
||||
return partialIds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIdList(List<Object> partialIds) {
|
||||
this.partialIds = partialIds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFutureFetch() {
|
||||
return futureFetch;
|
||||
|
||||
Reference in New Issue
Block a user