mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Merge remote-tracking branch 'ebean/master'
This commit is contained in:
@@ -4,7 +4,6 @@ import java.io.Externalizable;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectOutput;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.avaje.ebeaninternal.server.cache;
|
||||
|
||||
import com.avaje.ebean.BackgroundExecutor;
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.cache.ServerCache;
|
||||
import com.avaje.ebean.cache.ServerCacheOptions;
|
||||
import com.avaje.ebean.cache.ServerCacheStatistics;
|
||||
|
||||
@@ -68,11 +68,11 @@ public abstract class BeanRequest {
|
||||
public void rollbackTransIfRequired() {
|
||||
if (createdTransaction) {
|
||||
try {
|
||||
transaction.rollback();
|
||||
transaction.rollbackIfActive();
|
||||
} catch (Exception e) {
|
||||
// Just log this and carry on. A previous exception has been
|
||||
// thrown and if this rollback throws exception it likely means
|
||||
// that the connection is broken (and the datasource and db will cleanup)
|
||||
// that the connection is broken (and the dataSource and db will cleanup)
|
||||
log.error("Error trying to rollback a transaction (after a prior exception thrown)", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,4 +84,9 @@ public class DefaultBeanState implements BeanState {
|
||||
public boolean isDisableLazyLoad() {
|
||||
return intercept.isDisableLazyLoad();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetForInsert() {
|
||||
intercept.setNew();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,7 +195,6 @@ public class DefaultContainer implements SpiContainer {
|
||||
bootup.addPersistControllers(serverConfig.getPersistControllers());
|
||||
bootup.addPostLoaders(serverConfig.getPostLoaders());
|
||||
bootup.addFindControllers(serverConfig.getFindControllers());
|
||||
bootup.addTransactionEventListeners(serverConfig.getTransactionEventListeners());
|
||||
bootup.addPersistListeners(serverConfig.getPersistListeners());
|
||||
bootup.addQueryAdapters(serverConfig.getQueryAdapters());
|
||||
bootup.addServerConfigStartup(serverConfig.getServerConfigStartupListeners());
|
||||
|
||||
@@ -71,10 +71,8 @@ import javax.persistence.NonUniqueResultException;
|
||||
import javax.persistence.OptimisticLockException;
|
||||
import javax.persistence.PersistenceException;
|
||||
import javax.sql.DataSource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -1134,30 +1132,52 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public <T> Map<?, T> findMap(Query<T> query, Transaction t) {
|
||||
public <K, T> Map<K, T> findMap(Query<T> query, Transaction t) {
|
||||
|
||||
SpiOrmQueryRequest request = createQueryRequest(Type.MAP, query, t);
|
||||
|
||||
Object result = request.getFromQueryCache();
|
||||
if (result != null) {
|
||||
return (Map<?, T>) result;
|
||||
return (Map<K, T>) result;
|
||||
}
|
||||
|
||||
try {
|
||||
request.initTransIfRequired();
|
||||
return (Map<?, T>) request.findMap();
|
||||
return (Map<K, T>) request.findMap();
|
||||
|
||||
} finally {
|
||||
request.endTransIfRequired();
|
||||
}
|
||||
}
|
||||
|
||||
public <T> int findRowCount(Query<T> query, Transaction t) {
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <A> List<A> findSingleAttributeList(Query<?> query, Transaction t) {
|
||||
|
||||
SpiOrmQueryRequest request = createQueryRequest(Type.ATTRIBUTE, query, t);
|
||||
Object result = request.getFromQueryCache();
|
||||
if (result != null) {
|
||||
return (List<A>) result;
|
||||
}
|
||||
try {
|
||||
request.initTransIfRequired();
|
||||
return (List<A>) request.findSingleAttributeList();
|
||||
|
||||
} finally {
|
||||
request.endTransIfRequired();
|
||||
}
|
||||
}
|
||||
|
||||
public <T> int findCount(Query<T> query, Transaction t) {
|
||||
|
||||
SpiQuery<T> copy = ((SpiQuery<T>) query).copy();
|
||||
return findRowCountWithCopy(copy, t);
|
||||
}
|
||||
|
||||
public <T> int findRowCount(Query<T> query, Transaction t) {
|
||||
return findCount(query, t);
|
||||
}
|
||||
|
||||
public <T> int findRowCountWithCopy(Query<T> query, Transaction t) {
|
||||
|
||||
SpiOrmQueryRequest<T> request = createQueryRequest(Type.ROWCOUNT, query, t);
|
||||
@@ -1170,16 +1190,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();
|
||||
@@ -1213,7 +1231,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
}
|
||||
}
|
||||
|
||||
public <T> FutureRowCount<T> findFutureRowCount(Query<T> q, Transaction t) {
|
||||
public <T> FutureRowCount<T> findFutureCount(Query<T> q, Transaction t) {
|
||||
|
||||
SpiQuery<T> copy = ((SpiQuery<T>) q).copy();
|
||||
copy.setFutureFetch(true);
|
||||
@@ -1228,17 +1246,15 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
return queryFuture;
|
||||
}
|
||||
|
||||
public <T> FutureRowCount<T> findFutureRowCount(Query<T> q, Transaction t) {
|
||||
return findFutureCount(q, t);
|
||||
}
|
||||
|
||||
public <T> FutureIds<T> findFutureIds(Query<T> query, Transaction t) {
|
||||
|
||||
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);
|
||||
@@ -1286,6 +1302,19 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
return new LimitOffsetPagedList<T>(this, spiQuery);
|
||||
}
|
||||
|
||||
public <T> QueryIterator<T> findIterate(Query<T> query, Transaction t) {
|
||||
|
||||
SpiOrmQueryRequest<T> request = createQueryRequest(Type.ITERATE, query, t);
|
||||
try {
|
||||
request.initTransIfRequired();
|
||||
return request.findIterate();
|
||||
|
||||
} catch (RuntimeException ex) {
|
||||
request.endTransIfRequired();
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
public <T> void findEach(Query<T> query, QueryEachConsumer<T> consumer, Transaction t) {
|
||||
|
||||
SpiOrmQueryRequest<T> request = createQueryRequest(Type.ITERATE, query, t);
|
||||
|
||||
@@ -340,14 +340,14 @@ public class InternalConfiguration {
|
||||
|
||||
boolean localL2 = cacheManager.isLocalL2Caching();
|
||||
if (serverConfig.isExplicitTransactionBeginMode()) {
|
||||
return new ExplicitTransactionManager(localL2, serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, beanDescriptorManager, this.getBootupClasses());
|
||||
return new ExplicitTransactionManager(localL2, serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, beanDescriptorManager);
|
||||
}
|
||||
|
||||
if (isAutoCommitMode()) {
|
||||
return new AutoCommitTransactionManager(localL2, serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, beanDescriptorManager, this.getBootupClasses());
|
||||
return new AutoCommitTransactionManager(localL2, serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, beanDescriptorManager);
|
||||
}
|
||||
|
||||
return new TransactionManager(localL2, serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, beanDescriptorManager, this.getBootupClasses());
|
||||
return new TransactionManager(localL2, serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, beanDescriptorManager);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import com.avaje.ebean.QueryIterator;
|
||||
import com.avaje.ebean.Version;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebeaninternal.api.BeanIdList;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -21,6 +21,14 @@ public interface OrmQueryEngine {
|
||||
*/
|
||||
<T> BeanCollection<T> findMany(OrmQueryRequest<T> request);
|
||||
|
||||
/**
|
||||
* Execute the findSingleAttributeList query.
|
||||
*/
|
||||
<A> List<A> findSingleAttributeList(OrmQueryRequest<?> request);
|
||||
|
||||
/**
|
||||
* Execute the findVersions query.
|
||||
*/
|
||||
<T> List<Version<T>> findVersions(OrmQueryRequest<T> request);
|
||||
|
||||
/**
|
||||
@@ -36,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.
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.avaje.ebeaninternal.server.core;
|
||||
import com.avaje.ebean.PersistenceContextScope;
|
||||
import com.avaje.ebean.QueryEachConsumer;
|
||||
import com.avaje.ebean.QueryEachWhileConsumer;
|
||||
import com.avaje.ebean.QueryIterator;
|
||||
import com.avaje.ebean.RawSql;
|
||||
import com.avaje.ebean.Version;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
@@ -12,7 +13,6 @@ import com.avaje.ebean.event.BeanFindController;
|
||||
import com.avaje.ebean.event.BeanQueryAdapter;
|
||||
import com.avaje.ebean.event.BeanQueryRequest;
|
||||
import com.avaje.ebean.text.json.JsonReadOptions;
|
||||
import com.avaje.ebeaninternal.api.BeanIdList;
|
||||
import com.avaje.ebeaninternal.api.CQueryPlanKey;
|
||||
import com.avaje.ebeaninternal.api.HashQuery;
|
||||
import com.avaje.ebeaninternal.api.LoadContext;
|
||||
@@ -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) {
|
||||
@@ -373,6 +372,14 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
return (Map<?, ?>) queryEngine.findMany(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the findSingleAttributeList query.
|
||||
*/
|
||||
@Override
|
||||
public <A> List<A> findSingleAttributeList() {
|
||||
return queryEngine.findSingleAttributeList(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a bean specific finder if one has been set.
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import com.avaje.ebean.ValuePair;
|
||||
import com.avaje.ebean.bean.PreGetterCallback;
|
||||
import com.avaje.ebeaninternal.api.ConcurrencyMode;
|
||||
import com.avaje.ebean.annotation.DocStoreMode;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
@@ -36,7 +37,7 @@ import java.util.Set;
|
||||
/**
|
||||
* PersistRequest for insert update or delete of a bean.
|
||||
*/
|
||||
public final class PersistRequestBean<T> extends PersistRequest implements BeanPersistRequest<T>, DocStoreUpdate {
|
||||
public final class PersistRequestBean<T> extends PersistRequest implements BeanPersistRequest<T>, DocStoreUpdate, PreGetterCallback {
|
||||
|
||||
private final BeanManager<T> beanManager;
|
||||
|
||||
@@ -137,6 +138,11 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
|
||||
private long version;
|
||||
|
||||
/**
|
||||
* Flag set when request is added to JDBC batch registered as a "getter callback" to automatically flush batch.
|
||||
*/
|
||||
private boolean getterCallback;
|
||||
|
||||
public PersistRequestBean(SpiEbeanServer server, T bean, Object parentBean, BeanManager<T> mgr, SpiTransaction t,
|
||||
PersistExecute persistExecute, PersistRequest.Type type, boolean saveRecurse, boolean publish) {
|
||||
|
||||
@@ -239,8 +245,17 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
*/
|
||||
public void setBatched() {
|
||||
batched = true;
|
||||
if (type == Type.INSERT || type == Type.UPDATE) {
|
||||
// used to trigger automatic jdbc batch flush
|
||||
intercept.registerGetterCallback(this);
|
||||
getterCallback = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preGetterTrigger() {
|
||||
transaction.flushBatch();
|
||||
}
|
||||
|
||||
public void setSkipBatchForTopLevel() {
|
||||
skipBatchForTopLevel = true;
|
||||
@@ -621,6 +636,9 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
|
||||
@Override
|
||||
public int executeNow() {
|
||||
if (getterCallback) {
|
||||
intercept.clearGetterCallback();
|
||||
}
|
||||
switch (type) {
|
||||
case INSERT:
|
||||
persistExecute.executeInsertBean(this);
|
||||
@@ -803,7 +821,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the bean to the TransactionEvent. This will be used by TransactionManager to synch Cache,
|
||||
* Add the bean to the TransactionEvent. This will be used by TransactionManager to sync Cache,
|
||||
* Cluster and text indexes.
|
||||
*/
|
||||
private void addEvent() {
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* Used to provide iteration over query results.
|
||||
* <p>
|
||||
* This can be used when you want to process a very large number of results and
|
||||
* means that you don't have to hold all the results in memory at once (unlike
|
||||
* findList(), findSet() etc where all the beans are held in the List or Set
|
||||
* etc).
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
*
|
||||
* Query<Customer> query = server.find(Customer.class)
|
||||
* .fetch("contacts", new FetchConfig().query(2))
|
||||
* .where().gt("id", 0)
|
||||
* .orderBy("id")
|
||||
* .setMaxRows(2);
|
||||
*
|
||||
* QueryIterator<Customer> it = query.findIterate();
|
||||
* try {
|
||||
* while (it.hasNext()) {
|
||||
* Customer customer = it.next();
|
||||
* // do something with customer...
|
||||
* }
|
||||
* } finally {
|
||||
* // close the associated resources
|
||||
* it.close();
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
* @param <T>
|
||||
* the type of entity bean in the iteration
|
||||
*/
|
||||
public interface QueryIterator<T> extends Iterator<T>, java.io.Closeable {
|
||||
|
||||
/**
|
||||
* Returns <tt>true</tt> if the iteration has more elements.
|
||||
*/
|
||||
boolean hasNext();
|
||||
|
||||
/**
|
||||
* Returns the next element in the iteration.
|
||||
*/
|
||||
T next();
|
||||
|
||||
/**
|
||||
* Remove is not allowed.
|
||||
*/
|
||||
void remove();
|
||||
|
||||
/**
|
||||
* Close the underlying resources held by this iterator.
|
||||
*/
|
||||
void close();
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import com.avaje.ebean.QueryEachConsumer;
|
||||
import com.avaje.ebean.QueryEachWhileConsumer;
|
||||
import com.avaje.ebean.QueryIterator;
|
||||
import com.avaje.ebean.Version;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
@@ -70,7 +71,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.
|
||||
@@ -107,6 +108,11 @@ public interface SpiOrmQueryRequest<T> extends DocQueryRequest<T> {
|
||||
*/
|
||||
Map<?, ?> findMap();
|
||||
|
||||
/**
|
||||
* Execute the findSingleAttributeList query.
|
||||
*/
|
||||
<A> List<A> findSingleAttributeList();
|
||||
|
||||
/**
|
||||
* Try to get the query result from the query cache.
|
||||
*/
|
||||
|
||||
@@ -41,7 +41,7 @@ final class TransWrapper {
|
||||
|
||||
void rollbackIfCreated() {
|
||||
if (wasCreated){
|
||||
transaction.rollback();
|
||||
transaction.rollbackIfActive();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ import com.avaje.ebean.event.BeanPersistListener;
|
||||
import com.avaje.ebean.event.BeanPostLoad;
|
||||
import com.avaje.ebean.event.BeanQueryAdapter;
|
||||
import com.avaje.ebean.event.ServerConfigStartup;
|
||||
import com.avaje.ebean.event.TransactionEventListener;
|
||||
import com.avaje.ebean.event.changelog.ChangeLogListener;
|
||||
import com.avaje.ebean.event.changelog.ChangeLogPrepare;
|
||||
import com.avaje.ebean.event.changelog.ChangeLogRegister;
|
||||
@@ -54,8 +53,6 @@ public class BootupClasses implements ClassFilter {
|
||||
|
||||
private final List<Class<?>> beanPostLoadList = new ArrayList<Class<?>>();
|
||||
|
||||
private final List<Class<?>> transactionEventListenerList = new ArrayList<Class<?>>();
|
||||
|
||||
private final List<Class<?>> beanFindControllerList = new ArrayList<Class<?>>();
|
||||
private final List<Class<?>> beanQueryAdapterList = new ArrayList<Class<?>>();
|
||||
|
||||
@@ -70,7 +67,6 @@ public class BootupClasses implements ClassFilter {
|
||||
private final List<BeanPostLoad> beanPostLoadInstances = new ArrayList<BeanPostLoad>();
|
||||
private final List<BeanPersistListener> persistListenerInstances = new ArrayList<BeanPersistListener>();
|
||||
private final List<BeanQueryAdapter> queryAdapterInstances = new ArrayList<BeanQueryAdapter>();
|
||||
private final List<TransactionEventListener> transactionEventListenerInstances = new ArrayList<TransactionEventListener>();
|
||||
|
||||
private Class<?> changeLogPrepareClass;
|
||||
private Class<?> changeLogListenerClass;
|
||||
@@ -181,19 +177,6 @@ public class BootupClasses implements ClassFilter {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add TransactionEventListeners instances.
|
||||
*/
|
||||
public void addTransactionEventListeners(List<TransactionEventListener> transactionEventListeners) {
|
||||
if (transactionEventListeners != null) {
|
||||
for (TransactionEventListener c : transactionEventListeners) {
|
||||
this.transactionEventListenerInstances.add(c);
|
||||
// don't automatically instantiate
|
||||
this.transactionEventListenerList.remove(c.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addPersistListeners(List<BeanPersistListener> listenerInstances) {
|
||||
if (listenerInstances != null) {
|
||||
for (BeanPersistListener l : listenerInstances) {
|
||||
@@ -351,14 +334,6 @@ public class BootupClasses implements ClassFilter {
|
||||
return idGeneratorInstances;
|
||||
}
|
||||
|
||||
public List<TransactionEventListener> getTransactionEventListeners() {
|
||||
// add class registered TransactionEventListener to the already created instances
|
||||
for (Class<?> cls : transactionEventListenerList) {
|
||||
createAdd(cls, transactionEventListenerInstances);
|
||||
}
|
||||
return transactionEventListenerInstances;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of Embeddable classes.
|
||||
*/
|
||||
@@ -440,11 +415,6 @@ public class BootupClasses implements ClassFilter {
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
if (TransactionEventListener.class.isAssignableFrom(cls)) {
|
||||
transactionEventListenerList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
if (ScalarType.class.isAssignableFrom(cls)) {
|
||||
scalarTypeList.add(cls);
|
||||
interesting = true;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.bean.EntityBeanIntercept;
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebeaninternal.server.query.SqlJoinType;
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.bean.EntityBeanIntercept;
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebeaninternal.server.query.SqlJoinType;
|
||||
|
||||
|
||||
@@ -357,7 +357,7 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> {
|
||||
|
||||
String tableAlias = manyToMany ? "int_." : "t0.";
|
||||
if (manyToMany) {
|
||||
query.setIncludeTableJoin(inverseJoin);
|
||||
query.setM2MIncludeJoin(inverseJoin);
|
||||
}
|
||||
String rawWhere = deriveWhereParentIdSql(true, tableAlias);
|
||||
String expr = descriptor.getParentIdInExpr(parentIds.size(), rawWhere);
|
||||
|
||||
@@ -3,7 +3,6 @@ package com.avaje.ebeaninternal.server.deploy;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.bean.BeanCollectionAdd;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.api.ClassUtil;
|
||||
import com.avaje.ebeaninternal.server.text.json.ReadJson;
|
||||
import com.fasterxml.jackson.core.JsonParseException;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
|
||||
@@ -217,12 +217,10 @@ public final class IdBinderSimple implements IdBinder {
|
||||
if (!idValue.getClass().equals(expectedType)) {
|
||||
idValue = scalarType.toBeanType(idValue);
|
||||
}
|
||||
|
||||
if (bean != null) {
|
||||
// support PropertyChangeSupport
|
||||
idProperty.setValueIntercept(bean, idValue);
|
||||
}
|
||||
|
||||
return idValue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,11 +22,6 @@ public interface ImportedId {
|
||||
*/
|
||||
boolean isScalar();
|
||||
|
||||
/**
|
||||
* Return the logical property name.
|
||||
*/
|
||||
String getLogicalName();
|
||||
|
||||
/**
|
||||
* For scalar id return the related single db column.
|
||||
* <p>
|
||||
@@ -46,11 +41,6 @@ public interface ImportedId {
|
||||
*/
|
||||
void dmlAppend(GenerateDmlRequest request);
|
||||
|
||||
/**
|
||||
* Append to the DML statement to the where clause.
|
||||
*/
|
||||
void dmlWhere(GenerateDmlRequest request, EntityBean bean);
|
||||
|
||||
/**
|
||||
* Bind the value from the bean.
|
||||
*/
|
||||
|
||||
@@ -46,11 +46,6 @@ public class ImportedIdEmbedded implements ImportedId {
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getLogicalName() {
|
||||
return owner.getName() + "." + foreignAssocOne.getName();
|
||||
}
|
||||
|
||||
|
||||
public String getDbColumn() {
|
||||
return null;
|
||||
}
|
||||
@@ -68,34 +63,6 @@ public class ImportedIdEmbedded implements ImportedId {
|
||||
}
|
||||
}
|
||||
|
||||
public void dmlWhere(GenerateDmlRequest request, EntityBean bean) {
|
||||
|
||||
Object embeddedId = null;
|
||||
if (bean != null) {
|
||||
embeddedId = foreignAssocOne.getValue(bean);
|
||||
}
|
||||
|
||||
if (embeddedId == null) {
|
||||
for (int i = 0; i < imported.length; i++) {
|
||||
if (imported[i].owner.isDbUpdatable()) {
|
||||
request.appendColumnIsNull(imported[i].localDbColumn);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
EntityBean embedded = (EntityBean) embeddedId;
|
||||
for (int i = 0; i < imported.length; i++) {
|
||||
if (imported[i].owner.isDbUpdatable()) {
|
||||
Object value = imported[i].foreignProperty.getValue(embedded);
|
||||
if (value == null) {
|
||||
request.appendColumnIsNull(imported[i].localDbColumn);
|
||||
} else {
|
||||
request.appendColumn(imported[i].localDbColumn);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Object bind(BindableRequest request, EntityBean bean) throws SQLException {
|
||||
|
||||
Object embeddedId = null;
|
||||
|
||||
@@ -82,10 +82,6 @@ public final class ImportedIdSimple implements ImportedId, Comparable<ImportedId
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getLogicalName() {
|
||||
return logicalName;
|
||||
}
|
||||
|
||||
public String getDbColumn() {
|
||||
return localDbColumn;
|
||||
}
|
||||
@@ -114,21 +110,6 @@ public final class ImportedIdSimple implements ImportedId, Comparable<ImportedId
|
||||
request.appendColumn(localDbColumn);
|
||||
}
|
||||
|
||||
public void dmlWhere(GenerateDmlRequest request, EntityBean bean) {
|
||||
|
||||
if (owner.isDbUpdatable()) {
|
||||
Object value = null;
|
||||
if (bean != null) {
|
||||
value = getIdValue(bean);
|
||||
}
|
||||
if (value == null) {
|
||||
request.appendColumnIsNull(localDbColumn);
|
||||
} else {
|
||||
request.appendColumn(localDbColumn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Object bind(BindableRequest request, EntityBean bean) throws SQLException {
|
||||
|
||||
Object value = null;
|
||||
|
||||
@@ -170,9 +170,7 @@ public class AnnotationAssocManys extends AnnotationParser {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the full table name
|
||||
* @param joinTable
|
||||
* @return
|
||||
* Return the full table name
|
||||
*/
|
||||
private String getFullTableName(JoinTable joinTable) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
@@ -4,8 +4,6 @@ import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
|
||||
|
||||
/**
|
||||
* Contains the various ElMatcher implementations.
|
||||
|
||||
+22
-12
@@ -253,11 +253,6 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
|
||||
return query.asDraft();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> includeSoftDeletes() {
|
||||
return setIncludeSoftDeletes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> setIncludeSoftDeletes() {
|
||||
return query.setIncludeSoftDeletes();
|
||||
@@ -323,9 +318,14 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
|
||||
return query.findFutureIds();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FutureRowCount<T> findFutureCount() {
|
||||
return query.findFutureCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FutureRowCount<T> findFutureRowCount() {
|
||||
return query.findFutureRowCount();
|
||||
return findFutureCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -339,15 +339,25 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int findRowCount() {
|
||||
return query.findRowCount();
|
||||
public int findCount() {
|
||||
return query.findCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Object> findIds() {
|
||||
public int findRowCount() {
|
||||
return findCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <A> List<A> findIds() {
|
||||
return query.findIds();
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryIterator<T> findIterate() {
|
||||
return query.findIterate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void findEach(QueryEachConsumer<T> consumer) {
|
||||
query.findEach(consumer);
|
||||
@@ -369,13 +379,13 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<?, T> findMap() {
|
||||
public <K> Map<K, T> findMap() {
|
||||
return query.findMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <K> Map<K, T> findMap(String keyProperty, Class<K> keyType) {
|
||||
return query.findMap(keyProperty, keyType);
|
||||
public <A> List<A> findSingleAttributeList() {
|
||||
return query.findSingleAttributeList();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -48,9 +48,14 @@ public class FilterExpressionList<T> extends DefaultExpressionList<T> {
|
||||
return rootQuery.findFutureList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FutureRowCount<T> findFutureCount() {
|
||||
return rootQuery.findFutureCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FutureRowCount<T> findFutureRowCount() {
|
||||
return rootQuery.findFutureRowCount();
|
||||
return findFutureCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -59,13 +64,18 @@ public class FilterExpressionList<T> extends DefaultExpressionList<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<?, T> findMap() {
|
||||
public <K> Map<K, T> findMap() {
|
||||
return rootQuery.findMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int findCount() {
|
||||
return rootQuery.findCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int findRowCount() {
|
||||
return rootQuery.findRowCount();
|
||||
return findCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -12,6 +12,7 @@ import com.avaje.ebean.PagedList;
|
||||
import com.avaje.ebean.Query;
|
||||
import com.avaje.ebean.QueryEachConsumer;
|
||||
import com.avaje.ebean.QueryEachWhileConsumer;
|
||||
import com.avaje.ebean.QueryIterator;
|
||||
import com.avaje.ebean.Version;
|
||||
import com.avaje.ebean.event.BeanQueryRequest;
|
||||
import com.avaje.ebean.search.Match;
|
||||
@@ -62,6 +63,7 @@ class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expression
|
||||
* This is expected to only used after expressions are built via query language parsing.
|
||||
* </p>
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void simplify() {
|
||||
exprList.simplifyEntries();
|
||||
|
||||
@@ -325,11 +327,6 @@ class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expression
|
||||
return exprList.asDraft();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> includeSoftDeletes() {
|
||||
return setIncludeSoftDeletes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> setIncludeSoftDeletes() {
|
||||
return exprList.setIncludeSoftDeletes();
|
||||
@@ -361,15 +358,25 @@ class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expression
|
||||
}
|
||||
|
||||
@Override
|
||||
public FutureRowCount<T> findFutureRowCount() {
|
||||
return exprList.findFutureRowCount();
|
||||
public FutureRowCount<T> findFutureCount() {
|
||||
return exprList.findFutureCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Object> findIds() {
|
||||
public FutureRowCount<T> findFutureRowCount() {
|
||||
return findFutureCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <A> List<A> findIds() {
|
||||
return exprList.findIds();
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryIterator<T> findIterate() {
|
||||
return exprList.findIterate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void findEach(QueryEachConsumer<T> consumer) {
|
||||
exprList.findEach(consumer);
|
||||
@@ -386,13 +393,13 @@ class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expression
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<?, T> findMap() {
|
||||
public <K> Map<K, T> findMap() {
|
||||
return exprList.findMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <K> Map<K, T> findMap(String keyProperty, Class<K> keyType) {
|
||||
return exprList.findMap(keyProperty, keyType);
|
||||
public <A> List<A> findSingleAttributeList() {
|
||||
return exprList.findSingleAttributeList();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -401,10 +408,15 @@ class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expression
|
||||
}
|
||||
|
||||
@Override
|
||||
public int findRowCount() {
|
||||
public int findCount() {
|
||||
return exprList.findRowCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int findRowCount() {
|
||||
return findCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<T> findSet() {
|
||||
return exprList.findSet();
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
// Generated from /home/rob/github/avaje-ebeanorm/src/test/resources/EQL.g4 by ANTLR 4.5.3
|
||||
package com.avaje.ebeaninternal.server.grammer.antlr;
|
||||
import org.antlr.v4.runtime.Lexer;
|
||||
|
||||
import org.antlr.v4.runtime.CharStream;
|
||||
import org.antlr.v4.runtime.Token;
|
||||
import org.antlr.v4.runtime.TokenStream;
|
||||
import org.antlr.v4.runtime.*;
|
||||
import org.antlr.v4.runtime.atn.*;
|
||||
import org.antlr.v4.runtime.Lexer;
|
||||
import org.antlr.v4.runtime.RuntimeMetaData;
|
||||
import org.antlr.v4.runtime.Vocabulary;
|
||||
import org.antlr.v4.runtime.VocabularyImpl;
|
||||
import org.antlr.v4.runtime.atn.ATN;
|
||||
import org.antlr.v4.runtime.atn.ATNDeserializer;
|
||||
import org.antlr.v4.runtime.atn.LexerATNSimulator;
|
||||
import org.antlr.v4.runtime.atn.PredictionContextCache;
|
||||
import org.antlr.v4.runtime.dfa.DFA;
|
||||
import org.antlr.v4.runtime.misc.*;
|
||||
|
||||
@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"})
|
||||
public class EQLLexer extends Lexer {
|
||||
|
||||
@@ -1,13 +1,23 @@
|
||||
// Generated from /home/rob/github/avaje-ebeanorm/src/test/resources/EQL.g4 by ANTLR 4.5.3
|
||||
package com.avaje.ebeaninternal.server.grammer.antlr;
|
||||
import org.antlr.v4.runtime.atn.*;
|
||||
|
||||
import org.antlr.v4.runtime.NoViableAltException;
|
||||
import org.antlr.v4.runtime.Parser;
|
||||
import org.antlr.v4.runtime.ParserRuleContext;
|
||||
import org.antlr.v4.runtime.RecognitionException;
|
||||
import org.antlr.v4.runtime.RuntimeMetaData;
|
||||
import org.antlr.v4.runtime.TokenStream;
|
||||
import org.antlr.v4.runtime.Vocabulary;
|
||||
import org.antlr.v4.runtime.VocabularyImpl;
|
||||
import org.antlr.v4.runtime.atn.ATN;
|
||||
import org.antlr.v4.runtime.atn.ATNDeserializer;
|
||||
import org.antlr.v4.runtime.atn.ParserATNSimulator;
|
||||
import org.antlr.v4.runtime.atn.PredictionContextCache;
|
||||
import org.antlr.v4.runtime.dfa.DFA;
|
||||
import org.antlr.v4.runtime.*;
|
||||
import org.antlr.v4.runtime.misc.*;
|
||||
import org.antlr.v4.runtime.tree.*;
|
||||
import org.antlr.v4.runtime.tree.ParseTreeListener;
|
||||
import org.antlr.v4.runtime.tree.TerminalNode;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Iterator;
|
||||
import java.util.ArrayList;
|
||||
|
||||
@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"})
|
||||
public class EQLParser extends Parser {
|
||||
|
||||
@@ -1,186 +0,0 @@
|
||||
#
|
||||
# Used by MimeTypeHelper to find the mime types of based on file extensions.
|
||||
|
||||
abs=audio/x-mpeg
|
||||
ai=application/postscript
|
||||
aif=audio/x-aiff
|
||||
aifc=audio/x-aiff
|
||||
aiff=audio/x-aiff
|
||||
aim=application/x-aim
|
||||
art=image/x-jg
|
||||
asc=text/plain
|
||||
asf=video/x-ms-asf
|
||||
asx=video/x-ms-asf
|
||||
au=audio/basic
|
||||
avi=video/x-msvideo
|
||||
avx=video/x-rad-screenplay
|
||||
|
||||
bcpio=application/x-bcpio
|
||||
bin=application/octet-stream
|
||||
bmp=image/bmp
|
||||
body=text/html
|
||||
|
||||
cdf=application/x-netcdf
|
||||
cer=application/x-x509-ca-cert
|
||||
class=application/java
|
||||
cpio=application/x-cpio
|
||||
csh=application/x-csh
|
||||
css=text/css
|
||||
csv=text/csv
|
||||
|
||||
dib=image/bmp
|
||||
doc=application/msword
|
||||
dtd=application/xml-dtd
|
||||
dv=video/x-dv
|
||||
dvi=application/x-dvi
|
||||
dms=application/octet-stream
|
||||
|
||||
eps=application/postscript
|
||||
etx=text/x-setext
|
||||
exe=application/octet-stream
|
||||
|
||||
gif=image/gif
|
||||
gtar=application/x-gtar
|
||||
gz=application/x-gzip
|
||||
|
||||
hdf=application/x-hdf
|
||||
htc=text/x-component
|
||||
htm=text/html
|
||||
html=text/html
|
||||
hqx=application/mac-binhex40
|
||||
|
||||
ico=image/x-icon
|
||||
ief=image/ief
|
||||
|
||||
jad=text/vnd.sun.j2me.app-descriptor
|
||||
jar=application/java-archive
|
||||
java=text/plain
|
||||
jnlp=application/x-java-jnlp-file
|
||||
jpe=image/jpeg
|
||||
jpeg=image/jpeg
|
||||
jpg=image/jpeg
|
||||
js=text/javascript
|
||||
jsf=text/plain
|
||||
jspf=text/plain
|
||||
|
||||
kar=audio/midi
|
||||
|
||||
latex=application/x-latex
|
||||
lha=application/octet-stream
|
||||
lzh=application/octet-stream
|
||||
|
||||
m3u=audio/x-mpegurl
|
||||
mac=image/x-macpaint
|
||||
man=application/x-troff-man
|
||||
mathml=application/mathml+xml
|
||||
me=application/x-troff-me
|
||||
mid=audio/midi
|
||||
midi=audio/midi
|
||||
mif=application/vnd.mif
|
||||
mov=video/quicktime
|
||||
movie=video/x-sgi-movie
|
||||
mp1=audio/x-mpeg
|
||||
mp2=audio/mpeg
|
||||
mp3=audio/mpeg
|
||||
mpa=audio/x-mpeg
|
||||
mpe=video/mpeg
|
||||
mpeg=video/mpeg
|
||||
mpega=audio/x-mpeg
|
||||
mpga=audio/mpeg
|
||||
mpg=video/mpeg
|
||||
mpv2=video/mpeg2
|
||||
ms=application/x-troff-ms
|
||||
|
||||
nc=application/x-netcdf
|
||||
|
||||
oda=application/oda
|
||||
ogg=application/ogg
|
||||
|
||||
pbm=image/x-portable-bitmap
|
||||
pct=image/pict
|
||||
pdf=application/pdf
|
||||
pgm=image/x-portable-graymap
|
||||
pic=image/pict
|
||||
pict=image/pict
|
||||
pls=audio/x-scpls
|
||||
png=image/png
|
||||
pnm=image/x-portable-anymap
|
||||
pnt=image/x-macpaint
|
||||
ppm=image/x-portable-pixmap
|
||||
pps=application/vnd.ms-powerpoint
|
||||
ppt=application/vnd.ms-powerpoint
|
||||
ps=application/postscript
|
||||
psd=image/x-photoshop
|
||||
|
||||
qt=video/quicktime
|
||||
qti=image/x-quicktime
|
||||
qtif=image/x-quicktime
|
||||
|
||||
ra=audio/x-realaudio
|
||||
ram=audio/x-pn-realaudio
|
||||
ras=image/x-cmu-raster
|
||||
rdf=application/rdf+xml
|
||||
rgb=image/x-rgb
|
||||
rpm=audio/x-pn-realaudio-plugin
|
||||
rm=application/vnd.rn-realmedia
|
||||
roff=application/x-troff
|
||||
rtf=text/rtf
|
||||
rtx=text/richtext
|
||||
|
||||
sh=application/x-sh
|
||||
shar=application/x-shar
|
||||
shtml=text/x-server-parsed-html
|
||||
sgml=text/sgml
|
||||
sgm=text/sgml
|
||||
smf=audio/x-midi
|
||||
sit=application/x-stuffit
|
||||
snd=audio/basic
|
||||
src=application/x-wais-source
|
||||
sv4cpio=application/x-sv4cpio
|
||||
sv4crc=application/x-sv4crc
|
||||
svg=image/svg+xml
|
||||
svgz=image/svg
|
||||
swf=application/x-shockwave-flash
|
||||
|
||||
t=application/x-troff
|
||||
tar=application/x-tar
|
||||
tcl=application/x-tcl
|
||||
tex=application/x-tex
|
||||
texi=application/x-texinfo
|
||||
texinfo=application/x-texinfo
|
||||
tif=image/tiff
|
||||
tiff=image/tiff
|
||||
tr=application/x-troff
|
||||
tsv=text/tab-separated-values
|
||||
txt=text/plain
|
||||
|
||||
ulw=audio/basic
|
||||
ustar=application/x-ustar
|
||||
|
||||
vcd=application/x-cdlink
|
||||
vrml=model/vrml
|
||||
vsd=application/x-visio
|
||||
vxml=application/voicexml+xml
|
||||
|
||||
wav=audio/x-wav
|
||||
wbmp=image/vnd.wap.wbmp
|
||||
wml=text/vnd.wap.wml
|
||||
wmlc=application/vnd.wap.wmlc
|
||||
wmls=text/vnd.wap.wmlscript
|
||||
wmlscriptc=application/vnd.wap.wmlscriptc
|
||||
wrl=model/vrml
|
||||
|
||||
xbm=image/x-xbitmap
|
||||
xht=application/xhtml+xml
|
||||
xhtml=application/xhtml+xml
|
||||
xls=application/vnd.ms-excel
|
||||
xml=application/xml
|
||||
xpm=image/x-xpixmap
|
||||
xsl=application/xml
|
||||
xslt=application/xslt+xml
|
||||
xul=application/vnd.mozilla.xul+xml
|
||||
xwd=image/x-xwindowdump
|
||||
|
||||
Z=application/x-compress
|
||||
z=application/x-compress
|
||||
zip=application/zip
|
||||
@@ -56,11 +56,9 @@ public abstract class DLoadBaseContext {
|
||||
|
||||
int queryBatchSize = queryProps.getQueryFetchBatch();
|
||||
if (queryBatchSize == -1) {
|
||||
// not eager query fetch, just lazy loading
|
||||
return batchSize;
|
||||
|
||||
} else if (queryBatchSize == 0) {
|
||||
// default query fetch batch size is 100
|
||||
return 100;
|
||||
|
||||
} else {
|
||||
|
||||
@@ -25,9 +25,7 @@ public class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContex
|
||||
private LoadBuffer currentBuffer;
|
||||
|
||||
public DLoadBeanContext(DLoadContext parent, BeanDescriptor<?> desc, String path, int defaultBatchSize, OrmQueryProperties queryProps) {
|
||||
|
||||
super(parent, desc, path, defaultBatchSize, queryProps);
|
||||
|
||||
// bufferList only required when using query joins (queryFetch)
|
||||
this.bufferList = (!queryFetch) ? null : new ArrayList<DLoadBeanContext.LoadBuffer>();
|
||||
this.currentBuffer = createBuffer(firstBatchSize);
|
||||
|
||||
@@ -284,20 +284,23 @@ public class DLoadContext implements LoadContext {
|
||||
|
||||
private void registerSecondaryNode(boolean many, OrmQueryProperties props) {
|
||||
|
||||
String path = props.getPath();
|
||||
int lazyJoinBatch = props.getLazyFetchBatch();
|
||||
int batchSize = lazyJoinBatch > 0 ? lazyJoinBatch : defaultBatchSize;
|
||||
|
||||
if (many) {
|
||||
DLoadManyContext manyContext = createManyContext(path, batchSize, props);
|
||||
manyMap.put(path, manyContext);
|
||||
int batchSize;
|
||||
if (props.isQueryFetch()) {
|
||||
batchSize = 100;
|
||||
} else {
|
||||
DLoadBeanContext beanContext = createBeanContext(path, batchSize, props);
|
||||
beanMap.put(path, beanContext);
|
||||
int lazyJoinBatch = props.getLazyFetchBatch();
|
||||
batchSize = lazyJoinBatch > 0 ? lazyJoinBatch : defaultBatchSize;
|
||||
}
|
||||
|
||||
String path = props.getPath();
|
||||
if (many) {
|
||||
manyMap.put(path, createManyContext(path, batchSize, props));
|
||||
} else {
|
||||
beanMap.put(path, createBeanContext(path, batchSize, props));
|
||||
}
|
||||
}
|
||||
|
||||
private DLoadManyContext getManyContext(String path) {
|
||||
protected DLoadManyContext getManyContext(String path) {
|
||||
if (path == null) {
|
||||
throw new RuntimeException("path is null?");
|
||||
}
|
||||
|
||||
@@ -146,7 +146,7 @@ public final class BatchControl {
|
||||
|
||||
/**
|
||||
* Entity Bean insert, update or delete. This will either execute the request
|
||||
* immediately or queue it for batch processing later. The queue is flushed
|
||||
* immediately or queue it for batch processing later. The queue is flushedIntercept
|
||||
* according to the depth (object graph depth).
|
||||
*/
|
||||
public int executeOrQueue(PersistRequestBean<?> request, boolean batch) {
|
||||
|
||||
@@ -10,6 +10,6 @@ public class DmlUtil {
|
||||
* Return true if the value is null or a Numeric 0 (for primitive int's and long's) or Option empty.
|
||||
*/
|
||||
public static boolean isNullOrZero(Object value) {
|
||||
return value == null || value instanceof Number && ((Number) value).longValue() == 0l;
|
||||
return value == null || value instanceof Number && ((Number) value).longValue() == 0L;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import com.avaje.ebeaninternal.api.SpiTransaction;
|
||||
import com.avaje.ebeaninternal.api.SpiUpdate;
|
||||
import com.avaje.ebeaninternal.server.core.PersistRequestOrmUpdate;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.type.DataBind;
|
||||
import com.avaje.ebeaninternal.server.util.BindParamsParser;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -5,7 +5,6 @@ import com.avaje.ebeaninternal.api.SpiSqlUpdate;
|
||||
import com.avaje.ebeaninternal.api.SpiTransaction;
|
||||
import com.avaje.ebeaninternal.server.core.PersistRequestUpdateSql;
|
||||
import com.avaje.ebeaninternal.server.core.PersistRequestUpdateSql.SqlType;
|
||||
import com.avaje.ebeaninternal.server.type.DataBind;
|
||||
import com.avaje.ebeaninternal.server.util.BindParamsParser;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
package com.avaje.ebeaninternal.server.persist.dmlbind;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.api.DerivedRelationshipData;
|
||||
import com.avaje.ebeaninternal.server.core.PersistRequestBean;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Request object passed to bindables.
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.avaje.ebeaninternal.server.query;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.QueryIterator;
|
||||
import com.avaje.ebean.QueryIterator;
|
||||
import com.avaje.ebean.Version;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
|
||||
@@ -123,7 +123,7 @@ public class CQueryBuilder {
|
||||
|
||||
if (!sqlTree.isIncludeJoins()) {
|
||||
// simple - delete from table ...
|
||||
return aliasStrip(buildSql("delete", request, predicates, sqlTree).getSql());
|
||||
return aliasStrip(buildSql("delete", request, predicates, sqlTree).getSql());
|
||||
}
|
||||
// wrap as - delete from table where id in (select id ...)
|
||||
String sql = buildSql(null, request, predicates, sqlTree).getSql();
|
||||
@@ -135,11 +135,11 @@ public class CQueryBuilder {
|
||||
|
||||
private <T> String buildUpdateSql(OrmQueryRequest<T> request, String rootTableAlias, CQueryPredicates predicates, SqlTree sqlTree) {
|
||||
|
||||
String updateClause = "update "+request.getBeanDescriptor().getBaseTable()+" set "+predicates.getDbUpdateClause();
|
||||
String updateClause = "update " + request.getBeanDescriptor().getBaseTable() + " set " + predicates.getDbUpdateClause();
|
||||
|
||||
if (!sqlTree.isIncludeJoins()) {
|
||||
// simple - update table set ... where ...
|
||||
return aliasStrip(buildSqlUpdate(updateClause, request, predicates, sqlTree).getSql());
|
||||
return aliasStrip(buildSqlUpdate(updateClause, request, predicates, sqlTree).getSql());
|
||||
}
|
||||
// wrap as - update table set ... where id in (select id ...)
|
||||
String sql = buildSqlUpdate(null, request, predicates, sqlTree).getSql();
|
||||
@@ -161,26 +161,20 @@ public class CQueryBuilder {
|
||||
* Replace the root table alias.
|
||||
*/
|
||||
private String aliasReplace(String sql, String replaceWith) {
|
||||
sql = StringHelper.replaceString(sql, "${RTA}.", replaceWith+".");
|
||||
sql = StringHelper.replaceString(sql, "${RTA}.", replaceWith + ".");
|
||||
return StringHelper.replaceString(sql, "${RTA}", replaceWith);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the row count query.
|
||||
*/
|
||||
public <T> CQueryFetchIds buildFetchIdsQuery(OrmQueryRequest<T> request) {
|
||||
public CQueryFetchSingleAttribute buildFetchAttributeQuery(OrmQueryRequest<?> request) {
|
||||
|
||||
SpiQuery<T> query = request.getQuery();
|
||||
|
||||
query.setSelectId();
|
||||
SpiQuery<?> query = request.getQuery();
|
||||
query.setSingleAttribute();
|
||||
|
||||
CQueryPredicates predicates = new CQueryPredicates(binder, request);
|
||||
CQueryPlan queryPlan = request.getQueryPlan();
|
||||
if (queryPlan != null) {
|
||||
// skip building the SqlTree and Sql string
|
||||
predicates.prepare(false);
|
||||
String sql = queryPlan.getSql();
|
||||
return new CQueryFetchIds(request, predicates, sql);
|
||||
return new CQueryFetchSingleAttribute(request, predicates, queryPlan);
|
||||
}
|
||||
|
||||
// use RawSql or generated Sql
|
||||
@@ -188,13 +182,19 @@ public class CQueryBuilder {
|
||||
|
||||
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());
|
||||
|
||||
queryPlan = new CQueryPlan(request, s.getSql(), sqlTree, false, s.isIncludesRowNumberColumn(), predicates.getLogWhereSql());
|
||||
request.putQueryPlan(queryPlan);
|
||||
return new CQueryFetchIds(request, predicates, sql);
|
||||
return new CQueryFetchSingleAttribute(request, predicates, queryPlan);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the find ids query.
|
||||
*/
|
||||
public <T> CQueryFetchSingleAttribute buildFetchIdsQuery(OrmQueryRequest<T> request) {
|
||||
|
||||
request.getQuery().setSelectId();
|
||||
return buildFetchAttributeQuery(request);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -225,20 +225,10 @@ public class CQueryBuilder {
|
||||
|
||||
ManyWhereJoins manyWhereJoins = query.getManyWhereJoins();
|
||||
|
||||
boolean hasMany = manyWhereJoins.isHasMany();
|
||||
if (manyWhereJoins.isSelectId()) {
|
||||
// just select the id property
|
||||
query.setSelectId();
|
||||
} else {
|
||||
// select the id and the required formula properties
|
||||
if (manyWhereJoins.isFormulaWithJoin()) {
|
||||
query.select(manyWhereJoins.getFormulaProperties());
|
||||
}
|
||||
|
||||
String sqlSelect = "select count(*)";
|
||||
if (hasMany) {
|
||||
// need to count distinct id's ...
|
||||
query.setSqlDistinct(true);
|
||||
sqlSelect = null;
|
||||
} else {
|
||||
query.setSelectId();
|
||||
}
|
||||
|
||||
CQueryPredicates predicates = new CQueryPredicates(binder, request);
|
||||
@@ -257,6 +247,14 @@ public class CQueryBuilder {
|
||||
sqlTree.addSoftDeletePredicate(query);
|
||||
}
|
||||
|
||||
boolean hasMany = sqlTree.hasMany();
|
||||
String sqlSelect = "select count(*)";
|
||||
if (hasMany) {
|
||||
// need to count distinct id's ...
|
||||
query.setSqlDistinct(true);
|
||||
sqlSelect = null;
|
||||
}
|
||||
|
||||
SqlLimitResponse s = buildSql(sqlSelect, request, predicates, sqlTree);
|
||||
String sql = s.getSql();
|
||||
if (hasMany || query.isRawSql()) {
|
||||
@@ -452,8 +450,8 @@ public class CQueryBuilder {
|
||||
}
|
||||
|
||||
sb.append(select.getSelectSql());
|
||||
if (query.isDistinctQuery() && dbOrderBy != null) {
|
||||
// add the orderby columns to the select clause (due to distinct)
|
||||
if (query.isDistinctQuery() && dbOrderBy != null && !query.isSingleAttribute()) {
|
||||
// add the orderBy columns to the select clause (due to distinct)
|
||||
sb.append(", ").append(convertDbOrderByForSelect(dbOrderBy));
|
||||
}
|
||||
}
|
||||
@@ -488,7 +486,7 @@ public class CQueryBuilder {
|
||||
}
|
||||
if (stripAlias) {
|
||||
// strip the table alias for use in update statement
|
||||
idSql = StringHelper.replaceString(idSql, "t0.","");
|
||||
idSql = StringHelper.replaceString(idSql, "t0.", "");
|
||||
}
|
||||
sb.append(idSql).append(" ");
|
||||
hasWhere = true;
|
||||
|
||||
@@ -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.ebean.QueryIterator;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.lib.util.Str;
|
||||
import com.avaje.ebeaninternal.server.persist.Binder;
|
||||
@@ -89,29 +88,24 @@ public class CQueryEngine {
|
||||
}
|
||||
|
||||
/**
|
||||
* Build and execute the find Id's query.
|
||||
* Build and execute the findSingleAttributeList query.
|
||||
*/
|
||||
public <T> BeanIdList findIds(OrmQueryRequest<T> request) {
|
||||
public <A> List<A> findSingleAttributeList(OrmQueryRequest<?> request) {
|
||||
|
||||
CQueryFetchIds rcQuery = queryBuilder.buildFetchIdsQuery(request);
|
||||
CQueryFetchSingleAttribute rcQuery = queryBuilder.buildFetchAttributeQuery(request);
|
||||
return findAttributeList(request, rcQuery);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <A> List<A> findAttributeList(OrmQueryRequest<?> request, CQueryFetchSingleAttribute rcQuery) {
|
||||
try {
|
||||
|
||||
BeanIdList list = rcQuery.findIds();
|
||||
|
||||
List<A> list = (List<A>)rcQuery.findList();
|
||||
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) {
|
||||
@@ -119,6 +113,15 @@ public class CQueryEngine {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build and execute the find Id's query.
|
||||
*/
|
||||
public <A> List<A> findIds(OrmQueryRequest<?> request) {
|
||||
|
||||
CQueryFetchSingleAttribute rcQuery = queryBuilder.buildFetchIdsQuery(request);
|
||||
return findAttributeList(request, rcQuery);
|
||||
}
|
||||
|
||||
private <T> void logGeneratedSql(OrmQueryRequest<T> request, String sql, String bindLog) {
|
||||
String logSql = sql;
|
||||
if (TransactionManager.SQL_LOGGER.isTraceEnabled()) {
|
||||
@@ -300,9 +303,10 @@ public class CQueryEngine {
|
||||
|
||||
|
||||
SpiQuery<T> query = request.getQuery();
|
||||
if (query.getMaxRows() > 1 || query.getFirstRow() > 0) {
|
||||
if (!query.isDistinct() && (query.getMaxRows() > 1 || query.getFirstRow() > 0)) {
|
||||
// deemed to be a be a paging query - check that the order by contains
|
||||
// the id property to ensure unique row ordering for predicable paging
|
||||
// but only in case, this is not a distinct query
|
||||
request.getBeanDescriptor().appendOrderById(query);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,278 +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.BeanIdList;
|
||||
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.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Executes the select row count query.
|
||||
*/
|
||||
public class CQueryFetchIds {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(CQueryFetchIds.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 int maxRows;
|
||||
|
||||
/**
|
||||
* Create the Sql select based on the request.
|
||||
*/
|
||||
public CQueryFetchIds(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 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();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bind log.
|
||||
*/
|
||||
public String getBindLog() {
|
||||
return bindLog;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the generated sql.
|
||||
*/
|
||||
public String getGeneratedSql() {
|
||||
return sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
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);
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
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.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.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Base compiled query request for single attribute queries.
|
||||
*/
|
||||
class CQueryFetchSingleAttribute {
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* Create the Sql select based on the request.
|
||||
*/
|
||||
public CQueryFetchSingleAttribute(OrmQueryRequest<?> request, CQueryPredicates predicates, CQueryPlan plan) {
|
||||
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.
|
||||
*/
|
||||
protected String getSummary() {
|
||||
StringBuilder sb = new StringBuilder(80);
|
||||
sb.append("FindAttr 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.
|
||||
*/
|
||||
protected List<Object> findList() throws SQLException {
|
||||
|
||||
long startNano = System.nanoTime();
|
||||
try {
|
||||
|
||||
prepareExecute();
|
||||
|
||||
List<Object> result = new ArrayList<Object>();
|
||||
|
||||
while (dataReader.next()) {
|
||||
result.add(scalarType.read(dataReader));
|
||||
dataReader.resetColumnPosition();
|
||||
rowCount++;
|
||||
}
|
||||
|
||||
long exeNano = System.nanoTime() - startNano;
|
||||
executionTimeMicros = (int) exeNano / 1000;
|
||||
|
||||
return result;
|
||||
|
||||
} finally {
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import java.sql.SQLException;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.QueryIterator;
|
||||
import com.avaje.ebean.QueryIterator;
|
||||
import com.avaje.ebeaninternal.server.core.OrmQueryRequest;
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,7 +5,7 @@ import java.util.ArrayList;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.QueryIterator;
|
||||
import com.avaje.ebean.QueryIterator;
|
||||
import com.avaje.ebeaninternal.server.core.OrmQueryRequest;
|
||||
|
||||
/**
|
||||
|
||||
@@ -266,4 +266,7 @@ public class CQueryPlan {
|
||||
return stats.getLastQueryTime();
|
||||
}
|
||||
|
||||
public BeanProperty getSingleProperty() {
|
||||
return sqlTree.getRootNode().getSingleProperty();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
package com.avaje.ebeaninternal.server.query;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.QueryIterator;
|
||||
import com.avaje.ebean.QueryIterator;
|
||||
import com.avaje.ebean.Version;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.event.BeanFindController;
|
||||
import com.avaje.ebeaninternal.api.BeanIdList;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
import com.avaje.ebeaninternal.api.SpiTransaction;
|
||||
import com.avaje.ebeaninternal.server.core.OrmQueryEngine;
|
||||
@@ -65,12 +64,18 @@ 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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <A> List<A> findSingleAttributeList(OrmQueryRequest<?> request) {
|
||||
flushJdbcBatchOnQuery(request);
|
||||
return queryEngine.findSingleAttributeList(request);
|
||||
}
|
||||
|
||||
public <T> QueryIterator<T> findIterate(OrmQueryRequest<T> request) {
|
||||
|
||||
// LIMITATION: You can not use QueryIterator to load bean cache
|
||||
|
||||
@@ -43,19 +43,27 @@ public class LimitOffsetPagedList<T> implements PagedList<T> {
|
||||
this.firstRow = query.getFirstRow();
|
||||
}
|
||||
|
||||
public void loadRowCount() {
|
||||
getFutureRowCount();
|
||||
public void loadCount() {
|
||||
getFutureCount();
|
||||
}
|
||||
|
||||
public Future<Integer> getFutureRowCount() {
|
||||
public void loadRowCount() {
|
||||
loadCount();
|
||||
}
|
||||
|
||||
public Future<Integer> getFutureCount() {
|
||||
synchronized (monitor) {
|
||||
if (futureRowCount == null) {
|
||||
futureRowCount = server.findFutureRowCount(query, null);
|
||||
futureRowCount = server.findFutureCount(query, null);
|
||||
}
|
||||
return futureRowCount;
|
||||
}
|
||||
}
|
||||
|
||||
public Future<Integer> getFutureRowCount() {
|
||||
return getFutureCount();
|
||||
}
|
||||
|
||||
public List<T> getList() {
|
||||
synchronized (monitor) {
|
||||
if (list == null) {
|
||||
@@ -67,7 +75,7 @@ public class LimitOffsetPagedList<T> implements PagedList<T> {
|
||||
|
||||
public int getTotalPageCount() {
|
||||
|
||||
int rowCount = getTotalRowCount();
|
||||
int rowCount = getTotalCount();
|
||||
if (rowCount == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
@@ -75,7 +83,7 @@ public class LimitOffsetPagedList<T> implements PagedList<T> {
|
||||
}
|
||||
}
|
||||
|
||||
public int getTotalRowCount() {
|
||||
public int getTotalCount() {
|
||||
synchronized (monitor) {
|
||||
if (futureRowCount != null) {
|
||||
try {
|
||||
@@ -89,13 +97,17 @@ public class LimitOffsetPagedList<T> implements PagedList<T> {
|
||||
if (foregroundTotalRowCount > -1) return foregroundTotalRowCount;
|
||||
|
||||
// just using foreground thread
|
||||
foregroundTotalRowCount = server.findRowCount(query, null);
|
||||
foregroundTotalRowCount = server.findCount(query, null);
|
||||
return foregroundTotalRowCount;
|
||||
}
|
||||
}
|
||||
|
||||
public int getTotalRowCount() {
|
||||
return getTotalCount();
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return (firstRow + maxRows) < getTotalRowCount();
|
||||
return (firstRow + maxRows) < getTotalCount();
|
||||
}
|
||||
|
||||
public boolean hasPrev() {
|
||||
@@ -110,7 +122,7 @@ public class LimitOffsetPagedList<T> implements PagedList<T> {
|
||||
|
||||
int first = firstRow + 1;
|
||||
int last = firstRow + getList().size();
|
||||
int total = getTotalRowCount();
|
||||
int total = getTotalCount();
|
||||
|
||||
return first + to + last + of + total;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -60,21 +60,6 @@ public class SqlTree {
|
||||
this.includeJoins = includeJoins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct for RawSql.
|
||||
*/
|
||||
public SqlTree(String summary, SqlTreeNode rootNode) {
|
||||
this.summary = summary;
|
||||
this.rootNode = rootNode;
|
||||
this.selectSql = null;
|
||||
this.fromSql = null;
|
||||
this.inheritanceWhereSql = null;
|
||||
this.encryptedProps = null;
|
||||
this.manyProperty = null;
|
||||
this.includes = null;
|
||||
this.includeJoins = false; //not valid for rawSql
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the query includes joins (not valid for rawSql).
|
||||
*/
|
||||
@@ -153,4 +138,10 @@ public class SqlTree {
|
||||
return encryptedProps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the query has a many join.
|
||||
*/
|
||||
public boolean hasMany() {
|
||||
return manyProperty != null || rootNode.hasMany();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ public class SqlTreeBuilder {
|
||||
this.query = request.getQuery();
|
||||
this.disableLazyLoad = query.isDisableLazyLoading();
|
||||
this.subQuery = Type.SUBQUERY.equals(query.getType()) || Type.ID_LIST.equals(query.getType());
|
||||
this.includeJoin = query.getIncludeTableJoin();
|
||||
this.includeJoin = query.getM2mIncludeJoin();
|
||||
this.manyWhereJoins = query.getManyWhereJoins();
|
||||
this.queryDetail = query.getDetail();
|
||||
|
||||
@@ -260,7 +260,7 @@ public class SqlTreeBuilder {
|
||||
|
||||
// Optional many property for lazy loading query
|
||||
BeanPropertyAssocMany<?> lazyLoadMany = (query == null) ? null : query.getLazyLoadMany();
|
||||
boolean withId = !rawNoId && !subQuery && (query == null || !query.isDistinct());
|
||||
boolean withId = !rawNoId && !subQuery && (query == null || query.isWithId());
|
||||
return new SqlTreeNodeRoot(desc, props, myList, withId, includeJoin, lazyLoadMany, SpiQuery.TemporalMode.of(query), disableLazyLoad);
|
||||
|
||||
} else if (prop instanceof BeanPropertyAssocMany<?>) {
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.avaje.ebeaninternal.server.query;
|
||||
import com.avaje.ebean.Version;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.DbReadContext;
|
||||
import com.avaje.ebeaninternal.server.deploy.DbSqlContext;
|
||||
|
||||
@@ -57,4 +58,15 @@ public interface SqlTreeNode {
|
||||
* Load a version of a @History bean with effective dates.
|
||||
*/
|
||||
<T> Version<T> loadVersion(DbReadContext ctx) throws SQLException;
|
||||
|
||||
/**
|
||||
* Return true if the query has a many join.
|
||||
*/
|
||||
boolean hasMany();
|
||||
|
||||
/**
|
||||
* Return the property for singleAttribute query.
|
||||
*/
|
||||
BeanProperty getSingleProperty();
|
||||
|
||||
}
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
package com.avaje.ebeaninternal.server.query;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.avaje.ebean.Version;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
@@ -24,6 +18,12 @@ import com.avaje.ebeaninternal.server.deploy.TableJoin;
|
||||
import com.avaje.ebeaninternal.server.deploy.id.IdBinder;
|
||||
import com.avaje.ebeaninternal.server.lib.util.StringHelper;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Normal bean included in the query.
|
||||
*/
|
||||
@@ -83,13 +83,6 @@ public class SqlTreeNodeBean implements SqlTreeNode {
|
||||
*/
|
||||
private boolean intersectionAsOfTableAlias;
|
||||
|
||||
/**
|
||||
* Construct for Raw SQL.
|
||||
*/
|
||||
public SqlTreeNodeBean(BeanDescriptor<?> desc, SqlTreeProperties props, boolean withId, boolean disableLazyLoad) {
|
||||
this(null, null, desc, props, null, withId, null, null, disableLazyLoad);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct for leaf node.
|
||||
*/
|
||||
@@ -137,6 +130,11 @@ public class SqlTreeNodeBean implements SqlTreeNode {
|
||||
pathMap = createPathMap(prefix, desc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeanProperty getSingleProperty() {
|
||||
return properties[0];
|
||||
}
|
||||
|
||||
private Map<String, String> createPathMap(String prefix, BeanDescriptor<?> desc) {
|
||||
|
||||
BeanPropertyAssocMany<?>[] manys = desc.propertiesMany();
|
||||
@@ -570,4 +568,14 @@ public class SqlTreeNodeBean implements SqlTreeNode {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMany() {
|
||||
|
||||
for (SqlTreeNode child : children) {
|
||||
if (child.hasMany()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.avaje.ebeaninternal.server.query;
|
||||
import com.avaje.ebean.Version;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssoc;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
import com.avaje.ebeaninternal.server.deploy.DbReadContext;
|
||||
@@ -55,6 +56,11 @@ public class SqlTreeNodeExtraJoin implements SqlTreeNode {
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeanProperty getSingleProperty() {
|
||||
throw new IllegalStateException("No expected");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the extra join is a many join.
|
||||
* <p>
|
||||
@@ -146,4 +152,9 @@ public class SqlTreeNodeExtraJoin implements SqlTreeNode {
|
||||
public <T> Version<T> loadVersion(DbReadContext ctx) throws SQLException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMany() {
|
||||
return manyJoin;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package com.avaje.ebeaninternal.server.query;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
import com.avaje.ebeaninternal.server.deploy.DbReadContext;
|
||||
import com.avaje.ebeaninternal.server.deploy.DbSqlContext;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
public final class SqlTreeNodeManyRoot extends SqlTreeNodeBean {
|
||||
|
||||
private final BeanPropertyAssocMany<?> manyProp;
|
||||
@@ -38,4 +38,8 @@ public final class SqlTreeNodeManyRoot extends SqlTreeNodeBean {
|
||||
super.appendFrom(ctx, joinType.autoToOuter());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMany() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.avaje.ebeaninternal.server.query;
|
||||
import com.avaje.ebean.Version;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssoc;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne;
|
||||
@@ -39,6 +40,11 @@ public class SqlTreeNodeManyWhereJoin implements SqlTreeNode {
|
||||
this.parentPrefix = split[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeanProperty getSingleProperty() {
|
||||
throw new IllegalStateException("No expected");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAsOfTableAlias(SpiQuery<?> query) {
|
||||
// do nothing here ...
|
||||
@@ -109,4 +115,9 @@ public class SqlTreeNodeManyWhereJoin implements SqlTreeNode {
|
||||
// nothing to do here
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMany() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,14 +25,6 @@ public final class SqlTreeNodeRoot extends SqlTreeNodeBean {
|
||||
this.includeJoin = includeJoin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct for raw sql named queries.
|
||||
*/
|
||||
public SqlTreeNodeRoot(BeanDescriptor<?> desc, SqlTreeProperties props, boolean withId) {
|
||||
super(desc, props, withId, false);
|
||||
this.includeJoin = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set AsOf support (at root level).
|
||||
*/
|
||||
|
||||
@@ -43,6 +43,10 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
|
||||
public static final String DEFAULT_QUERY_NAME = "default";
|
||||
|
||||
private static final FetchConfig FETCH_QUERY = new FetchConfig().query();
|
||||
|
||||
private static final FetchConfig FETCH_LAZY = new FetchConfig().lazy();
|
||||
|
||||
private final Class<T> beanType;
|
||||
|
||||
private final BeanDescriptor<T> beanDescriptor;
|
||||
@@ -55,7 +59,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
* For lazy loading of ManyToMany we need to add a join to the intersection table. This is that
|
||||
* join to the intersection table.
|
||||
*/
|
||||
private TableJoin includeTableJoin;
|
||||
private TableJoin m2mIncludeJoin;
|
||||
|
||||
private ProfilingListener profilingListener;
|
||||
|
||||
@@ -119,8 +123,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
*/
|
||||
private ReadEvent futureFetchAudit;
|
||||
|
||||
private List<Object> partialIds;
|
||||
|
||||
private int timeout;
|
||||
|
||||
/**
|
||||
@@ -188,6 +190,8 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
*/
|
||||
private boolean forUpdate;
|
||||
|
||||
private boolean singleAttribute;
|
||||
|
||||
/**
|
||||
* Set to true if this query has been tuned by autoTune.
|
||||
*/
|
||||
@@ -530,6 +534,26 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
select(beanDescriptor.getIdBinder().getIdProperty());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSingleAttribute() {
|
||||
this.singleAttribute = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is a single attribute query.
|
||||
*/
|
||||
public boolean isSingleAttribute() {
|
||||
return singleAttribute;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the Id should be included in the query.
|
||||
*/
|
||||
@Override
|
||||
public boolean isWithId() {
|
||||
return !distinct && !singleAttribute;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NaturalKeyBindParam getNaturalKeyBindParam() {
|
||||
NaturalKeyBindParam namedBind = null;
|
||||
@@ -571,7 +595,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
public DefaultOrmQuery<T> copy(EbeanServer server) {
|
||||
|
||||
DefaultOrmQuery<T> copy = new DefaultOrmQuery<T>(beanDescriptor, server, expressionFactory);
|
||||
copy.includeTableJoin = includeTableJoin;
|
||||
copy.m2mIncludeJoin = m2mIncludeJoin;
|
||||
copy.profilingListener = profilingListener;
|
||||
|
||||
// copy.query = query;
|
||||
@@ -846,7 +870,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
*/
|
||||
CQueryPlanKey createQueryPlanKey() {
|
||||
|
||||
queryPlanKey = new OrmQueryPlanKey(includeTableJoin, type, detail, maxRows, firstRow,
|
||||
queryPlanKey = new OrmQueryPlanKey(m2mIncludeJoin, type, detail, maxRows, firstRow,
|
||||
disableLazyLoading, orderBy,
|
||||
distinct, sqlDistinct, mapKey, id, bindParams, whereExpressions, havingExpressions,
|
||||
temporalMode, forUpdate, rootTableAlias, rawSql, updateProperties);
|
||||
@@ -1013,6 +1037,16 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
return fetch(property, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> fetchQuery(String property) {
|
||||
return fetch(property, null, FETCH_QUERY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> fetchLazy(String property) {
|
||||
return fetch(property, null, FETCH_LAZY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultOrmQuery<T> fetch(String property, FetchConfig joinConfig) {
|
||||
return fetch(property, null, joinConfig);
|
||||
@@ -1023,6 +1057,16 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
return fetch(property, columns, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> fetchQuery(String property, String columns) {
|
||||
return fetch(property, columns, FETCH_QUERY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> fetchLazy(String property, String columns) {
|
||||
return fetch(property, columns, FETCH_LAZY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultOrmQuery<T> fetch(String property, String columns, FetchConfig config) {
|
||||
detail.fetch(property, columns, config);
|
||||
@@ -1048,11 +1092,16 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int findRowCount() {
|
||||
public int findCount() {
|
||||
// a copy of this query is made in the server
|
||||
// as the query needs to modified (so we modify
|
||||
// the copy rather than this query instance)
|
||||
return server.findRowCount(this, null);
|
||||
return server.findCount(this, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int findRowCount() {
|
||||
return findCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1065,6 +1114,11 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
server.findEach(this, consumer, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryIterator<T> findIterate() {
|
||||
return server.findIterate(this, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Version<T>> findVersions() {
|
||||
this.temporalMode = TemporalMode.VERSIONS;
|
||||
@@ -1093,15 +1147,14 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<?, T> findMap() {
|
||||
public <K> Map<K, T> findMap() {
|
||||
return server.findMap(this, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <K> Map<K, T> findMap(String keyProperty, Class<K> keyType) {
|
||||
setMapKey(keyProperty);
|
||||
return (Map<K, T>) findMap();
|
||||
public <A> List<A> findSingleAttributeList() {
|
||||
return (List<A>)server.findSingleAttributeList(this, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1119,9 +1172,14 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
return server.findFutureList(this, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FutureRowCount<T> findFutureCount() {
|
||||
return server.findFutureCount(this, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FutureRowCount<T> findFutureRowCount() {
|
||||
return server.findFutureRowCount(this, null);
|
||||
return findFutureCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1254,14 +1312,13 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
return "Query [" + whereExpressions + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableJoin getIncludeTableJoin() {
|
||||
return includeTableJoin;
|
||||
public TableJoin getM2mIncludeJoin() {
|
||||
return m2mIncludeJoin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIncludeTableJoin(TableJoin includeTableJoin) {
|
||||
this.includeTableJoin = includeTableJoin;
|
||||
public void setM2MIncludeJoin(TableJoin m2mIncludeJoin) {
|
||||
this.m2mIncludeJoin = m2mIncludeJoin;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1449,16 +1506,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;
|
||||
|
||||
@@ -14,9 +14,8 @@ import com.avaje.ebeaninternal.server.deploy.TableJoin;
|
||||
*/
|
||||
public class OrmQueryPlanKey implements CQueryPlanKey {
|
||||
|
||||
private final TableJoin includeTableJoin;
|
||||
private final String m2mIncludeTable;
|
||||
private final String orderByAsSting;
|
||||
private final OrmQueryDetail detail;
|
||||
private final SpiExpression where;
|
||||
private final SpiExpression having;
|
||||
private final RawSql.Key rawSqlKey;
|
||||
@@ -36,11 +35,10 @@ public class OrmQueryPlanKey implements CQueryPlanKey {
|
||||
private final int planHash;
|
||||
private final int bindCount;
|
||||
|
||||
public OrmQueryPlanKey(TableJoin includeTableJoin, SpiQuery.Type type, OrmQueryDetail detail, int maxRows, int firstRow, boolean disableLazyLoading, OrderBy<?> orderBy, boolean distinct, boolean sqlDistinct, String mapKey, Object id, BindParams bindParams, SpiExpression whereExpressions, SpiExpression havingExpressions, SpiQuery.TemporalMode temporalMode, boolean forUpdate, String rootTableAlias, RawSql rawSql, OrmUpdateProperties updateProperties) {
|
||||
public OrmQueryPlanKey(TableJoin m2mIncludeTable, SpiQuery.Type type, OrmQueryDetail detail, int maxRows, int firstRow, boolean disableLazyLoading, OrderBy<?> orderBy, boolean distinct, boolean sqlDistinct, String mapKey, Object id, BindParams bindParams, SpiExpression whereExpressions, SpiExpression havingExpressions, SpiQuery.TemporalMode temporalMode, boolean forUpdate, String rootTableAlias, RawSql rawSql, OrmUpdateProperties updateProperties) {
|
||||
|
||||
this.includeTableJoin = includeTableJoin;
|
||||
this.m2mIncludeTable = m2mIncludeTable == null ? null : m2mIncludeTable.getTable();
|
||||
this.type = type;
|
||||
this.detail = detail;
|
||||
this.maxRows = maxRows;
|
||||
this.firstRow = firstRow;
|
||||
this.disableLazyLoading = disableLazyLoading;
|
||||
@@ -69,7 +67,7 @@ public class OrmQueryPlanKey implements CQueryPlanKey {
|
||||
builder.add(hasIdValue);
|
||||
builder.add(temporalMode);
|
||||
builder.add(rawSqlKey == null ? 0 : rawSqlKey.hashCode());
|
||||
builder.add(includeTableJoin != null ? includeTableJoin.queryHash() : 0);
|
||||
builder.add(this.m2mIncludeTable);
|
||||
builder.add(rootTableAlias);
|
||||
|
||||
if (detail != null) {
|
||||
@@ -120,15 +118,12 @@ public class OrmQueryPlanKey implements CQueryPlanKey {
|
||||
if (hasIdValue != that.hasIdValue) return false;
|
||||
if (type != that.type) return false;
|
||||
if (temporalMode != that.temporalMode) return false;
|
||||
if (includeTableJoin != null ? !includeTableJoin.equals(that.includeTableJoin) : that.includeTableJoin != null) return false;
|
||||
if (m2mIncludeTable != null ? !m2mIncludeTable.equals(that.m2mIncludeTable) : that.m2mIncludeTable != null) return false;
|
||||
if (orderByAsSting != null ? !orderByAsSting.equals(that.orderByAsSting) : that.orderByAsSting != null) return false;
|
||||
if (where != null ? !where.isSameByPlan(that.where) : that.where != null) return false;
|
||||
if (having != null ? !having.isSameByPlan(that.having) : that.having != null) return false;
|
||||
if (updateProperties != null ? !updateProperties.isSameByPlan(that.updateProperties) : that.updateProperties != null) return false;
|
||||
if (rawSqlKey != null ? !rawSqlKey.equals(that.rawSqlKey) : that.rawSqlKey != null) return false;
|
||||
|
||||
// if (detail != null ? !detail.equals(that.detail) : that.detail != null) return false;
|
||||
|
||||
if (mapKey != null ? !mapKey.equals(that.mapKey) : that.mapKey != null) return false;
|
||||
return rootTableAlias != null ? rootTableAlias.equals(that.rootTableAlias) : that.rootTableAlias == null;
|
||||
}
|
||||
|
||||
+3
-4
@@ -3,10 +3,9 @@ package com.avaje.ebeaninternal.server.transaction;
|
||||
import com.avaje.ebean.BackgroundExecutor;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebeaninternal.api.SpiTransaction;
|
||||
import com.avaje.ebeanservice.docstore.api.DocStoreUpdateProcessor;
|
||||
import com.avaje.ebeaninternal.server.cluster.ClusterManager;
|
||||
import com.avaje.ebeaninternal.server.core.bootup.BootupClasses;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptorManager;
|
||||
import com.avaje.ebeanservice.docstore.api.DocStoreUpdateProcessor;
|
||||
|
||||
import java.sql.Connection;
|
||||
|
||||
@@ -18,9 +17,9 @@ import java.sql.Connection;
|
||||
public class AutoCommitTransactionManager extends TransactionManager {
|
||||
|
||||
public AutoCommitTransactionManager(boolean localL2Caching, ServerConfig serverConfig, ClusterManager clusterManager, BackgroundExecutor backgroundExecutor,
|
||||
DocStoreUpdateProcessor indexUpdateProcessor, BeanDescriptorManager descMgr, BootupClasses bootupClasses) {
|
||||
DocStoreUpdateProcessor indexUpdateProcessor, BeanDescriptorManager descMgr) {
|
||||
|
||||
super(localL2Caching, serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, descMgr, bootupClasses);
|
||||
super(localL2Caching, serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, descMgr);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
-1
@@ -1,7 +1,6 @@
|
||||
package com.avaje.ebeaninternal.server.transaction;
|
||||
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebean.bean.PersistenceContextUtil;
|
||||
import com.avaje.ebeaninternal.api.Monitor;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
+2
-5
@@ -4,8 +4,7 @@ import com.avaje.ebeaninternal.api.SpiTransaction;
|
||||
import com.avaje.ebeaninternal.server.transaction.TransactionMap.State;
|
||||
|
||||
/**
|
||||
* Used by EbeanMgr to store its Transactions in a ThreadLocal. This way the
|
||||
* transaction objects don't have to passed around.
|
||||
* Used to store Transactions in a ThreadLocal.
|
||||
*/
|
||||
public final class DefaultTransactionThreadLocal {
|
||||
|
||||
@@ -99,7 +98,7 @@ public final class DefaultTransactionThreadLocal {
|
||||
* block.
|
||||
* <p>
|
||||
* <pre>
|
||||
* Ebean.beingTransaction();
|
||||
* Ebean.beginTransaction();
|
||||
* try {
|
||||
* // ... perform some actions in a single transaction
|
||||
*
|
||||
@@ -110,8 +109,6 @@ public final class DefaultTransactionThreadLocal {
|
||||
* Ebean.endTransaction();
|
||||
* }
|
||||
* </pre>
|
||||
* <p>
|
||||
* </p>
|
||||
*/
|
||||
public static void end(String serverName) {
|
||||
|
||||
|
||||
+5
-10
@@ -4,10 +4,9 @@ import com.avaje.ebean.BackgroundExecutor;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebeaninternal.api.SpiTransaction;
|
||||
import com.avaje.ebeanservice.docstore.api.DocStoreUpdateProcessor;
|
||||
import com.avaje.ebeaninternal.server.cluster.ClusterManager;
|
||||
import com.avaje.ebeaninternal.server.core.bootup.BootupClasses;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptorManager;
|
||||
import com.avaje.ebeanservice.docstore.api.DocStoreUpdateProcessor;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.Connection;
|
||||
@@ -18,9 +17,9 @@ import java.sql.Connection;
|
||||
public class ExplicitTransactionManager extends TransactionManager {
|
||||
|
||||
public ExplicitTransactionManager(boolean localL2Caching, ServerConfig serverConfig, ClusterManager clusterManager, BackgroundExecutor backgroundExecutor,
|
||||
DocStoreUpdateProcessor indexUpdateProcessor, BeanDescriptorManager descMgr, BootupClasses bootupClasses) {
|
||||
DocStoreUpdateProcessor indexUpdateProcessor, BeanDescriptorManager descMgr) {
|
||||
|
||||
super(localL2Caching, serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, descMgr, bootupClasses);
|
||||
super(localL2Caching, serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, descMgr);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -44,11 +43,7 @@ public class ExplicitTransactionManager extends TransactionManager {
|
||||
return DatabasePlatform.OnQueryOnly.valueOf(systemPropertyValue.trim().toUpperCase());
|
||||
}
|
||||
|
||||
if (DatabasePlatform.OnQueryOnly.CLOSE.equals(dbPlatformOnQueryOnly)) {
|
||||
// Not using OnQueryOnly.CLOSE with ExplicitJdbcTransaction
|
||||
return DatabasePlatform.OnQueryOnly.COMMIT;
|
||||
}
|
||||
// default to commit if not defined on the platform
|
||||
return dbPlatformOnQueryOnly == null ? DatabasePlatform.OnQueryOnly.COMMIT : dbPlatformOnQueryOnly;
|
||||
// default to rollback if not defined on the platform
|
||||
return dbPlatformOnQueryOnly == null ? DatabasePlatform.OnQueryOnly.ROLLBACK : dbPlatformOnQueryOnly;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,6 +66,8 @@ public class JdbcTransaction implements SpiTransaction {
|
||||
*/
|
||||
protected boolean active;
|
||||
|
||||
protected boolean rollbackOnly;
|
||||
|
||||
/**
|
||||
* The underlying Connection.
|
||||
*/
|
||||
@@ -851,33 +853,15 @@ public class JdbcTransaction implements SpiTransaction {
|
||||
}
|
||||
}
|
||||
|
||||
protected void notifyQueryOnly() {
|
||||
if (manager != null) {
|
||||
manager.notifyOfQueryOnly(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rollback, Commit or Close for query only transaction.
|
||||
* <p>
|
||||
* For a transaction that was used for queries only we can choose to either
|
||||
* rollback or just close the connection for performance.
|
||||
* </p>
|
||||
* Rollback or Commit for query only transaction.
|
||||
*/
|
||||
protected void connectionEndForQueryOnly() {
|
||||
try {
|
||||
switch (onQueryOnly) {
|
||||
case ROLLBACK:
|
||||
performRollback();
|
||||
break;
|
||||
case COMMIT:
|
||||
performCommit();
|
||||
break;
|
||||
case CLOSE:
|
||||
// valid at READ COMMITTED Isolation
|
||||
break;
|
||||
default:
|
||||
performRollback();
|
||||
if (onQueryOnly == OnQueryOnly.COMMIT) {
|
||||
performCommit();
|
||||
} else {
|
||||
performRollback();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
logger.error("Error when ending a query only transaction via " + onQueryOnly, e);
|
||||
@@ -898,37 +882,73 @@ public class JdbcTransaction implements SpiTransaction {
|
||||
connection.commit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch flush, jdbc commit, trigger registered TransactionCallbacks, notify l2 cache etc.
|
||||
*/
|
||||
private void flushCommitAndNotify() throws SQLException {
|
||||
if (batchControl != null && !batchControl.isEmpty()) {
|
||||
batchControl.flush();
|
||||
}
|
||||
firePreCommit();
|
||||
// only performCommit can throw an exception
|
||||
performCommit();
|
||||
firePostCommit();
|
||||
notifyCommit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a commit, fire callbacks and notify l2 cache etc.
|
||||
* <p>
|
||||
* This leaves the transaction active and expects another commit
|
||||
* to occur later (which closes the underlying connection etc).
|
||||
* </p>
|
||||
*/
|
||||
@Override
|
||||
public void commitAndContinue() throws RollbackException {
|
||||
if (rollbackOnly) {
|
||||
return;
|
||||
}
|
||||
if (!isActive()) {
|
||||
throw new IllegalStateException(illegalStateMessage);
|
||||
}
|
||||
try {
|
||||
flushCommitAndNotify();
|
||||
// the event has been sent to the transaction manager
|
||||
// for postCommit processing (l2 cache updates etc)
|
||||
// start a new transaction event
|
||||
event = new TransactionEvent();
|
||||
|
||||
} catch (Exception e) {
|
||||
doRollback(e);
|
||||
throw new RollbackException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit the transaction.
|
||||
*/
|
||||
@Override
|
||||
public void commit() throws RollbackException {
|
||||
if (rollbackOnly) {
|
||||
rollback();
|
||||
return;
|
||||
}
|
||||
if (!isActive()) {
|
||||
throw new IllegalStateException(illegalStateMessage);
|
||||
}
|
||||
|
||||
firePreCommit();
|
||||
|
||||
try {
|
||||
if (queryOnly) {
|
||||
// can rollback or just close for performance
|
||||
connectionEndForQueryOnly();
|
||||
} else {
|
||||
// commit
|
||||
if (batchControl != null && !batchControl.isEmpty()) {
|
||||
batchControl.flush();
|
||||
}
|
||||
performCommit();
|
||||
flushCommitAndNotify();
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
doRollback(e);
|
||||
throw new RollbackException(e);
|
||||
|
||||
} finally {
|
||||
// these will not throw an exception
|
||||
firePostCommit();
|
||||
deactivate();
|
||||
notifyCommit();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -945,6 +965,32 @@ public class JdbcTransaction implements SpiTransaction {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the transaction is marked as rollback only.
|
||||
*/
|
||||
@Override
|
||||
public boolean isRollbackOnly() {
|
||||
return rollbackOnly;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the transaction as rollback only.
|
||||
*/
|
||||
@Override
|
||||
public void setRollbackOnly() {
|
||||
this.rollbackOnly = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform rollback is the transaction is still active.
|
||||
*/
|
||||
@Override
|
||||
public void rollbackIfActive() {
|
||||
if (isActive()) {
|
||||
rollback(null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rollback the transaction.
|
||||
*/
|
||||
@@ -962,17 +1008,26 @@ public class JdbcTransaction implements SpiTransaction {
|
||||
if (!isActive()) {
|
||||
throw new IllegalStateException(illegalStateMessage);
|
||||
}
|
||||
try {
|
||||
doRollback(cause);
|
||||
} finally {
|
||||
deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the jdbc rollback and fire any registered callbacks.
|
||||
*/
|
||||
private void doRollback(Throwable cause) {
|
||||
firePreRollback();
|
||||
try {
|
||||
performRollback();
|
||||
|
||||
} catch (Exception ex) {
|
||||
} catch (SQLException ex) {
|
||||
throw new PersistenceException(ex);
|
||||
|
||||
} finally {
|
||||
// these will not throw an exception
|
||||
firePostRollback();
|
||||
deactivate();
|
||||
notifyRollback(cause);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,6 @@ import com.avaje.ebean.BackgroundExecutor;
|
||||
import com.avaje.ebean.config.PersistBatch;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform.OnQueryOnly;
|
||||
import com.avaje.ebean.dbmigration.DbOffline;
|
||||
import com.avaje.ebean.event.TransactionEventListener;
|
||||
import com.avaje.ebean.event.changelog.ChangeLogListener;
|
||||
import com.avaje.ebean.event.changelog.ChangeLogPrepare;
|
||||
import com.avaje.ebean.event.changelog.ChangeSet;
|
||||
@@ -14,11 +12,10 @@ import com.avaje.ebeaninternal.api.TransactionEvent;
|
||||
import com.avaje.ebeaninternal.api.TransactionEventTable;
|
||||
import com.avaje.ebeaninternal.api.TransactionEventTable.TableIUD;
|
||||
import com.avaje.ebeaninternal.server.cluster.ClusterManager;
|
||||
import com.avaje.ebeaninternal.server.core.bootup.BootupClasses;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptorManager;
|
||||
import org.avaje.datasource.DataSourcePool;
|
||||
import com.avaje.ebeanservice.docstore.api.DocStoreUpdateProcessor;
|
||||
import com.avaje.ebeanservice.docstore.api.DocStoreUpdates;
|
||||
import org.avaje.datasource.DataSourcePool;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -92,8 +89,6 @@ public class TransactionManager {
|
||||
|
||||
protected final BulkEventListenerMap bulkEventListenerMap;
|
||||
|
||||
protected final TransactionEventListener[] transactionEventListeners;
|
||||
|
||||
/**
|
||||
* Used to prepare the change set setting user context information in the
|
||||
* foreground thread before logging.
|
||||
@@ -115,7 +110,7 @@ public class TransactionManager {
|
||||
* Create the TransactionManager
|
||||
*/
|
||||
public TransactionManager(boolean localL2Caching, ServerConfig config, ClusterManager clusterManager, BackgroundExecutor backgroundExecutor,
|
||||
DocStoreUpdateProcessor docStoreUpdateProcessor, BeanDescriptorManager descMgr, BootupClasses bootupClasses) {
|
||||
DocStoreUpdateProcessor docStoreUpdateProcessor, BeanDescriptorManager descMgr) {
|
||||
|
||||
this.skipCacheAfterWrite = config.isSkipCacheAfterWrite();
|
||||
this.localL2Caching = localL2Caching;
|
||||
@@ -133,9 +128,6 @@ public class TransactionManager {
|
||||
this.docStoreUpdateProcessor = docStoreUpdateProcessor;
|
||||
this.bulkEventListenerMap = new BulkEventListenerMap(config.getBulkTableEventListeners());
|
||||
|
||||
List<TransactionEventListener> transactionEventListeners = bootupClasses.getTransactionEventListeners();
|
||||
this.transactionEventListeners = transactionEventListeners.toArray(new TransactionEventListener[transactionEventListeners.size()]);
|
||||
|
||||
this.prefix = "";
|
||||
this.externalTransPrefix = "e";
|
||||
|
||||
@@ -192,51 +184,10 @@ public class TransactionManager {
|
||||
return OnQueryOnly.valueOf(systemPropertyValue.trim().toUpperCase());
|
||||
}
|
||||
|
||||
if (OnQueryOnly.CLOSE.equals(dbPlatformOnQueryOnly)) {
|
||||
// check for read committed isolation level
|
||||
if (!isReadCommittedIsolation(ds)) {
|
||||
logger.warn("Ignoring DatabasePlatform.OnQueryOnly.CLOSE as the transaction Isolation Level is not READ_COMMITTED");
|
||||
// we will just use ROLLBACK and ignore the desired optimisation
|
||||
return OnQueryOnly.ROLLBACK;
|
||||
} else {
|
||||
// will use the OnQueryOnly.CLOSE optimisation
|
||||
return OnQueryOnly.CLOSE;
|
||||
}
|
||||
}
|
||||
// default to rollback if not defined on the platform
|
||||
return dbPlatformOnQueryOnly == null ? OnQueryOnly.ROLLBACK : dbPlatformOnQueryOnly;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the isolation level is read committed.
|
||||
*/
|
||||
protected boolean isReadCommittedIsolation(DataSource ds) {
|
||||
|
||||
if (DbOffline.isSet()) {
|
||||
return true;
|
||||
}
|
||||
Connection c = null;
|
||||
try {
|
||||
c = ds.getConnection();
|
||||
|
||||
int isolationLevel = c.getTransactionIsolation();
|
||||
return (isolationLevel == Connection.TRANSACTION_READ_COMMITTED);
|
||||
|
||||
} catch (SQLException ex) {
|
||||
String m = "Errored trying to determine the default Isolation Level";
|
||||
throw new PersistenceException(m, ex);
|
||||
|
||||
} finally {
|
||||
try {
|
||||
if (c != null) {
|
||||
c.close();
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
logger.error("closing connection", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getServerName() {
|
||||
return serverName;
|
||||
}
|
||||
@@ -344,16 +295,12 @@ public class TransactionManager {
|
||||
public void notifyOfRollback(SpiTransaction transaction, Throwable cause) {
|
||||
|
||||
try {
|
||||
if (TXN_LOGGER.isInfoEnabled()) {
|
||||
if (TXN_LOGGER.isDebugEnabled()) {
|
||||
String msg = transaction.getLogPrefix() + "Rollback";
|
||||
if (cause != null) {
|
||||
msg += " error: " + formatThrowable(cause);
|
||||
}
|
||||
TXN_LOGGER.info(msg);
|
||||
}
|
||||
|
||||
for (TransactionEventListener listener : transactionEventListeners) {
|
||||
listener.postTransactionRollback(transaction, cause);
|
||||
TXN_LOGGER.debug(msg);
|
||||
}
|
||||
|
||||
} catch (Exception ex) {
|
||||
@@ -410,10 +357,6 @@ public class TransactionManager {
|
||||
postCommit.notifyLocalCache();
|
||||
backgroundExecutor.execute(postCommit.backgroundNotify());
|
||||
|
||||
for (TransactionEventListener listener : transactionEventListeners) {
|
||||
listener.postTransactionCommit(transaction);
|
||||
}
|
||||
|
||||
} catch (Exception ex) {
|
||||
logger.error("NotifyOfCommit failed. L2 Cache potentially not notified.", ex);
|
||||
}
|
||||
|
||||
@@ -209,7 +209,7 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
|
||||
initialiseJacksonTypes(config);
|
||||
|
||||
if (bootupClasses != null) {
|
||||
initialiseCustomScalarTypes(jsonDateTime, bootupClasses, config);
|
||||
initialiseCustomScalarTypes(jsonDateTime, bootupClasses);
|
||||
initialiseScalarConverters(bootupClasses);
|
||||
initialiseCompoundTypes(bootupClasses);
|
||||
}
|
||||
@@ -682,7 +682,7 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
|
||||
* interface and register it with this TypeManager.
|
||||
* </p>
|
||||
*/
|
||||
protected void initialiseCustomScalarTypes(JsonConfig.DateTime mode, BootupClasses bootupClasses, ServerConfig serverConfig) {
|
||||
protected void initialiseCustomScalarTypes(JsonConfig.DateTime mode, BootupClasses bootupClasses) {
|
||||
|
||||
ScalarTypeLongToTimestamp longToTimestamp = new ScalarTypeLongToTimestamp(mode);
|
||||
|
||||
|
||||
@@ -165,11 +165,7 @@ public class ImmutableMetaFactory {
|
||||
if (methods[i].getParameterTypes().length == 0) {
|
||||
// could be a getter
|
||||
String methName = methods[i].getName();
|
||||
if (methName.equals("hashCode")) {
|
||||
|
||||
} else if (methName.equals("toString")) {
|
||||
|
||||
} else {
|
||||
if (!methName.equals("hashCode") && !methName.equals("toString")) {
|
||||
Class<?> returnType = methods[i].getReturnType();
|
||||
if (paramType.equals(returnType)) {
|
||||
return methods[i];
|
||||
|
||||
Reference in New Issue
Block a user