diff --git a/src/main/java/com/avaje/ebeaninternal/api/SpiTransaction.java b/src/main/java/com/avaje/ebeaninternal/api/SpiTransaction.java
index 6b8b8bed4..67304e390 100644
--- a/src/main/java/com/avaje/ebeaninternal/api/SpiTransaction.java
+++ b/src/main/java/com/avaje/ebeaninternal/api/SpiTransaction.java
@@ -6,7 +6,6 @@ import java.util.List;
import com.avaje.ebean.Transaction;
import com.avaje.ebean.bean.PersistenceContext;
import com.avaje.ebeaninternal.server.persist.BatchControl;
-import com.avaje.ebeaninternal.server.transaction.TransactionLogBuffer;
/**
* Extends Transaction with additional API required on server.
@@ -16,6 +15,11 @@ import com.avaje.ebeaninternal.server.transaction.TransactionLogBuffer;
*/
public interface SpiTransaction extends Transaction {
+ /**
+ * Return the string prefix with the transactin id and label used in logging.
+ */
+ public String getLogPrefix();
+
/**
* Return true if generated SQL and Bind values should be logged to the
* transaction log.
@@ -29,15 +33,14 @@ public interface SpiTransaction extends Transaction {
public boolean isLogSummary();
/**
- * Log a comment to the transaction log for Ebean INTERNAL use. There should
- * always be an external LogLevel check prior to calling this method.
+ * Log a message to the SQL logger.
*/
- public void logInternal(String msg);
+ public void logSql(String msg);
/**
- * Return the buffer containing transaction log messages.
+ * Log a message to the SUMMARY logger.
*/
- public TransactionLogBuffer getLogBuffer();
+ public void logSummary(String msg);
/**
* Register a "Derived Relationship" (that requires an additional update).
diff --git a/src/main/java/com/avaje/ebeaninternal/server/autofetch/DefaultAutoFetchManager.java b/src/main/java/com/avaje/ebeaninternal/server/autofetch/DefaultAutoFetchManager.java
index 8f64eabb6..0443d99e4 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/autofetch/DefaultAutoFetchManager.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/autofetch/DefaultAutoFetchManager.java
@@ -69,8 +69,6 @@ public class DefaultAutoFetchManager implements AutoFetchManager, Serializable {
private transient boolean queryTuningAddVersion;
private transient AutofetchMode mode;
-
- private transient boolean useFileLogging;
/**
* Server that owns this Profile Listener.
@@ -95,7 +93,6 @@ public class DefaultAutoFetchManager implements AutoFetchManager, Serializable {
AutofetchConfig autofetchConfig = serverConfig.getAutofetchConfig();
- useFileLogging = autofetchConfig.isUseFileLogging();
queryTuning = autofetchConfig.isQueryTuning();
queryTuningAddVersion = autofetchConfig.isQueryTuningAddVersion();
profiling = autofetchConfig.isProfiling();
@@ -116,7 +113,7 @@ public class DefaultAutoFetchManager implements AutoFetchManager, Serializable {
String msg = "AutoFetch queryTuning[" + queryTuning + "] profiling[" + profiling
+ "] mode[" + mode + "] profiling rate[" + profilingRate
+ "] min[" + profilingMin + "] base[" + profilingBase + "]";
- logging.logToJavaLogger(msg);
+ logging.logInfo(msg, null);
}
}
@@ -272,10 +269,10 @@ public class DefaultAutoFetchManager implements AutoFetchManager, Serializable {
*
*/
public void shutdown() {
- if (useFileLogging) {
+ //if (useFileLogging) {
collectUsageViaGC(-1);
serialize();
- }
+ //}
}
/**
diff --git a/src/main/java/com/avaje/ebeaninternal/server/autofetch/DefaultAutoFetchManagerLogging.java b/src/main/java/com/avaje/ebeaninternal/server/autofetch/DefaultAutoFetchManagerLogging.java
index fd36c5028..1fbe15737 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/autofetch/DefaultAutoFetchManagerLogging.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/autofetch/DefaultAutoFetchManagerLogging.java
@@ -1,15 +1,13 @@
package com.avaje.ebeaninternal.server.autofetch;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import com.avaje.ebean.config.AutofetchConfig;
import com.avaje.ebean.config.GlobalProperties;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebeaninternal.server.lib.BackgroundThread;
import com.avaje.ebeaninternal.server.querydefn.OrmQueryDetail;
-import com.avaje.ebeaninternal.server.transaction.log.SimpleLogger;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.logging.Level;
/**
* Handles the logging aspects for the DefaultAutoFetchListener.
@@ -22,12 +20,8 @@ public class DefaultAutoFetchManagerLogging {
private static final Logger logger = LoggerFactory.getLogger(DefaultAutoFetchManagerLogging.class);
- private final SimpleLogger fileLogger;
-
private final DefaultAutoFetchManager manager;
- private final boolean useFileLogger;
-
private final boolean traceUsageCollection;
public DefaultAutoFetchManagerLogging(ServerConfig serverConfig, DefaultAutoFetchManager profileListener) {
@@ -37,21 +31,8 @@ public class DefaultAutoFetchManagerLogging {
AutofetchConfig autofetchConfig = serverConfig.getAutofetchConfig();
traceUsageCollection = GlobalProperties.getBoolean("ebean.autofetch.traceUsageCollection", false);
- useFileLogger = autofetchConfig.isUseFileLogging();
-
- if (!useFileLogger) {
- fileLogger = null;
-
- } else {
- // a separate log file just like the transaction logging
- // for putting the profiling log messages. The benefit is that
- // this doesn't pollute the main log with heaps of messages.
- String baseDir = serverConfig.getLoggingDirectoryWithEval();
- fileLogger = new SimpleLogger(baseDir, "autofetch", true, "csv");
- }
-
+
int updateFreqInSecs = autofetchConfig.getProfileUpdateFrequency();
-
BackgroundThread.add(updateFreqInSecs, new UpdateProfile());
}
@@ -61,63 +42,30 @@ public class DefaultAutoFetchManagerLogging {
}
}
- private void logFile(String msg, Throwable e) {
- if (useFileLogger) {
- String errMsg = e == null ? "" : e.getMessage();
- fileLogger.log("\"Error\",\"" + msg+" "+errMsg+"\",,,,");
- }
- }
-
-
public void logInfo(String msg, Throwable e) {
- logFile(msg, e);
logger.info(msg, e);
}
public void logError(String msg, Throwable e) {
- logFile(msg, e);
logger.error(msg, e);
}
- @Deprecated
- public void logError(Level level, String msg, Throwable e) {
- logError(msg, e);
- }
-
- public void logToJavaLogger(String msg) {
- logger.info(msg);
- }
-
public void logSummary(String summaryInfo) {
- String msg = "\"Summary\",\""+summaryInfo+"\",,,,";
-
- if (useFileLogger) {
- fileLogger.log(msg);
- }
+ String msg = "\"Summary\",\""+summaryInfo+"\",,,,";
logger.debug(msg);
}
public void logChanged(TunedQueryInfo tunedFetch, OrmQueryDetail newQueryDetail) {
String msg = tunedFetch.getLogOutput(newQueryDetail);
-
- if (useFileLogger) {
- fileLogger.log(msg);
- } else {
- logger.debug(msg);
- }
+ logger.debug(msg);
}
public void logNew(TunedQueryInfo tunedFetch) {
String msg = tunedFetch.getLogOutput(null);
-
- if (useFileLogger) {
- fileLogger.log(msg);
- } else {
- logger.debug(msg);
- }
+ logger.debug(msg);
}
public boolean isTraceUsageCollection() {
diff --git a/src/main/java/com/avaje/ebeaninternal/server/cluster/mcast/OutgoingPacketsAcked.java b/src/main/java/com/avaje/ebeaninternal/server/cluster/mcast/OutgoingPacketsAcked.java
index f20405e00..f0bc221fb 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/cluster/mcast/OutgoingPacketsAcked.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/cluster/mcast/OutgoingPacketsAcked.java
@@ -30,18 +30,11 @@ public class OutgoingPacketsAcked {
private boolean resetGotAllMin() {
- long tempMin;
- if (recievedByMap.isEmpty()){
- //System.out.println(" -- -- -- -- "+recievedByMap.isEmpty());
- tempMin = Long.MAX_VALUE;
- } else {
- tempMin = Long.MAX_VALUE;
- }
+ long tempMin = Long.MAX_VALUE;
for (GroupMemberAck groupMemAck : recievedByMap.values()) {
long memberMin = groupMemAck.getGotAllPacketId();
- if (memberMin < tempMin){
- //System.out.println(" -- new tmpMin "+memberMin);
+ if (memberMin < tempMin) {
tempMin = memberMin;
}
}
@@ -62,24 +55,19 @@ public class OutgoingPacketsAcked {
GroupMemberAck groupMemberAck = recievedByMap.get(groupMember);
if (groupMemberAck == null) {
- //System.out.println(" -- new groupMemberAck");
groupMemberAck = new GroupMemberAck();
groupMemberAck.setIfBigger(ack.getGotAllPacketId());
recievedByMap.put(groupMember, groupMemberAck);
checkMin = true;
} else {
checkMin = groupMemberAck.getGotAllPacketId() == minimumGotAllPacketId;
- //System.out.println(" -- existing groupMemberAck, checkMin:"+checkMin+" "+groupMemberAck.getGotAllPacketId());
groupMemberAck.setIfBigger(ack.getGotAllPacketId());
}
boolean minChanged = false;
- //System.out.println(" -- checkMin:"+checkMin+" minimumGotAllPacketId:"+minimumGotAllPacketId);
- if (checkMin || minimumGotAllPacketId == 0){
-
+ if (checkMin || minimumGotAllPacketId == 0){
minChanged = resetGotAllMin();
- //System.out.println(" -- minChanged:"+minChanged+" minimumGotAllPacketId:"+minimumGotAllPacketId);
}
return minChanged ? minimumGotAllPacketId : 0;
diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultBeanLoader.java b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultBeanLoader.java
index 21987174e..724e1438b 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultBeanLoader.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultBeanLoader.java
@@ -5,6 +5,9 @@ import java.util.List;
import javax.persistence.EntityNotFoundException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import com.avaje.ebean.ExpressionList;
import com.avaje.ebean.Transaction;
import com.avaje.ebean.bean.BeanCollection;
@@ -21,8 +24,6 @@ import com.avaje.ebeaninternal.api.SpiQuery.Mode;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import com.avaje.ebeaninternal.server.transaction.DefaultPersistenceContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
* Helper to handle lazy loading and refreshing of beans.
@@ -164,21 +165,6 @@ public class DefaultBeanLoader {
ObjectGraphNode node = ctx == null ? null : ctx.getObjectGraphNode();
loadManyInternal(parentBean, propertyName, null, false, node, onlyIds);
-
- if (server.getAdminLogging().isDebugLazyLoad()) {
-
- Class> cls = parentBean.getClass();
- BeanDescriptor> desc = server.getBeanDescriptor(cls);
- BeanPropertyAssocMany> many = (BeanPropertyAssocMany>) desc.getBeanProperty(propertyName);
-
- StackTraceElement cause = debugLazyLoad.getStackTraceElement(cls);
-
- String msg = "debug.lazyLoad " + many.getManyType() + " [" + desc + "][" + propertyName + "]";
- if (cause != null) {
- msg += " at: " + cause;
- }
- System.err.println(msg);
- }
}
public void refreshMany(Object parentBean, String propertyName, Transaction t) {
diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java
index ce8b36d39..bc1b9d356 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java
@@ -13,14 +13,16 @@ import java.util.Map;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.concurrent.FutureTask;
-import java.util.ServiceLoader;
+
import javax.management.InstanceAlreadyExistsException;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.persistence.PersistenceException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import com.avaje.ebean.AdminAutofetch;
-import com.avaje.ebean.AdminLogging;
import com.avaje.ebean.BackgroundExecutor;
import com.avaje.ebean.BeanState;
import com.avaje.ebean.CallableSql;
@@ -108,8 +110,6 @@ import com.avaje.ebeaninternal.server.transaction.TransactionManager;
import com.avaje.ebeaninternal.server.transaction.TransactionScopeManager;
import com.avaje.ebeaninternal.util.ParamTypeHelper;
import com.avaje.ebeaninternal.util.ParamTypeHelper.TypeInfo;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
* The default server side implementation of EbeanServer.
@@ -122,8 +122,6 @@ public final class DefaultServer implements SpiEbeanServer {
private final DatabasePlatform databasePlatform;
- private final AdminLogging adminLogging;
-
private final AdminAutofetch adminAutofetch;
private final TransactionManager transactionManager;
@@ -224,7 +222,6 @@ public final class DefaultServer implements SpiEbeanServer {
this.queryBatchSize = config.getServerConfig().getQueryBatchSize();
this.cqueryEngine = config.getCQueryEngine();
this.expressionFactory = config.getExpressionFactory();
- this.adminLogging = config.getLogControl();
this.encryptKeyManager = config.getServerConfig().getEncryptKeyManager();
this.beanDescriptorManager = config.getBeanDescriptorManager();
@@ -321,10 +318,6 @@ public final class DefaultServer implements SpiEbeanServer {
return ddlGenerator;
}
- public AdminLogging getAdminLogging() {
- return adminLogging;
- }
-
public AdminAutofetch getAdminAutofetch() {
return adminAutofetch;
}
@@ -358,11 +351,9 @@ public final class DefaultServer implements SpiEbeanServer {
this.mbeanServer = mbeanServer;
this.mbeanName = "Ebean:server=" + serverName + uniqueServerId;
- ObjectName adminName;
- ObjectName autofethcName;
+ ObjectName autofetchName;
try {
- adminName = new ObjectName(mbeanName + ",function=Logging");
- autofethcName = new ObjectName(mbeanName + ",key=AutoFetch");
+ autofetchName = new ObjectName(mbeanName + ",key=AutoFetch");
} catch (Exception e) {
String msg = "Failed to register the JMX beans for Ebean server [" + serverName + "].";
logger.error(msg, e);
@@ -370,19 +361,15 @@ public final class DefaultServer implements SpiEbeanServer {
}
try {
- mbeanServer.registerMBean(adminLogging, adminName);
- mbeanServer.registerMBean(adminAutofetch, autofethcName);
+ mbeanServer.registerMBean(adminAutofetch, autofetchName);
} catch (InstanceAlreadyExistsException e) {
// tomcat webapp reloading
String msg = "JMX beans for Ebean server [" + serverName + "] already registered. Will try unregister/register" + e.getMessage();
logger.warn(msg);
try {
- mbeanServer.unregisterMBean(adminName);
- mbeanServer.unregisterMBean(autofethcName);
- // re-register
- mbeanServer.registerMBean(adminLogging, adminName);
- mbeanServer.registerMBean(adminAutofetch, autofethcName);
+ mbeanServer.unregisterMBean(autofetchName);
+ mbeanServer.registerMBean(adminAutofetch, autofetchName);
} catch (Exception ae) {
String amsg = "Unable to unregister/register the JMX beans for Ebean server [" + serverName + "].";
@@ -398,7 +385,6 @@ public final class DefaultServer implements SpiEbeanServer {
public void run() {
try {
if (mbeanServer != null) {
- mbeanServer.unregisterMBean(new ObjectName(mbeanName + ",function=Logging"));
mbeanServer.unregisterMBean(new ObjectName(mbeanName + ",key=AutoFetch"));
}
} catch (Exception e) {
@@ -674,16 +660,6 @@ public final class DefaultServer implements SpiEbeanServer {
return transactionManager.createTransaction(true, isolation.getLevel());
}
- /**
- * Log a comment to the transaction log (of the current transaction).
- */
- public void logComment(String msg) {
- Transaction t = transactionScopeManager.get();
- if (t != null) {
- t.log(msg);
- }
- }
-
public T execute(TxCallable c) {
return execute(null, c);
}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServerFactory.java b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServerFactory.java
index d33f4e910..3c5f6598c 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServerFactory.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServerFactory.java
@@ -341,14 +341,6 @@ public class DefaultServerFactory implements BootupEbeanManager {
return bootupClassSearch.getBootupClasses().createCopy();
}
- /**
- * Execute the DDL if required.
- */
- private void executeDDL(SpiEbeanServer server, boolean online) {
-
- server.getDdlGenerator().execute(online);
- }
-
/**
* Set the naming convention to underscore if it has not already been set.
*/
diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/InternalConfiguration.java b/src/main/java/com/avaje/ebeaninternal/server/core/InternalConfiguration.java
index c9fb29e36..67604b76a 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/core/InternalConfiguration.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/core/InternalConfiguration.java
@@ -1,5 +1,8 @@
package com.avaje.ebeaninternal.server.core;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import com.avaje.ebean.ExpressionFactory;
import com.avaje.ebean.cache.ServerCacheManager;
import com.avaje.ebean.config.ExternalTransactionManager;
@@ -19,7 +22,6 @@ import com.avaje.ebeaninternal.server.deploy.parse.DeployCreateProperties;
import com.avaje.ebeaninternal.server.deploy.parse.DeployInherit;
import com.avaje.ebeaninternal.server.deploy.parse.DeployUtil;
import com.avaje.ebeaninternal.server.expression.DefaultExpressionFactory;
-import com.avaje.ebeaninternal.server.jmx.MAdminLogging;
import com.avaje.ebeaninternal.server.persist.Binder;
import com.avaje.ebeaninternal.server.persist.DefaultPersister;
import com.avaje.ebeaninternal.server.query.CQueryEngine;
@@ -37,8 +39,6 @@ import com.avaje.ebeaninternal.server.transaction.TransactionManager;
import com.avaje.ebeaninternal.server.transaction.TransactionScopeManager;
import com.avaje.ebeaninternal.server.type.DefaultTypeManager;
import com.avaje.ebeaninternal.server.type.TypeManager;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
* Used to extend the ServerConfig with additional objects used to configure and
@@ -72,8 +72,6 @@ public class InternalConfiguration {
private final BeanDescriptorManager beanDescriptorManager;
- private final MAdminLogging logControl;
-
private final DebugLazyLoad debugLazyLoad;
private final TransactionManager transactionManager;
@@ -94,8 +92,9 @@ public class InternalConfiguration {
private final XmlConfig xmlConfig;
- public InternalConfiguration(XmlConfig xmlConfig, ClusterManager clusterManager, ServerCacheManager cacheManager,
- SpiBackgroundExecutor backgroundExecutor, ServerConfig serverConfig, BootupClasses bootupClasses, PstmtBatch pstmtBatch) {
+ public InternalConfiguration(XmlConfig xmlConfig, ClusterManager clusterManager,
+ ServerCacheManager cacheManager, SpiBackgroundExecutor backgroundExecutor,
+ ServerConfig serverConfig, BootupClasses bootupClasses, PstmtBatch pstmtBatch) {
this.xmlConfig = xmlConfig;
this.pstmtBatch = pstmtBatch;
@@ -123,20 +122,21 @@ public class InternalConfiguration {
this.debugLazyLoad = new DebugLazyLoad(serverConfig.isDebugLazyLoad());
- this.transactionManager = new TransactionManager(clusterManager, backgroundExecutor, serverConfig, beanDescriptorManager,
- this.getBootupClasses());
+ this.transactionManager = new TransactionManager(clusterManager, backgroundExecutor,
+ serverConfig, beanDescriptorManager, this.getBootupClasses());
- this.logControl = new MAdminLogging(serverConfig, transactionManager);
+ this.cQueryEngine = new CQueryEngine(serverConfig.getDatabasePlatform(), binder,
+ backgroundExecutor);
- this.cQueryEngine = new CQueryEngine(serverConfig.getDatabasePlatform(), logControl, binder, backgroundExecutor);
-
- ExternalTransactionManager externalTransactionManager = serverConfig.getExternalTransactionManager();
+ ExternalTransactionManager externalTransactionManager = serverConfig
+ .getExternalTransactionManager();
if (externalTransactionManager == null && serverConfig.isUseJtaTransactionManager()) {
externalTransactionManager = new JtaTransactionManager();
}
if (externalTransactionManager != null) {
externalTransactionManager.setTransactionManager(transactionManager);
- this.transactionScopeManager = new ExternalTransactionScopeManager(transactionManager, externalTransactionManager);
+ this.transactionScopeManager = new ExternalTransactionScopeManager(transactionManager,
+ externalTransactionManager);
logger.info("Using Transaction Manager [" + externalTransactionManager.getClass() + "]");
} else {
this.transactionScopeManager = new DefaultTransactionScopeManager(transactionManager);
@@ -167,7 +167,7 @@ public class InternalConfiguration {
}
public RelationalQueryEngine createRelationalQueryEngine() {
- return new DefaultRelationalQueryEngine(logControl, binder, serverConfig.getDatabaseBooleanTrue());
+ return new DefaultRelationalQueryEngine(binder, serverConfig.getDatabaseBooleanTrue());
}
public OrmQueryEngine createOrmQueryEngine() {
@@ -175,7 +175,7 @@ public class InternalConfiguration {
}
public Persister createPersister(SpiEbeanServer server) {
-
+
return new DefaultPersister(server, binder, beanDescriptorManager, pstmtBatch);
}
@@ -239,10 +239,6 @@ public class InternalConfiguration {
return deployUtil;
}
- public MAdminLogging getLogControl() {
- return logControl;
- }
-
public TransactionManager getTransactionManager() {
return transactionManager;
}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryRequest.java b/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryRequest.java
index f3a06e745..72cb538f2 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryRequest.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryRequest.java
@@ -403,7 +403,7 @@ public final class OrmQueryRequest extends BeanRequest implements BeanQueryRe
*/
public void logSql(String sql) {
if (transaction.isLogSql()) {
- transaction.logInternal(sql);
+ transaction.logSql(sql);
}
}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/PersistRequestBean.java b/src/main/java/com/avaje/ebeaninternal/server/core/PersistRequestBean.java
index 3d58118e3..15d279fe9 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/core/PersistRequestBean.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/core/PersistRequestBean.java
@@ -576,13 +576,13 @@ public class PersistRequestBean extends PersistRequest implements BeanPersist
String name = beanDescriptor.getName();
switch (type) {
case INSERT:
- transaction.logInternal("Inserted [" + name + "] [" + idValue + "]");
+ transaction.logSummary("Inserted [" + name + "] [" + idValue + "]");
break;
case UPDATE:
- transaction.logInternal("Updated [" + name + "] [" + idValue + "]");
+ transaction.logSummary("Updated [" + name + "] [" + idValue + "]");
break;
case DELETE:
- transaction.logInternal("Deleted [" + name + "] [" + idValue + "]");
+ transaction.logSummary("Deleted [" + name + "] [" + idValue + "]");
break;
default:
break;
diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/PersistRequestCallableSql.java b/src/main/java/com/avaje/ebeaninternal/server/core/PersistRequestCallableSql.java
index 2c93ef31e..7c0c200b5 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/core/PersistRequestCallableSql.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/core/PersistRequestCallableSql.java
@@ -90,7 +90,7 @@ public final class PersistRequestCallableSql extends PersistRequest {
if (transaction.isLogSummary()) {
String m = "CallableSql label[" + callableSql.getLabel() + "]" + " rows[" + rowCount+ "]" + " bind[" + bindLog + "]";
- transaction.logInternal(m);
+ transaction.logSummary(m);
}
// register table modifications with the transaction event
diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/PersistRequestOrmUpdate.java b/src/main/java/com/avaje/ebeaninternal/server/core/PersistRequestOrmUpdate.java
index d8cc19353..d3364b4b9 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/core/PersistRequestOrmUpdate.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/core/PersistRequestOrmUpdate.java
@@ -93,7 +93,7 @@ public final class PersistRequestOrmUpdate extends PersistRequest {
if (transaction.isLogSummary()) {
String m = ormUpdateType + " table[" + tableName + "] rows["+ rowCount + "] bind[" + bindLog + "]";
- transaction.logInternal(m);
+ transaction.logSummary(m);
}
if (ormUpdate.isNotifyCache()) {
diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/PersistRequestUpdateSql.java b/src/main/java/com/avaje/ebeaninternal/server/core/PersistRequestUpdateSql.java
index 008c3a861..bc0d10947 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/core/PersistRequestUpdateSql.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/core/PersistRequestUpdateSql.java
@@ -100,7 +100,7 @@ public final class PersistRequestUpdateSql extends PersistRequest {
if (transaction.isLogSummary()) {
String m = description + " table[" + tableName + "] rows["+ rowCount + "] bind[" + bindLog + "]";
- transaction.logInternal(m);
+ transaction.logSummary(m);
}
if (updateSql.isAutoTableMod()) {
diff --git a/src/main/java/com/avaje/ebeaninternal/server/ddl/DdlGenerator.java b/src/main/java/com/avaje/ebeaninternal/server/ddl/DdlGenerator.java
index 675d6351a..fd7a9e4ce 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/ddl/DdlGenerator.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/ddl/DdlGenerator.java
@@ -6,7 +6,6 @@ import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.LineNumberReader;
-import java.io.PrintStream;
import java.io.StringReader;
import java.sql.Connection;
import java.sql.PreparedStatement;
@@ -16,14 +15,15 @@ import java.util.List;
import javax.persistence.PersistenceException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import com.avaje.ebean.Transaction;
import com.avaje.ebean.config.NamingConvention;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
import com.avaje.ebeaninternal.api.SpiEbeanPlugin;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
* Controls the generation of DDL and potentially runs the resulting scripts.
diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/DbSqlContext.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/DbSqlContext.java
index d78aef344..482d2c958 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/deploy/DbSqlContext.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/DbSqlContext.java
@@ -1,116 +1,115 @@
package com.avaje.ebeaninternal.server.deploy;
-
/**
* Used to provide context during sql construction.
*/
public interface DbSqlContext {
- /**
- * Add a join to the sql query.
- */
- public void addJoin(String type, String table, TableJoinColumn[] cols, String a1, String a2);
+ /**
+ * Add a join to the sql query.
+ */
+ public void addJoin(String type, String table, TableJoinColumn[] cols, String a1, String a2);
- public void pushSecondaryTableAlias(String alias);
+ public void pushSecondaryTableAlias(String alias);
- /**
- * Push the current table alias onto the stack.
- */
- public void pushTableAlias(String tableAlias);
+ /**
+ * Push the current table alias onto the stack.
+ */
+ public void pushTableAlias(String tableAlias);
- /**
- * Pop the current table alias from the stack.
- */
- public void popTableAlias();
+ /**
+ * Pop the current table alias from the stack.
+ */
+ public void popTableAlias();
- /**
- * Add an encrypted property which will require additional binding.
- */
- public void addEncryptedProp(BeanProperty prop);
+ /**
+ * Add an encrypted property which will require additional binding.
+ */
+ public void addEncryptedProp(BeanProperty prop);
- /**
- * Return a list of encrypted properties which require additional binding.
- */
- public BeanProperty[] getEncryptedProps();
+ /**
+ * Return a list of encrypted properties which require additional binding.
+ */
+ public BeanProperty[] getEncryptedProps();
- /**
- * Append a char directly to the SQL buffer.
- */
- public DbSqlContext append(char s);
+ /**
+ * Append a char directly to the SQL buffer.
+ */
+ public DbSqlContext append(char s);
- /**
- * Append a string directly to the SQL buffer.
- */
- public DbSqlContext append(String s);
+ /**
+ * Append a string directly to the SQL buffer.
+ */
+ public DbSqlContext append(String s);
- /**
- * Peek the current table alias.
- */
- public String peekTableAlias();
+ /**
+ * Peek the current table alias.
+ */
+ public String peekTableAlias();
- /**
- * Add a raw column to the sql.
- */
- public void appendRawColumn(String rawcolumnWithTableAlias);
+ /**
+ * Add a raw column to the sql.
+ */
+ public void appendRawColumn(String rawcolumnWithTableAlias);
- /**
- * Append a column with an explicit table alias.
- */
- public void appendColumn(String tableAlias, String column);
+ /**
+ * Append a column with an explicit table alias.
+ */
+ public void appendColumn(String tableAlias, String column);
- /**
- * Append a column with the current table alias.
- */
- public void appendColumn(String column);
+ /**
+ * Append a column with the current table alias.
+ */
+ public void appendColumn(String column);
- /**
- * Append a Sql Formula select. This converts the "${ta}" keyword to the
- * current table alias.
- */
- public void appendFormulaSelect(String sqlFormulaSelect);
+ /**
+ * Append a Sql Formula select. This converts the "${ta}" keyword to the
+ * current table alias.
+ */
+ public void appendFormulaSelect(String sqlFormulaSelect);
- /**
- * Append a Sql Formula join. This converts the "${ta}" keyword to the
- * current table alias.
- */
- public void appendFormulaJoin(String sqlFormulaJoin, boolean forceOuterJoin);
+ /**
+ * Append a Sql Formula join. This converts the "${ta}" keyword to the current
+ * table alias.
+ */
+ public void appendFormulaJoin(String sqlFormulaJoin, boolean forceOuterJoin);
- /**
- * Return the current content length.
- */
- public int length();
+ /**
+ * Return the current content length.
+ */
+ public int length();
- /**
- * Return the current context of the sql context.
- */
- public String getContent();
+ /**
+ * Return the current context of the sql context.
+ */
+ public String getContent();
- /**
- * Return the current join node.
- */
- public String peekJoin();
+ /**
+ * Return the current join node.
+ */
+ public String peekJoin();
- /**
- * Push a join node onto the stack.
- */
- public void pushJoin(String prefix);
+ /**
+ * Push a join node onto the stack.
+ */
+ public void pushJoin(String prefix);
- /**
- * Pop a join node off the stack.
- */
- public void popJoin();
+ /**
+ * Pop a join node off the stack.
+ */
+ public void popJoin();
- /**
- * Return a table alias without many where clause joins.
- * Typically this is for the select clause (fetch joins).
- */
- public String getTableAlias(String prefix);
+ /**
+ * Return a table alias without many where clause joins. Typically this is for
+ * the select clause (fetch joins).
+ */
+ public String getTableAlias(String prefix);
- /**
- * Return a table alias that takes into account many where joins.
- */
- public String getTableAliasManyWhere(String prefix);
+ /**
+ * Return a table alias that takes into account many where joins.
+ */
+ public String getTableAliasManyWhere(String prefix);
- public String getRelativePrefix(String propName);
+ public String getRelativePrefix(String propName);
}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/TableJoin.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/TableJoin.java
index 7fc9e1f0f..9c23588eb 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/deploy/TableJoin.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/TableJoin.java
@@ -15,194 +15,189 @@ import com.avaje.ebeaninternal.server.query.SqlBeanLoad;
*/
public final class TableJoin {
-
- public static final String NEW_LINE = "\n";
-
- public static final String LEFT_OUTER = "left outer join";
+ public static final String LEFT_OUTER = "left outer join";
- public static final String JOIN = "join";
-
- /**
- * Flag set when the imported key maps to the primary key.
- * This occurs for intersection tables (ManyToMany).
- */
- private final boolean importedPrimaryKey;
-
- /**
- * The joined table.
- */
- private final String table;
-
- /**
- * The type of join. LEFT OUTER etc.
- */
- private final String type;
+ public static final String JOIN = "join";
- /**
- * The persist cascade info.
- */
- private final BeanCascadeInfo cascadeInfo;
-
- /**
- * Properties as an array.
- */
- private final BeanProperty[] properties;
-
- /**
- * Columns as an array.
- */
- private final TableJoinColumn[] columns;
+ /**
+ * Flag set when the imported key maps to the primary key. This occurs for
+ * intersection tables (ManyToMany).
+ */
+ private final boolean importedPrimaryKey;
- /**
- * Create a TableJoin.
- */
- public TableJoin(DeployTableJoin deploy, LinkedHashMap propMap) {
-
- this.importedPrimaryKey = deploy.isImportedPrimaryKey();
- this.table = InternString.intern(deploy.getTable());
- this.type = InternString.intern(deploy.getType());
- this.cascadeInfo = deploy.getCascadeInfo();
-
- DeployTableJoinColumn[] deployCols = deploy.columns();
- this.columns = new TableJoinColumn[deployCols.length];
- for (int i = 0; i < deployCols.length; i++) {
- this.columns[i] = new TableJoinColumn(deployCols[i]);
- }
-
- DeployBeanProperty[] deployProps = deploy.properties();
- if (deployProps.length > 0 && propMap == null){
- throw new NullPointerException("propMap is null?");
- }
-
- this.properties = new BeanProperty[deployProps.length];
- for (int i = 0; i < deployProps.length; i++) {
- BeanProperty prop = propMap.get(deployProps[i].getName());
- this.properties[i] = prop;
- }
-
+ /**
+ * The joined table.
+ */
+ private final String table;
+
+ /**
+ * The type of join. LEFT OUTER etc.
+ */
+ private final String type;
+
+ /**
+ * The persist cascade info.
+ */
+ private final BeanCascadeInfo cascadeInfo;
+
+ /**
+ * Properties as an array.
+ */
+ private final BeanProperty[] properties;
+
+ /**
+ * Columns as an array.
+ */
+ private final TableJoinColumn[] columns;
+
+ /**
+ * Create a TableJoin.
+ */
+ public TableJoin(DeployTableJoin deploy, LinkedHashMap propMap) {
+
+ this.importedPrimaryKey = deploy.isImportedPrimaryKey();
+ this.table = InternString.intern(deploy.getTable());
+ this.type = InternString.intern(deploy.getType());
+ this.cascadeInfo = deploy.getCascadeInfo();
+
+ DeployTableJoinColumn[] deployCols = deploy.columns();
+ this.columns = new TableJoinColumn[deployCols.length];
+ for (int i = 0; i < deployCols.length; i++) {
+ this.columns[i] = new TableJoinColumn(deployCols[i]);
}
- /**
- * Create a tableJoin based on this object but with different alias.
- */
- public TableJoin createWithAlias(String localAlias, String foreignAlias) {
-
- return new TableJoin(this, localAlias, foreignAlias);
- }
-
- /**
- * Construct a copy but with different table alias'.
- */
- private TableJoin(TableJoin join, String localAlias, String foreignAlias){
-
- // copy the immutable fields
- this.importedPrimaryKey = join.importedPrimaryKey;
- this.table = join.table;
- this.type = join.type;
- this.cascadeInfo = join.cascadeInfo;
- this.properties = join.properties;
- this.columns = join.columns;
- }
-
-
- public String toString() {
- StringBuilder sb = new StringBuilder(30);
- sb.append(type).append(" ").append(table).append(" ");
- for (int i = 0; i < columns.length; i++) {
- sb.append(columns[i]).append(" ");
- }
- return sb.toString();
+ DeployBeanProperty[] deployProps = deploy.properties();
+ if (deployProps.length > 0 && propMap == null) {
+ throw new NullPointerException("propMap is null?");
}
- public void appendSelect(DbSqlContext ctx, boolean subQuery) {
- for (int i = 0, x = properties.length; i < x; i++) {
- properties[i].appendSelect(ctx, subQuery);
- }
- }
-
- public void load(SqlBeanLoad sqlBeanLoad) throws SQLException {
- for (int i = 0, x = properties.length; i < x; i++) {
- properties[i].load(sqlBeanLoad);
- }
- }
-
- public Object readSet(DbReadContext ctx, Object bean, Class> type) throws SQLException {
- for (int i = 0, x = properties.length; i < x; i++) {
- properties[i].readSet(ctx, bean, type);
- }
- return null;
- }
-
- /**
- * Return true if the imported foreign key maps to the primary key.
- */
- public boolean isImportedPrimaryKey() {
- return importedPrimaryKey;
- }
-
- /**
- * Return the persist info.
- */
- public BeanCascadeInfo getCascadeInfo() {
- return cascadeInfo;
+ this.properties = new BeanProperty[deployProps.length];
+ for (int i = 0; i < deployProps.length; i++) {
+ BeanProperty prop = propMap.get(deployProps[i].getName());
+ this.properties[i] = prop;
}
- /**
- * Return the join columns.
- */
- public TableJoinColumn[] columns() {
- return columns;
- }
+ }
-
- /**
- * For secondary table joins returns the properties mapped to that table.
- */
- public BeanProperty[] properties() {
- return properties;
- }
+ /**
+ * Create a tableJoin based on this object but with different alias.
+ */
+ public TableJoin createWithAlias(String localAlias, String foreignAlias) {
- /**
- * Return the joined table name.
- */
- public String getTable() {
- return table;
- }
+ return new TableJoin(this, localAlias, foreignAlias);
+ }
- /**
- * Return the type of join. LEFT OUTER JOIN etc.
- */
- public String getType() {
- return type;
- }
+ /**
+ * Construct a copy but with different table alias'.
+ */
+ private TableJoin(TableJoin join, String localAlias, String foreignAlias) {
- /**
- * Return true if this join is a left outer join.
- */
- public boolean isOuterJoin() {
- return type.equals(LEFT_OUTER);
- }
-
- public boolean addJoin(boolean forceOuterJoin, String prefix, DbSqlContext ctx) {
+ // copy the immutable fields
+ this.importedPrimaryKey = join.importedPrimaryKey;
+ this.table = join.table;
+ this.type = join.type;
+ this.cascadeInfo = join.cascadeInfo;
+ this.properties = join.properties;
+ this.columns = join.columns;
+ }
- String[] names = SplitName.split(prefix);
- String a1 = ctx.getTableAlias(names[0]);
- String a2 = ctx.getTableAlias(prefix);
+ public String toString() {
+ StringBuilder sb = new StringBuilder(30);
+ sb.append(type).append(" ").append(table).append(" ");
+ for (int i = 0; i < columns.length; i++) {
+ sb.append(columns[i]).append(" ");
+ }
+ return sb.toString();
+ }
- return addJoin(forceOuterJoin, a1, a2, ctx);
+ public void appendSelect(DbSqlContext ctx, boolean subQuery) {
+ for (int i = 0, x = properties.length; i < x; i++) {
+ properties[i].appendSelect(ctx, subQuery);
}
-
- public boolean addJoin(boolean forceOuterJoin, String a1, String a2, DbSqlContext ctx) {
-
- ctx.addJoin(forceOuterJoin?LEFT_OUTER:type, table, columns(), a1, a2);
-
- return forceOuterJoin || LEFT_OUTER.equals(type);
+ }
+
+ public void load(SqlBeanLoad sqlBeanLoad) throws SQLException {
+ for (int i = 0, x = properties.length; i < x; i++) {
+ properties[i].load(sqlBeanLoad);
}
-
- /**
- * Explicitly add a (non-outer) join.
- */
- public void addInnerJoin(String a1, String a2, DbSqlContext ctx) {
- ctx.addJoin(JOIN, table, columns(), a1, a2);
+ }
+
+ public Object readSet(DbReadContext ctx, Object bean, Class> type) throws SQLException {
+ for (int i = 0, x = properties.length; i < x; i++) {
+ properties[i].readSet(ctx, bean, type);
}
+ return null;
+ }
+
+ /**
+ * Return true if the imported foreign key maps to the primary key.
+ */
+ public boolean isImportedPrimaryKey() {
+ return importedPrimaryKey;
+ }
+
+ /**
+ * Return the persist info.
+ */
+ public BeanCascadeInfo getCascadeInfo() {
+ return cascadeInfo;
+ }
+
+ /**
+ * Return the join columns.
+ */
+ public TableJoinColumn[] columns() {
+ return columns;
+ }
+
+ /**
+ * For secondary table joins returns the properties mapped to that table.
+ */
+ public BeanProperty[] properties() {
+ return properties;
+ }
+
+ /**
+ * Return the joined table name.
+ */
+ public String getTable() {
+ return table;
+ }
+
+ /**
+ * Return the type of join. LEFT OUTER JOIN etc.
+ */
+ public String getType() {
+ return type;
+ }
+
+ /**
+ * Return true if this join is a left outer join.
+ */
+ public boolean isOuterJoin() {
+ return type.equals(LEFT_OUTER);
+ }
+
+ public boolean addJoin(boolean forceOuterJoin, String prefix, DbSqlContext ctx) {
+
+ String[] names = SplitName.split(prefix);
+ String a1 = ctx.getTableAlias(names[0]);
+ String a2 = ctx.getTableAlias(prefix);
+
+ return addJoin(forceOuterJoin, a1, a2, ctx);
+ }
+
+ public boolean addJoin(boolean forceOuterJoin, String a1, String a2, DbSqlContext ctx) {
+
+ ctx.addJoin(forceOuterJoin ? LEFT_OUTER : type, table, columns(), a1, a2);
+
+ return forceOuterJoin || LEFT_OUTER.equals(type);
+ }
+
+ /**
+ * Explicitly add a (non-outer) join.
+ */
+ public void addInnerJoin(String a1, String a2, DbSqlContext ctx) {
+ ctx.addJoin(JOIN, table, columns(), a1, a2);
+ }
}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/jmx/MAdminLogging.java b/src/main/java/com/avaje/ebeaninternal/server/jmx/MAdminLogging.java
deleted file mode 100644
index f052fbd4f..000000000
--- a/src/main/java/com/avaje/ebeaninternal/server/jmx/MAdminLogging.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package com.avaje.ebeaninternal.server.jmx;
-
-import com.avaje.ebean.AdminLogging;
-import com.avaje.ebean.EbeanServer;
-import com.avaje.ebean.LogLevel;
-import com.avaje.ebean.config.ServerConfig;
-import com.avaje.ebeaninternal.server.transaction.TransactionManager;
-
-/**
- * Implementation of the LogControl.
- *
- * This is accessible via {@link EbeanServer#getAdminLogging()} or via JMX MBean.
- *
- */
-public class MAdminLogging implements MAdminLoggingMBean, AdminLogging {
-
- private final TransactionManager transactionManager;
-
- private boolean debugSql;
- private boolean debugLazyLoad;
-
- /**
- * Configure from serverConfig properties.
- */
- public MAdminLogging(ServerConfig serverConfig, TransactionManager txManager) {
-
- this.transactionManager = txManager;
- this.debugSql = serverConfig.isDebugSql();
- this.debugLazyLoad = serverConfig.isDebugLazyLoad();
- }
-
- public void setLogLevel(LogLevel logLevel){
- transactionManager.setTransactionLogLevel(logLevel);
- }
-
- public LogLevel getLogLevel() {
- return transactionManager.getTransactionLogLevel();
- }
-
- public boolean isDebugGeneratedSql() {
- return debugSql;
- }
-
- public void setDebugGeneratedSql(boolean debugSql) {
- this.debugSql = debugSql;
- }
-
- public boolean isDebugLazyLoad() {
- return debugLazyLoad;
- }
-
- public void setDebugLazyLoad(boolean debugLazyLoad) {
- this.debugLazyLoad = debugLazyLoad;
- }
-
-}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/jmx/MAdminLoggingMBean.java b/src/main/java/com/avaje/ebeaninternal/server/jmx/MAdminLoggingMBean.java
deleted file mode 100644
index 44c3e3c51..000000000
--- a/src/main/java/com/avaje/ebeaninternal/server/jmx/MAdminLoggingMBean.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package com.avaje.ebeaninternal.server.jmx;
-
-import com.avaje.ebean.LogLevel;
-
-public interface MAdminLoggingMBean {
-
- /**
- * The current log level .
- */
- public LogLevel getLogLevel();
-
- /**
- * Set the log level for native sql queries.
- */
- public void setLogLevel(LogLevel logLevel);
-
- /**
- * If true Log generated sql to the console.
- */
- public boolean isDebugGeneratedSql();
-
- /**
- * Set to true to Log generated sql to the console.
- */
- public void setDebugGeneratedSql(boolean debugSql);
-
- /**
- * Return true if lazy loading should be debugged.
- */
- public boolean isDebugLazyLoad();
-
- /**
- * Set the debugging on lazy loading.
- */
- public void setDebugLazyLoad(boolean debugLazyLoad);
-
-}
\ No newline at end of file
diff --git a/src/main/java/com/avaje/ebeaninternal/server/persist/BatchControl.java b/src/main/java/com/avaje/ebeaninternal/server/persist/BatchControl.java
index b1adbe1b6..bdd16c903 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/persist/BatchControl.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/persist/BatchControl.java
@@ -237,7 +237,7 @@ public final class BatchControl {
Arrays.sort(bsArray, depthComparator);
if (transaction.isLogSummary()) {
- transaction.logInternal("BatchControl flush " + Arrays.toString(bsArray));
+ transaction.logSummary("BatchControl flush " + Arrays.toString(bsArray));
}
for (int i = 0; i < bsArray.length; i++) {
BatchedBeanHolder bs = bsArray[i];
diff --git a/src/main/java/com/avaje/ebeaninternal/server/persist/DefaultPersister.java b/src/main/java/com/avaje/ebeaninternal/server/persist/DefaultPersister.java
index cb86a0f87..3a560f435 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/persist/DefaultPersister.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/persist/DefaultPersister.java
@@ -498,7 +498,7 @@ public final class DefaultPersister implements Persister {
if (idList != null) {
q.where().idIn(idList);
if (t.isLogSummary()) {
- t.logInternal("-- DeleteById of " + descriptor.getName() + " ids[" + idList + "] requires fetch of foreign key values");
+ t.logSummary("-- DeleteById of " + descriptor.getName() + " ids[" + idList + "] requires fetch of foreign key values");
}
List> beanList = server.findList(q, t);
deleteList(beanList, t);
@@ -507,7 +507,7 @@ public final class DefaultPersister implements Persister {
} else {
q.where().idEq(id);
if (t.isLogSummary()) {
- t.logInternal("-- DeleteById of " + descriptor.getName() + " id[" + id + "] requires fetch of foreign key values");
+ t.logSummary("-- DeleteById of " + descriptor.getName() + " id[" + id + "] requires fetch of foreign key values");
}
Object bean = server.findUnique(q, t);
if (bean == null) {
@@ -555,7 +555,7 @@ public final class DefaultPersister implements Persister {
for (int i = 0; i < manys.length; i++) {
SqlUpdate sqlDelete = manys[i].deleteByParentId(id, idList);
if (t.isLogSummary()) {
- t.logInternal("-- Deleting intersection table entries: " + manys[i].getFullBeanName());
+ t.logSummary("-- Deleting intersection table entries: " + manys[i].getFullBeanName());
}
executeSqlUpdate(sqlDelete, t);
}
@@ -563,7 +563,7 @@ public final class DefaultPersister implements Persister {
// delete the bean(s)
SqlUpdate deleteById = descriptor.deleteById(id, idList);
if (t.isLogSummary()) {
- t.logInternal("-- Deleting " + descriptor.getName() + " Ids" + idList);
+ t.logSummary("-- Deleting " + descriptor.getName() + " Ids" + idList);
}
// use Id's to update L2 cache rather than Bulk table event
@@ -1020,7 +1020,7 @@ public final class DefaultPersister implements Persister {
if (deletions != null && deletions.remove(otherBean)) {
String m = "Inserting and Deleting same object? " + otherBean;
if (t.isLogSummary()) {
- t.logInternal(m);
+ t.logSummary(m);
}
logger.warn(m);
diff --git a/src/main/java/com/avaje/ebeaninternal/server/persist/DeleteUnloadedForeignKeys.java b/src/main/java/com/avaje/ebeaninternal/server/persist/DeleteUnloadedForeignKeys.java
index fd3285285..3b69596a9 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/persist/DeleteUnloadedForeignKeys.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/persist/DeleteUnloadedForeignKeys.java
@@ -68,7 +68,7 @@ public class DeleteUnloadedForeignKeys {
SpiTransaction t = request.getTransaction();
if (t.isLogSummary()) {
- t.logInternal("-- Ebean fetching foreign key values for delete of " + descriptor.getName() + " id:" + id);
+ t.logSummary("-- Ebean fetching foreign key values for delete of " + descriptor.getName() + " id:" + id);
}
beanWithForeignKeys = server.findUnique(q, t);
}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/persist/ExeCallableSql.java b/src/main/java/com/avaje/ebeaninternal/server/persist/ExeCallableSql.java
index 2d83b2913..600718fbd 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/persist/ExeCallableSql.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/persist/ExeCallableSql.java
@@ -95,7 +95,7 @@ public class ExeCallableSql {
} else {
if (logSql){
- t.logInternal(sql);
+ t.logSql(sql);
}
cstmt = pstmtFactory.getCstmt(t, sql);
}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/persist/ExeOrmUpdate.java b/src/main/java/com/avaje/ebeaninternal/server/persist/ExeOrmUpdate.java
index 52b78a9b6..d3fba3418 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/persist/ExeOrmUpdate.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/persist/ExeOrmUpdate.java
@@ -123,7 +123,7 @@ public class ExeOrmUpdate {
} else {
if (logSql){
- t.logInternal(sql);
+ t.logSql(sql);
}
pstmt = pstmtFactory.getPstmt(t, sql);
}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/persist/ExeUpdateSql.java b/src/main/java/com/avaje/ebeaninternal/server/persist/ExeUpdateSql.java
index 0f3ea2784..d374fdf0e 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/persist/ExeUpdateSql.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/persist/ExeUpdateSql.java
@@ -115,7 +115,7 @@ public class ExeUpdateSql {
} else {
if (logSql){
- t.logInternal(sql);
+ t.logSql(sql);
}
pstmt = pstmtFactory.getPstmt(t, sql);
}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/persist/PstmtFactory.java b/src/main/java/com/avaje/ebeaninternal/server/persist/PstmtFactory.java
index 5a1cf50ac..7dd0f30e6 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/persist/PstmtFactory.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/persist/PstmtFactory.java
@@ -54,7 +54,7 @@ public class PstmtFactory {
}
if (logSql){
- t.logInternal(sql);
+ t.logSql(sql);
}
Connection conn = t.getInternalConnection();
@@ -83,7 +83,7 @@ public class PstmtFactory {
}
if (logSql){
- t.logInternal(sql);
+ t.logSql(sql);
}
Connection conn = t.getInternalConnection();
diff --git a/src/main/java/com/avaje/ebeaninternal/server/persist/dml/DeleteHandler.java b/src/main/java/com/avaje/ebeaninternal/server/persist/dml/DeleteHandler.java
index 5d1a38c1b..69b3f5701 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/persist/dml/DeleteHandler.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/persist/dml/DeleteHandler.java
@@ -36,23 +36,14 @@ public class DeleteHandler extends DmlHandler {
PreparedStatement pstmt;
if (isBatch) {
pstmt = getPstmt(t, sql, persistRequest, false);
-
} else {
- logSql(sql);
pstmt = getPstmt(t, sql, false);
}
dataBind = new DataBind(pstmt);
-
- bindLogAppend("Binding Delete [");
- bindLogAppend(meta.getTableName());
- bindLogAppend("] where[");
meta.bind(persistRequest, this);
- bindLogAppend("]");
-
- // log the binding to transaction log if requested
- logBinding();
+ logSql(sql);
}
/**
diff --git a/src/main/java/com/avaje/ebeaninternal/server/persist/dml/DmlBeanPersister.java b/src/main/java/com/avaje/ebeaninternal/server/persist/dml/DmlBeanPersister.java
index 693dadcbe..fd30a83f9 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/persist/dml/DmlBeanPersister.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/persist/dml/DmlBeanPersister.java
@@ -91,7 +91,7 @@ public final class DmlBeanPersister implements BeanPersister {
String errMsg = StringHelper.replaceStringMulti(e.getMessage(), new String[]{"\r","\n"}, "\\n ");
String msg = "ERROR executing DML bindLog["+handler.getBindLog()+"] error["+errMsg+"]";
if (request.getTransaction().isLogSummary()) {
- request.getTransaction().logInternal(msg);
+ request.getTransaction().logSummary(msg);
}
throw new PersistenceException(msg, e);
diff --git a/src/main/java/com/avaje/ebeaninternal/server/persist/dml/DmlHandler.java b/src/main/java/com/avaje/ebeaninternal/server/persist/dml/DmlHandler.java
index 9de126b0b..fe6b2b226 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/persist/dml/DmlHandler.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/persist/dml/DmlHandler.java
@@ -16,47 +16,43 @@ import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import com.avaje.ebeaninternal.server.persist.BatchedPstmt;
import com.avaje.ebeaninternal.server.persist.BatchedPstmtHolder;
import com.avaje.ebeaninternal.server.persist.dmlbind.BindableRequest;
+import com.avaje.ebeaninternal.server.transaction.TransactionManager;
import com.avaje.ebeaninternal.server.type.DataBind;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-
/**
* Base class for Handler implementations.
*/
public abstract class DmlHandler implements PersistHandler, BindableRequest {
private static final Logger logger = LoggerFactory.getLogger(DmlHandler.class);
-
- /**
- * The originating request.
- */
- protected final PersistRequestBean> persistRequest;
- protected final StringBuilder bindLog;
+ /**
+ * The originating request.
+ */
+ protected final PersistRequestBean> persistRequest;
- protected final Set loadedProps;
+ protected final StringBuilder bindLog;
- protected final SpiTransaction transaction;
-
- protected final boolean emptyStringToNull;
-
- protected final boolean logLevelSql;
+ protected final Set loadedProps;
- /**
- * The PreparedStatement used for the dml.
- */
- protected DataBind dataBind;
-
- protected String sql;
-
- protected ArrayList updateGenValues;
-
- private Set additionalProps;
+ protected final SpiTransaction transaction;
-// private boolean checkDelta;
-//
-// private BeanDelta deltaBean;
+ protected final boolean emptyStringToNull;
+
+ protected final boolean logLevelSql;
+
+ /**
+ * The PreparedStatement used for the dml.
+ */
+ protected DataBind dataBind;
+
+ protected String sql;
+
+ protected ArrayList updateGenValues;
+
+ private Set additionalProps;
protected DmlHandler(PersistRequestBean> persistRequest, boolean emptyStringToNull) {
this.persistRequest = persistRequest;
@@ -71,329 +67,308 @@ public abstract class DmlHandler implements PersistHandler, BindableRequest {
}
}
-// protected void setCheckDelta(boolean checkDelta) {
-// this.checkDelta = checkDelta;
-// }
-
public PersistRequestBean> getPersistRequest() {
return persistRequest;
}
-
- /**
- * Get the sql and bind the statement.
- */
- public abstract void bind() throws SQLException;
- /**
- * Execute now for non-batch execution.
- */
- public abstract void execute() throws SQLException;
+ /**
+ * Get the sql and bind the statement.
+ */
+ public abstract void bind() throws SQLException;
- /**
- * Check the rowCount.
- */
- protected void checkRowCount(int rowCount) throws SQLException, OptimisticLockException {
- try {
- persistRequest.checkRowCount(rowCount);
- persistRequest.postExecute();
- } catch (OptimisticLockException e){
- // add the SQL and bind values to error message
- String m = e.getMessage()+" sql["+sql+"] bind["+bindLog+"]";
- persistRequest.getTransaction().log("OptimisticLockException:"+m);
- throw new OptimisticLockException(m, null, e.getEntity());
- }
- }
-
- /**
- * Add this for batch execution.
- */
- public void addBatch() throws SQLException {
- PstmtBatch pstmtBatch = persistRequest.getPstmtBatch();
- if (pstmtBatch != null){
- pstmtBatch.addBatch(dataBind.getPstmt());
- } else {
- dataBind.getPstmt().addBatch();
- }
- }
+ /**
+ * Execute now for non-batch execution.
+ */
+ public abstract void execute() throws SQLException;
- /**
- * Close the underlying statement.
- */
- public void close() {
- try {
- if (dataBind != null){
- dataBind.close();
- }
- } catch (SQLException ex) {
- logger.error(null, ex);
- }
- }
-
- /**
- * Return the bind log.
- */
- public String getBindLog() {
- return bindLog == null ? "" : bindLog.toString();
- }
-
- /**
- * Set the Id value that was bound. This value is used for logging summary
- * level information.
- */
- public void setIdValue(Object idValue) {
- persistRequest.setBoundId(idValue);
- }
-
- /**
- * Log the bind information to the transaction log.
- */
- protected void logBinding() {
- if (logLevelSql) {
- transaction.logInternal(bindLog.toString());
- }
- }
-
- /**
- * Log the sql to the transaction log.
- */
- protected void logSql(String sql) {
- if (logLevelSql) {
- transaction.logInternal(sql);
- }
- }
-
-
- public boolean isIncluded(BeanProperty prop) {
- return (loadedProps == null || loadedProps.contains(prop.getName()));
- }
-
- public boolean isIncludedWhere(BeanProperty prop) {
- if (prop.isDbEncrypted()){
- // update without a version property ...
- // for encrypted properties only include if it was
- // also an updated/modified property
- return isIncluded(prop);
- }
- return prop.isDbUpdatable() && (loadedProps == null || loadedProps.contains(prop.getName()));
+ /**
+ * Check the rowCount.
+ */
+ protected void checkRowCount(int rowCount) throws SQLException, OptimisticLockException {
+ try {
+ persistRequest.checkRowCount(rowCount);
+ persistRequest.postExecute();
+ } catch (OptimisticLockException e) {
+ // add the SQL and bind values to error message
+ String m = e.getMessage() + " sql[" + sql + "] bind[" + bindLog + "]";
+ persistRequest.getTransaction().logSummary("OptimisticLockException:" + m);
+ throw new OptimisticLockException(m, null, e.getEntity());
}
-
- /**
- * Bind a raw value. Used to bind the discriminator column.
- */
- public Object bind(String propName, Object value, int sqlType) throws SQLException {
- if (logLevelSql) {
- bindLog.append(propName).append("=");
- bindLog.append(value).append(", ");
- }
- dataBind.setObject(value, sqlType);
- return value;
- }
+ }
- public Object bindNoLog(Object value, int sqlType, String logPlaceHolder) throws SQLException {
- if (logLevelSql) {
- bindLog.append(logPlaceHolder).append(" ");
- }
- dataBind.setObject(value, sqlType);
- return value;
+ /**
+ * Add this for batch execution.
+ */
+ public void addBatch() throws SQLException {
+ PstmtBatch pstmtBatch = persistRequest.getPstmtBatch();
+ if (pstmtBatch != null) {
+ pstmtBatch.addBatch(dataBind.getPstmt());
+ } else {
+ dataBind.getPstmt().addBatch();
}
+ }
- /**
- * Bind the value to the preparedStatement.
- */
- public Object bind(Object value, BeanProperty prop, String propName, boolean bindNull) throws SQLException {
- return bindInternal(logLevelSql, value, prop, propName, bindNull);
+ /**
+ * Close the underlying statement.
+ */
+ public void close() {
+ try {
+ if (dataBind != null) {
+ dataBind.close();
+ }
+ } catch (SQLException ex) {
+ logger.error(null, ex);
}
-
- /**
- * Bind the value to the preparedStatement without logging.
- */
- public Object bindNoLog(Object value, BeanProperty prop, String propName, boolean bindNull) throws SQLException {
- return bindInternal(false, value, prop, propName, bindNull);
+ }
+
+ /**
+ * Return the bind log.
+ */
+ public String getBindLog() {
+ return bindLog == null ? "" : bindLog.toString();
+ }
+
+ /**
+ * Set the Id value that was bound. This value is used for logging summary
+ * level information.
+ */
+ public void setIdValue(Object idValue) {
+ persistRequest.setBoundId(idValue);
+ }
+
+ /**
+ * Log the sql to the transaction log.
+ */
+ protected void logSql(String sql) {
+ if (logLevelSql) {
+ if (TransactionManager.SQL_LOGGER.isTraceEnabled()) {
+ sql += "; --bind(" + bindLog + ")";
+ }
+ transaction.logSql(sql);
}
-
- private Object bindInternal(boolean log, Object value, BeanProperty prop, String propName, boolean bindNull) throws SQLException {
-
- if (!bindNull){
- if (emptyStringToNull && (value instanceof String) && ((String)value).length() == 0){
- // support Oracle conversion of empty string to null
- //value = prop.getDbNullValue(value);
- value = null;
- }
- }
+ }
- if (!bindNull && value == null) {
- // where will have IS NULL clause so don't actually bind
- if (log) {
- bindLog.append(propName).append("=");
- bindLog.append("null, ");
- }
- } else {
- if (log) {
- bindLog.append(propName).append("=");
- if (prop.isLob()){
- bindLog.append("[LOB]");
- } else {
- String sv = String.valueOf(value);
- if (sv.length() > 50){
- sv = sv.substring(0,47)+"...";
- }
- bindLog.append(sv);
- }
- bindLog.append(", ");
- }
- // do the actual binding to PreparedStatement
- prop.bind(dataBind, value);
-// if (checkDelta) {
-// if (!prop.isId() && prop.isDeltaRequired()){
-// if (deltaBean == null){
-// deltaBean = persistRequest.createDeltaBean();
-// transaction.getEvent().addBeanDelta(deltaBean);
-// }
-// deltaBean.add(prop, value);
-// }
-// }
- }
- return value;
- }
-
- /**
- * Add the comment to the bind information log.
- */
- protected void bindLogAppend(String comment) {
- if (logLevelSql) {
- bindLog.append(comment);
- }
- }
+ public boolean isIncluded(BeanProperty prop) {
+ return (loadedProps == null || loadedProps.contains(prop.getName()));
+ }
- /**
- * For generated properties set on insert register as additional
- * loaded properties if required.
- */
- public final void registerAdditionalProperty(String propertyName) {
- if (loadedProps != null && !loadedProps.contains(propertyName)){
- if (additionalProps == null){
- additionalProps = new HashSet();
- }
- additionalProps.add(propertyName);
- }
+ public boolean isIncludedWhere(BeanProperty prop) {
+ if (prop.isDbEncrypted()) {
+ // update without a version property ...
+ // for encrypted properties only include if it was
+ // also an updated/modified property
+ return isIncluded(prop);
}
+ return prop.isDbUpdatable() && (loadedProps == null || loadedProps.contains(prop.getName()));
+ }
- /**
- * Set any additional (generated) properties to the set of loaded properties
- * if required.
- */
- protected void setAdditionalProperties() {
- if (additionalProps != null){
- // additional generated properties set on insert
- // added to the set of loaded properties
- additionalProps.addAll(loadedProps);
- persistRequest.setLoadedProps(additionalProps);
- }
- }
-
- /**
- * Register a generated value on a update. This can not be set to the bean
- * until after the where clause has been bound for concurrency checking.
- *
- * GeneratedProperty values are likely going to be used for optimistic
- * concurrency checking. This includes 'counter' and 'update timestamp'
- * generation.
- *
- */
- public void registerUpdateGenValue(BeanProperty prop, Object bean, Object value) {
- if (updateGenValues == null) {
- updateGenValues = new ArrayList();
- }
- updateGenValues.add(new UpdateGenValue(prop, bean, value));
- registerAdditionalProperty(prop.getName());
- }
-
-
-
- /**
- * Set any update generated values to the bean. Must be called after where
- * clause has been bound.
- */
- public void setUpdateGenValues() {
- if (updateGenValues != null) {
- for (int i = 0; i < updateGenValues.size(); i++) {
- UpdateGenValue updGenVal = updateGenValues.get(i);
- updGenVal.setValue();
- }
- }
- }
-
-
- /**
- * Check with useGeneratedKeys to get appropriate PreparedStatement.
- */
- protected PreparedStatement getPstmt(SpiTransaction t, String sql, boolean genKeys) throws SQLException {
- Connection conn = t.getInternalConnection();
- if (genKeys) {
- // the Id generated is always the first column
- // Required to stop Oracle10 giving us Oracle rowId??
- // Other jdbc drivers seem fine without this hint.
- int[] columns = {1};
- return conn.prepareStatement(sql, columns);
-
+ /**
+ * Bind a raw value. Used to bind the discriminator column.
+ */
+ public Object bind(String propName, Object value, int sqlType) throws SQLException {
+ if (logLevelSql) {
+ if (value == null) {
+ bindLog.append("null");
+ } else {
+ String sval = value.toString();
+ if (sval.length() > 50) {
+ bindLog.append(sval.substring(0, 47)).append("...");
} else {
- return conn.prepareStatement(sql);
+ bindLog.append(sval);
}
- }
+ }
+ bindLog.append(",");
+ }
+ dataBind.setObject(value, sqlType);
+ return value;
+ }
- /**
- * Return a prepared statement taking into account batch requirements.
- */
- protected PreparedStatement getPstmt(SpiTransaction t, String sql, PersistRequestBean> request, boolean genKeys)
- throws SQLException {
+ public Object bindNoLog(Object value, int sqlType, String logPlaceHolder) throws SQLException {
+ if (logLevelSql) {
+ bindLog.append(logPlaceHolder).append(" ");
+ }
+ dataBind.setObject(value, sqlType);
+ return value;
+ }
- BatchedPstmtHolder batch = t.getBatchControl().getPstmtHolder();
- PreparedStatement stmt = batch.getStmt(sql, request);
+ /**
+ * Bind the value to the preparedStatement.
+ */
+ public Object bind(Object value, BeanProperty prop, String propName, boolean bindNull)
+ throws SQLException {
+ return bindInternal(logLevelSql, value, prop, propName, bindNull);
+ }
- if (stmt != null) {
- return stmt;
- }
+ /**
+ * Bind the value to the preparedStatement without logging.
+ */
+ public Object bindNoLog(Object value, BeanProperty prop, String propName, boolean bindNull)
+ throws SQLException {
+ return bindInternal(false, value, prop, propName, bindNull);
+ }
- if (logLevelSql){
- t.logInternal(sql);
- }
-
- stmt = getPstmt(t, sql, genKeys);
+ private Object bindInternal(boolean log, Object value, BeanProperty prop, String propName,
+ boolean bindNull) throws SQLException {
- PstmtBatch pstmtBatch = request.getPstmtBatch();
- if (pstmtBatch != null){
- pstmtBatch.setBatchSize(stmt, t.getBatchControl().getBatchSize());
+ if (!bindNull) {
+ if (emptyStringToNull && (value instanceof String) && ((String) value).length() == 0) {
+ // support Oracle conversion of empty string to null
+ // value = prop.getDbNullValue(value);
+ value = null;
+ }
+ }
+
+ if (!bindNull && value == null) {
+ // where will have IS NULL clause so don't actually bind
+ if (log) {
+ bindLog.append("null, ");
+ }
+ } else {
+ if (log) {
+ if (prop.isLob()) {
+ bindLog.append("[LOB]");
+ } else {
+ String sv = String.valueOf(value);
+ if (sv.length() > 50) {
+ sv = sv.substring(0, 47) + "...";
+ }
+ bindLog.append(sv);
}
-
- BatchedPstmt bs = new BatchedPstmt(stmt, genKeys, sql, request.getPstmtBatch(), true);
- batch.addStmt(bs, request);
- return stmt;
- }
-
- /**
- * Hold the values from GeneratedValue that need to be set to the bean
- * property after the where clause has been built.
- */
- private static final class UpdateGenValue {
+ bindLog.append(",");
+ }
+ // do the actual binding to PreparedStatement
+ prop.bind(dataBind, value);
+ }
+ return value;
+ }
- private final BeanProperty property;
+ /**
+ * For generated properties set on insert register as additional loaded
+ * properties if required.
+ */
+ public final void registerAdditionalProperty(String propertyName) {
+ if (loadedProps != null && !loadedProps.contains(propertyName)) {
+ if (additionalProps == null) {
+ additionalProps = new HashSet();
+ }
+ additionalProps.add(propertyName);
+ }
+ }
- private final Object bean;
+ /**
+ * Set any additional (generated) properties to the set of loaded properties
+ * if required.
+ */
+ protected void setAdditionalProperties() {
+ if (additionalProps != null) {
+ // additional generated properties set on insert
+ // added to the set of loaded properties
+ additionalProps.addAll(loadedProps);
+ persistRequest.setLoadedProps(additionalProps);
+ }
+ }
- private final Object value;
+ /**
+ * Register a generated value on a update. This can not be set to the bean
+ * until after the where clause has been bound for concurrency checking.
+ *
+ * GeneratedProperty values are likely going to be used for optimistic
+ * concurrency checking. This includes 'counter' and 'update timestamp'
+ * generation.
+ *
+ */
+ public void registerUpdateGenValue(BeanProperty prop, Object bean, Object value) {
+ if (updateGenValues == null) {
+ updateGenValues = new ArrayList();
+ }
+ updateGenValues.add(new UpdateGenValue(prop, bean, value));
+ registerAdditionalProperty(prop.getName());
+ }
- private UpdateGenValue(BeanProperty property, Object bean, Object value) {
- this.property = property;
- this.bean = bean;
- this.value = value;
- }
+ /**
+ * Set any update generated values to the bean. Must be called after where
+ * clause has been bound.
+ */
+ public void setUpdateGenValues() {
+ if (updateGenValues != null) {
+ for (int i = 0; i < updateGenValues.size(); i++) {
+ UpdateGenValue updGenVal = updateGenValues.get(i);
+ updGenVal.setValue();
+ }
+ }
+ }
- /**
- * Set the value to the bean property.
- */
- private void setValue() {
- // support PropertyChangeSupport
- property.setValueIntercept(bean, value);
- }
- }
+ /**
+ * Check with useGeneratedKeys to get appropriate PreparedStatement.
+ */
+ protected PreparedStatement getPstmt(SpiTransaction t, String sql, boolean genKeys)
+ throws SQLException {
+ Connection conn = t.getInternalConnection();
+ if (genKeys) {
+ // the Id generated is always the first column
+ // Required to stop Oracle10 giving us Oracle rowId??
+ // Other jdbc drivers seem fine without this hint.
+ int[] columns = { 1 };
+ return conn.prepareStatement(sql, columns);
+
+ } else {
+ return conn.prepareStatement(sql);
+ }
+ }
+
+ /**
+ * Return a prepared statement taking into account batch requirements.
+ */
+ protected PreparedStatement getPstmt(SpiTransaction t, String sql, PersistRequestBean> request,
+ boolean genKeys) throws SQLException {
+
+ BatchedPstmtHolder batch = t.getBatchControl().getPstmtHolder();
+ PreparedStatement stmt = batch.getStmt(sql, request);
+
+ if (stmt != null) {
+ return stmt;
+ }
+
+ if (logLevelSql) {
+ t.logSql(sql);
+ }
+
+ stmt = getPstmt(t, sql, genKeys);
+
+ PstmtBatch pstmtBatch = request.getPstmtBatch();
+ if (pstmtBatch != null) {
+ pstmtBatch.setBatchSize(stmt, t.getBatchControl().getBatchSize());
+ }
+
+ BatchedPstmt bs = new BatchedPstmt(stmt, genKeys, sql, request.getPstmtBatch(), true);
+ batch.addStmt(bs, request);
+ return stmt;
+ }
+
+ /**
+ * Hold the values from GeneratedValue that need to be set to the bean
+ * property after the where clause has been built.
+ */
+ private static final class UpdateGenValue {
+
+ private final BeanProperty property;
+
+ private final Object bean;
+
+ private final Object value;
+
+ private UpdateGenValue(BeanProperty property, Object bean, Object value) {
+ this.property = property;
+ this.bean = bean;
+ this.value = value;
+ }
+
+ /**
+ * Set the value to the bean property.
+ */
+ private void setValue() {
+ // support PropertyChangeSupport
+ property.setValueIntercept(bean, value);
+ }
+ }
}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/persist/dml/InsertHandler.java b/src/main/java/com/avaje/ebeaninternal/server/persist/dml/InsertHandler.java
index 07f231c75..d83af7013 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/persist/dml/InsertHandler.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/persist/dml/InsertHandler.java
@@ -101,22 +101,15 @@ public class InsertHandler extends DmlHandler {
PreparedStatement pstmt;
if (isBatch) {
pstmt = getPstmt(t, sql, persistRequest, useGeneratedKeys);
-
} else {
- logSql(sql);
pstmt = getPstmt(t, sql, useGeneratedKeys);
}
dataBind = new DataBind(pstmt);
- bindLogAppend("Binding Insert [");
- bindLogAppend(desc.getBaseTable());
- bindLogAppend("] set[");
-
// bind the bean property values
meta.bind(this, bean, withId);
- bindLogAppend("]");
- logBinding();
+ logSql(sql);
}
/**
diff --git a/src/main/java/com/avaje/ebeaninternal/server/persist/dml/UpdateHandler.java b/src/main/java/com/avaje/ebeaninternal/server/persist/dml/UpdateHandler.java
index 6b42f6200..78e57bf41 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/persist/dml/UpdateHandler.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/persist/dml/UpdateHandler.java
@@ -52,23 +52,16 @@ public class UpdateHandler extends DmlHandler {
PreparedStatement pstmt;
if (isBatch) {
pstmt = getPstmt(t, sql, persistRequest, false);
-
} else {
- logSql(sql);
pstmt = getPstmt(t, sql, false);
}
dataBind = new DataBind(pstmt);
-
- bindLogAppend("Binding Update [");
- bindLogAppend(meta.getTableName());
- bindLogAppend("] ");
meta.bind(persistRequest, this, updatePlan);
setUpdateGenValues();
- bindLogAppend("]");
- logBinding();
+ logSql(sql);
}
@Override
diff --git a/src/main/java/com/avaje/ebeaninternal/server/persist/dml/UpdateMeta.java b/src/main/java/com/avaje/ebeaninternal/server/persist/dml/UpdateMeta.java
index ecc7b4056..56782351a 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/persist/dml/UpdateMeta.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/persist/dml/UpdateMeta.java
@@ -74,12 +74,8 @@ public final class UpdateMeta {
Object bean = persist.getBean();
- bind.bindLogAppend(" set[");
- // bind.setCheckDelta(true);
updatePlan.bindSet(bind, bean);
- // bind.setCheckDelta(false);
- bind.bindLogAppend("] where[");
id.dmlBind(bind, false, bean);
switch (persist.getConcurrencyMode()) {
diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/CQuery.java b/src/main/java/com/avaje/ebeaninternal/server/query/CQuery.java
index c82acd7ad..de9e1b1d7 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/query/CQuery.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/query/CQuery.java
@@ -56,805 +56,786 @@ import org.slf4j.LoggerFactory;
*/
public class CQuery implements DbReadContext, CancelableQuery {
- private static final Logger logger = LoggerFactory.getLogger(CQuery.class);
+ private static final Logger logger = LoggerFactory.getLogger(CQuery.class);
- private static final int GLOBAL_ROW_LIMIT = 1000000;
+ private static final int GLOBAL_ROW_LIMIT = 1000000;
- /**
- * The resultSet rows read.
- */
- private int rowCount;
+ /**
+ * The resultSet rows read.
+ */
+ private int rowCount;
- /**
- * The number of master EntityBeans loaded.
- */
- private int loadedBeanCount;
+ /**
+ * The number of master EntityBeans loaded.
+ */
+ private int loadedBeanCount;
- /**
- * Flag set when no more rows are in the resultSet.
- */
- private boolean noMoreRows;
- /**
- * Id of loaded 'master' bean.
- */
- private Object loadedBeanId;
- /**
- * Flag set when 'master' bean changed.
- */
- boolean loadedBeanChanged;
- /**
- * The 'master' bean just loaded.
- */
- private Object loadedBean;
+ /**
+ * Flag set when no more rows are in the resultSet.
+ */
+ private boolean noMoreRows;
+ /**
+ * Id of loaded 'master' bean.
+ */
+ private Object loadedBeanId;
+ /**
+ * Flag set when 'master' bean changed.
+ */
+ boolean loadedBeanChanged;
+ /**
+ * The 'master' bean just loaded.
+ */
+ private Object loadedBean;
- /**
- * Holds the previous loaded bean.
- */
- private Object prevLoadedBean;
+ /**
+ * Holds the previous loaded bean.
+ */
+ private Object prevLoadedBean;
- /**
- * The detail bean just loaded.
- */
- private Object loadedManyBean;
+ /**
+ * The detail bean just loaded.
+ */
+ private Object loadedManyBean;
- /**
- * The previous 'detail' collection remembered so that for manyToMany we can
- * turn on the modify listening.
- */
- private Object prevDetailCollection;
+ /**
+ * The previous 'detail' collection remembered so that for manyToMany we can
+ * turn on the modify listening.
+ */
+ private Object prevDetailCollection;
- /**
- * The current 'detail' collection being populated.
- */
- private Object currentDetailCollection;
+ /**
+ * The current 'detail' collection being populated.
+ */
+ private Object currentDetailCollection;
- /**
- * The 'master' collection being populated.
- */
- private final BeanCollection collection;
- /**
- * The help for the 'master' collection.
- */
- private final BeanCollectionHelp help;
+ /**
+ * The 'master' collection being populated.
+ */
+ private final BeanCollection collection;
+ /**
+ * The help for the 'master' collection.
+ */
+ private final BeanCollectionHelp help;
- /**
- * The overall find request wrapper object.
- */
- private final OrmQueryRequest request;
+ /**
+ * The overall find request wrapper object.
+ */
+ private final OrmQueryRequest request;
- private final BeanDescriptor desc;
+ private final BeanDescriptor desc;
- private final SpiQuery query;
-
- private final QueryListener queryListener;
-
- private Map currentPathMap;
+ private final SpiQuery query;
- private String currentPrefix;
-
- /**
- * Flag set true when reading 'master' and 'detail' beans.
- */
- private final boolean manyIncluded;
+ private final QueryListener queryListener;
- /**
- * Where clause predicates.
- */
- private final CQueryPredicates predicates;
+ private Map currentPathMap;
- /**
- * Object handling the SELECT generation and reading.
- */
- private final SqlTree sqlTree;
+ private String currentPrefix;
- private final boolean rawSql;
+ /**
+ * Flag set true when reading 'master' and 'detail' beans.
+ */
+ private final boolean manyIncluded;
- /**
- * The final sql that is generated.
- */
- private final String sql;
+ /**
+ * Where clause predicates.
+ */
+ private final CQueryPredicates predicates;
- /**
- * Where clause to show in logs when using an existing query plan.
- */
- private final String logWhereSql;
+ /**
+ * Object handling the SELECT generation and reading.
+ */
+ private final SqlTree sqlTree;
- /**
- * Set to true if the row number column is included in the sql.
- */
- private final boolean rowNumberIncluded;
+ private final boolean rawSql;
- /**
- * Tree that knows how to build the master and detail beans from the
- * resultSet.
- */
- private final SqlTreeNode rootNode;
+ /**
+ * The final sql that is generated.
+ */
+ private final String sql;
- /**
- * For master detail query.
- */
- private final BeanPropertyAssocMany> manyProperty;
+ /**
+ * Where clause to show in logs when using an existing query plan.
+ */
+ private final String logWhereSql;
- /**
- * The many property Expression language object.
- */
- private final ElPropertyValue manyPropertyEl;
-
- private final int backgroundFetchAfter;
+ /**
+ * Set to true if the row number column is included in the sql.
+ */
+ private final boolean rowNumberIncluded;
- private final int maxRowsLimit;
+ /**
+ * Tree that knows how to build the master and detail beans from the
+ * resultSet.
+ */
+ private final SqlTreeNode rootNode;
- /**
- * Flag set when backgroundFetchAfter limit is hit.
- */
- private boolean hasHitBackgroundFetchAfter;
+ /**
+ * For master detail query.
+ */
+ private final BeanPropertyAssocMany> manyProperty;
- private final PersistenceContext persistenceContext;
+ /**
+ * The many property Expression language object.
+ */
+ private final ElPropertyValue manyPropertyEl;
- private DataReader dataReader;
+ private final int backgroundFetchAfter;
- /**
- * The statement used to create the resultSet.
- */
- private PreparedStatement pstmt;
+ private final int maxRowsLimit;
- private boolean cancelled;
-
- private String bindLog;
+ /**
+ * Flag set when backgroundFetchAfter limit is hit.
+ */
+ private boolean hasHitBackgroundFetchAfter;
- private final CQueryPlan queryPlan;
+ private final PersistenceContext persistenceContext;
- private long startNano;
-
- private final Mode queryMode;
-
- private final boolean autoFetchProfiling;
-
- private final ObjectGraphNode autoFetchParentNode;
-
- private final AutoFetchManager autoFetchManager;
- private final WeakReference autoFetchManagerRef;
-
- private int executionTimeMicros;
-
- private final Boolean readOnly;
-
- private final SpiExpressionList> filterMany;
-
- /**
- * Create the Sql select based on the request.
- */
- @SuppressWarnings("unchecked")
- public CQuery(OrmQueryRequest request, CQueryPredicates predicates, CQueryPlan queryPlan) {
- this.request = request;
- this.queryPlan = queryPlan;
- this.query = request.getQuery();
- this.queryMode = query.getMode();
-
- this.readOnly = request.isReadOnly();
-
- this.autoFetchManager = query.getAutoFetchManager();
- this.autoFetchProfiling = autoFetchManager != null;
- this.autoFetchParentNode = autoFetchProfiling ? query.getParentNode() : null;
- this.autoFetchManagerRef = autoFetchProfiling ? new WeakReference(autoFetchManager) : null;
-
- // set the generated sql back to the query
- // so its available to the user...
- query.setGeneratedSql(queryPlan.getSql());
+ private DataReader dataReader;
- this.sqlTree = queryPlan.getSqlTree();
- this.rootNode = sqlTree.getRootNode();
-
- this.manyProperty = sqlTree.getManyProperty();
- this.manyPropertyEl = sqlTree.getManyPropertyEl();
- this.manyIncluded = sqlTree.isManyIncluded();
- if (manyIncluded) {
- // get filter to put on the collection for reuse with refresh
- String manyPropertyName = sqlTree.getManyPropertyName();
- OrmQueryProperties chunk = query.getDetail().getChunk(manyPropertyName, false);
- this.filterMany = chunk.getFilterMany();
- } else {
- this.filterMany = null;
- }
+ /**
+ * The statement used to create the resultSet.
+ */
+ private PreparedStatement pstmt;
- this.sql = queryPlan.getSql();
- this.rawSql = queryPlan.isRawSql();
- this.rowNumberIncluded = queryPlan.isRowNumberIncluded();
- this.logWhereSql = queryPlan.getLogWhereSql();
- this.desc = request.getBeanDescriptor();
- this.predicates = predicates;
+ private boolean cancelled;
- this.queryListener = query.getListener();
- if (queryListener == null) {
- // normal, use the one from the transaction
- this.persistenceContext = request.getPersistenceContext();
- } else {
- // 'Row Level Transaction Context'...
- // local transaction context that will be reset
- // after each 'master' bean is sent to the listener
- this.persistenceContext = new DefaultPersistenceContext();
- }
+ private String bindLog;
- this.maxRowsLimit = query.getMaxRows() > 0 ? query.getMaxRows() : GLOBAL_ROW_LIMIT;
- this.backgroundFetchAfter = query.getBackgroundFetchAfter() > 0 ? query.getBackgroundFetchAfter() : Integer.MAX_VALUE;
+ private final CQueryPlan queryPlan;
- this.help = createHelp(request);
- this.collection = (BeanCollection)(help != null ? help.createEmpty(false) : null);
- }
+ private long startNano;
- private BeanCollectionHelp createHelp(OrmQueryRequest request) {
- if (request.isFindById()) {
- return null;
- } else {
- SpiQuery.Type manyType = request.getQuery().getType();
- if (manyType == null){
- // subQuery compiled for InQueryExpression
- return null;
- }
- return BeanCollectionHelpFactory.create(request);
- }
- }
-
- public Boolean isReadOnly() {
- return readOnly;
+ private final Mode queryMode;
+
+ private final boolean autoFetchProfiling;
+
+ private final ObjectGraphNode autoFetchParentNode;
+
+ private final AutoFetchManager autoFetchManager;
+ private final WeakReference autoFetchManagerRef;
+
+ private int executionTimeMicros;
+
+ private final Boolean readOnly;
+
+ private final SpiExpressionList> filterMany;
+
+ /**
+ * Create the Sql select based on the request.
+ */
+ @SuppressWarnings("unchecked")
+ public CQuery(OrmQueryRequest request, CQueryPredicates predicates, CQueryPlan queryPlan) {
+ this.request = request;
+ this.queryPlan = queryPlan;
+ this.query = request.getQuery();
+ this.queryMode = query.getMode();
+
+ this.readOnly = request.isReadOnly();
+
+ this.autoFetchManager = query.getAutoFetchManager();
+ this.autoFetchProfiling = autoFetchManager != null;
+ this.autoFetchParentNode = autoFetchProfiling ? query.getParentNode() : null;
+ this.autoFetchManagerRef = autoFetchProfiling ? new WeakReference(
+ autoFetchManager) : null;
+
+ // set the generated sql back to the query
+ // so its available to the user...
+ query.setGeneratedSql(queryPlan.getSql());
+
+ this.sqlTree = queryPlan.getSqlTree();
+ this.rootNode = sqlTree.getRootNode();
+
+ this.manyProperty = sqlTree.getManyProperty();
+ this.manyPropertyEl = sqlTree.getManyPropertyEl();
+ this.manyIncluded = sqlTree.isManyIncluded();
+ if (manyIncluded) {
+ // get filter to put on the collection for reuse with refresh
+ String manyPropertyName = sqlTree.getManyPropertyName();
+ OrmQueryProperties chunk = query.getDetail().getChunk(manyPropertyName, false);
+ this.filterMany = chunk.getFilterMany();
+ } else {
+ this.filterMany = null;
}
- public void propagateState(Object e) {
- if (Boolean.TRUE.equals(readOnly)){
- if (e instanceof EntityBean){
- ((EntityBean)e)._ebean_getIntercept().setReadOnly(true);
- }
- }
- }
-
- public DataReader getDataReader() {
- return dataReader;
+ this.sql = queryPlan.getSql();
+ this.rawSql = queryPlan.isRawSql();
+ this.rowNumberIncluded = queryPlan.isRowNumberIncluded();
+ this.logWhereSql = queryPlan.getLogWhereSql();
+ this.desc = request.getBeanDescriptor();
+ this.predicates = predicates;
+
+ this.queryListener = query.getListener();
+ if (queryListener == null) {
+ // normal, use the one from the transaction
+ this.persistenceContext = request.getPersistenceContext();
+ } else {
+ // 'Row Level Transaction Context'...
+ // local transaction context that will be reset
+ // after each 'master' bean is sent to the listener
+ this.persistenceContext = new DefaultPersistenceContext();
}
- public Mode getQueryMode() {
- return queryMode;
- }
+ this.maxRowsLimit = query.getMaxRows() > 0 ? query.getMaxRows() : GLOBAL_ROW_LIMIT;
+ this.backgroundFetchAfter = query.getBackgroundFetchAfter() > 0 ? query
+ .getBackgroundFetchAfter() : Integer.MAX_VALUE;
- /**
- * Return true if we want to return vanilla (not enhanced) objects.
- */
- public boolean isVanillaMode() {
- return request.isVanillaMode();
+ this.help = createHelp(request);
+ this.collection = (BeanCollection) (help != null ? help.createEmpty(false) : null);
+ }
+
+ private BeanCollectionHelp createHelp(OrmQueryRequest request) {
+ if (request.isFindById()) {
+ return null;
+ } else {
+ SpiQuery.Type manyType = request.getQuery().getType();
+ if (manyType == null) {
+ // subQuery compiled for InQueryExpression
+ return null;
+ }
+ return BeanCollectionHelpFactory.create(request);
}
+ }
- public CQueryPredicates getPredicates() {
- return predicates;
- }
-
- public LoadContext getGraphContext() {
- return request.getGraphContext();
- }
+ public Boolean isReadOnly() {
+ return readOnly;
+ }
- public SpiOrmQueryRequest> getQueryRequest() {
- return request;
- }
-
- public void cancel() {
- synchronized (this) {
- this.cancelled = true;
- if (pstmt != null){
- try {
- pstmt.cancel();
- } catch (SQLException e){
- String msg = "Error cancelling query";
- throw new PersistenceException(msg, e);
- }
- }
- }
- }
-
- public boolean prepareBindExecuteQuery() throws SQLException {
-
- synchronized (this) {
- if (cancelled || query.isCancelled()){
- // cancelled before we started
- cancelled = true;
- return false;
- }
-
- startNano = System.nanoTime();
-
- // prepare
- SpiTransaction t = request.getTransaction();
- Connection conn = t.getInternalConnection();
- pstmt = conn.prepareStatement(sql);
-
- if (query.getTimeout() > 0){
- pstmt.setQueryTimeout(query.getTimeout());
- }
- if (query.getBufferFetchSizeHint() > 0){
- pstmt.setFetchSize(query.getBufferFetchSizeHint());
- }
-
- DataBind dataBind = new DataBind(pstmt);
-
- // bind keys for encrypted properties
- queryPlan.bindEncryptedProperties(dataBind);
-
- bindLog = predicates.bind(dataBind);
-
- // executeQuery
- ResultSet rset = pstmt.executeQuery();
- dataReader = queryPlan.createDataReader(rset);
-
- return true;
- }
- }
-
- /**
- * Close the resources.
- *
- * The jdbc resultSet and statement need to be closed. Its important that
- * this method is called.
- *
- */
- public void close() {
- try {
- if (dataReader != null) {
- dataReader.close();
- dataReader = null;
- }
- } catch (SQLException e) {
- logger.error(null, e);
- }
- try {
- if (pstmt != null) {
- pstmt.close();
- pstmt = null;
- }
- } catch (SQLException e) {
- logger.error(null, e);
- }
- }
-
-// /**
-// * Return the reference options used to define cache use.
-// */
-// public ReferenceOptions getReferenceOptionsFor(BeanPropertyAssocOne> beanProp) {
-//
-// String beanPropName = beanProp.getName();
-// if (currentPrefix != null){
-// beanPropName = currentPrefix+"."+beanPropName;
-// }
-// //ReferenceOptions opt = referenceOptionsMap.get(beanPropName);
-// if (opt == null){
-// OrmQueryProperties chunk = queryDetail.getChunk(beanPropName, false);
-// if (chunk != null) {
-// // get the options from the query
-// opt = chunk.getReferenceOptions();
-// }
-// if (opt == null){
-// // get the default options defined for the target bean type
-// opt = beanProp.getTargetDescriptor().getReferenceOptions();
-// }
-// referenceOptionsMap.put(beanPropName, opt);
-// }
-//
-// return opt;
-// }
-
- /**
- * Return the persistence context.
- */
- public PersistenceContext getPersistenceContext(){
- return persistenceContext;
- }
-
- public void setLoadedBean(Object bean, Object id) {
- if (id != null && id.equals(loadedBeanId)) {
- // master/detail loading with master bean
- // unchanged. NB Using id to avoid any issue
- // with equals not being implemented
-
- } else {
- if (manyIncluded) {
- if (rowCount > 1) {
- loadedBeanChanged = true;
- }
- this.prevLoadedBean = loadedBean;
- this.loadedBeanId = id;
- }
- this.loadedBean = bean;
- }
- }
-
- public void setLoadedManyBean(Object manyValue) {
- this.loadedManyBean = manyValue;
- }
-
- /**
- * Return the last read bean.
- */
- @SuppressWarnings("unchecked")
- public T getLoadedBean() {
- if (manyIncluded) {
- if (prevDetailCollection instanceof BeanCollection>) {
- ((BeanCollection>)prevDetailCollection).setModifyListening(manyProperty.getModifyListenMode());
-
- } else if (currentDetailCollection instanceof BeanCollection>) {
- ((BeanCollection>)currentDetailCollection).setModifyListening(manyProperty.getModifyListenMode());
- }
- }
-
- if (prevLoadedBean != null) {
- return (T)prevLoadedBean;
- } else {
- return (T)loadedBean;
- }
- }
-
- private boolean hasMoreRows() throws SQLException {
- synchronized (this) {
- if (cancelled){
- return false;
- }
- return dataReader.next();
- }
+ public void propagateState(Object e) {
+ if (Boolean.TRUE.equals(readOnly)) {
+ if (e instanceof EntityBean) {
+ ((EntityBean) e)._ebean_getIntercept().setReadOnly(true);
+ }
}
-
- /**
- * Read a row from the result set returning a bean.
- *
- * If the query includes a many then the first object in the returned array
- * is the one/master and the second the many/detail.
- *
- */
- private boolean readRow() throws SQLException {
+ }
- synchronized (this) {
- if (cancelled){
- return false;
- }
-
- if (!dataReader.next()){
- return false;
- }
+ public DataReader getDataReader() {
+ return dataReader;
+ }
- rowCount++;
- dataReader.resetColumnPosition();
-
- if (rowNumberIncluded) {
- // row_number() column used for limit features
- dataReader.incrementPos(1);
- }
-
- rootNode.load(this, null);
-
- return true;
- }
- }
-
- public int getQueryExecutionTimeMicros(){
- return executionTimeMicros;
- }
-
- public boolean readBean() throws SQLException {
-
- boolean result = readBeanInternal(true);
+ public Mode getQueryMode() {
+ return queryMode;
+ }
- updateExecutionStatistics();
-
- return result;
- }
-
- private boolean readBeanInternal(boolean inForeground) throws SQLException {
-
- if (loadedBeanCount >= maxRowsLimit) {
- collection.setHasMoreRows(hasMoreRows());
- return false;
- }
-
- if (inForeground && loadedBeanCount >= backgroundFetchAfter) {
- hasHitBackgroundFetchAfter = true;
- collection.setFinishedFetch(false);
- return false;
- }
-
- if (!manyIncluded) {
- // simple query... no details...
- return readRow();
- }
+ /**
+ * Return true if we want to return vanilla (not enhanced) objects.
+ */
+ public boolean isVanillaMode() {
+ return request.isVanillaMode();
+ }
- if (noMoreRows) {
- return false;
- }
+ public CQueryPredicates getPredicates() {
+ return predicates;
+ }
- if (rowCount == 0) {
- if (!readRow()) {
- // no rows at all...
- return false;
- } else {
- createNewDetailCollection();
- }
- }
+ public LoadContext getGraphContext() {
+ return request.getGraphContext();
+ }
- if (readIntoCurrentDetailCollection()) {
- createNewDetailCollection();
- // return prevLoadedBean
- return true;
+ public SpiOrmQueryRequest> getQueryRequest() {
+ return request;
+ }
- } else {
- // return loadedBean
- prevDetailCollection = null;
- prevLoadedBean = null;
- noMoreRows = true;
- return true;
- }
- }
-
- private boolean readIntoCurrentDetailCollection() throws SQLException {
- while (readRow()) {
- if (loadedBeanChanged) {
- loadedBeanChanged = false;
- return true;
- } else {
- addToCurrentDetailCollection();
- }
- }
- return false;
- }
-
- private BeanCollectionAdd currentDetailAdd;
-
- private void createNewDetailCollection() {
- prevDetailCollection = currentDetailCollection;
- if (queryMode.equals(Mode.LAZYLOAD_MANY)){
- // just populate the current collection
- currentDetailCollection = manyPropertyEl.elGetValue(loadedBean);
- } else {
- // create a new collection to populate and assign to the bean
- currentDetailCollection = manyProperty.createEmpty(request.isVanillaMode());
- manyPropertyEl.elSetValue(loadedBean, currentDetailCollection, false, false);
- }
-
- if (filterMany != null && !request.isVanillaMode()){
- // remember the for use with a refresh
- ((BeanCollection>)currentDetailCollection).setFilterMany(filterMany);
- }
-
- // the manyKey is always null for this case, just using default mapKey on the property
- currentDetailAdd = manyProperty.getBeanCollectionAdd(currentDetailCollection, null);
- addToCurrentDetailCollection();
- }
-
- private void addToCurrentDetailCollection() {
- if (loadedManyBean != null) {
- currentDetailAdd.addBean(loadedManyBean);
- }
- }
-
- public BeanCollection continueFetchingInBackground() throws SQLException {
- readTheRows(false);
- collection.setFinishedFetch(true);
- return collection;
- }
-
- public BeanCollection readCollection() throws SQLException {
-
- readTheRows(true);
-
- updateExecutionStatistics();
-
- return collection;
- }
-
- protected void updateExecutionStatistics() {
+ public void cancel() {
+ synchronized (this) {
+ this.cancelled = true;
+ if (pstmt != null) {
try {
- long exeNano = System.nanoTime() - startNano;
- executionTimeMicros = (int)exeNano/1000;
-
- if (autoFetchProfiling){
- autoFetchManager.collectQueryInfo(autoFetchParentNode, loadedBeanCount, executionTimeMicros);
- }
- queryPlan.executionTime(loadedBeanCount, executionTimeMicros);
-
- } catch (Exception e){
- logger.error(null, e);
+ pstmt.cancel();
+ } catch (SQLException e) {
+ String msg = "Error cancelling query";
+ throw new PersistenceException(msg, e);
}
+ }
}
-
- public QueryIterator readIterate(int bufferSize, OrmQueryRequest request) {
-
- if (bufferSize > 0){
- return new CQueryIteratorWithBuffer(this, request, bufferSize);
-
- } else {
- return new CQueryIteratorSimple(this, request);
- }
- }
+ }
- private void readTheRows(boolean inForeground) throws SQLException {
- while (hasNextBean(inForeground)) {
- if (queryListener != null) {
- queryListener.process(getLoadedBean());
+ public boolean prepareBindExecuteQuery() throws SQLException {
- } else {
- // add to the list/set/map
- help.add(collection, getLoadedBean());
- }
+ synchronized (this) {
+ if (cancelled || query.isCancelled()) {
+ // cancelled before we started
+ cancelled = true;
+ return false;
+ }
+
+ startNano = System.nanoTime();
+
+ // prepare
+ SpiTransaction t = request.getTransaction();
+ Connection conn = t.getInternalConnection();
+ pstmt = conn.prepareStatement(sql);
+
+ if (query.getTimeout() > 0) {
+ pstmt.setQueryTimeout(query.getTimeout());
+ }
+ if (query.getBufferFetchSizeHint() > 0) {
+ pstmt.setFetchSize(query.getBufferFetchSizeHint());
+ }
+
+ DataBind dataBind = new DataBind(pstmt);
+
+ // bind keys for encrypted properties
+ queryPlan.bindEncryptedProperties(dataBind);
+
+ bindLog = predicates.bind(dataBind);
+
+ // executeQuery
+ ResultSet rset = pstmt.executeQuery();
+ dataReader = queryPlan.createDataReader(rset);
+
+ return true;
+ }
+ }
+
+ /**
+ * Close the resources.
+ *
+ * The jdbc resultSet and statement need to be closed. Its important that this
+ * method is called.
+ *
+ */
+ public void close() {
+ try {
+ if (dataReader != null) {
+ dataReader.close();
+ dataReader = null;
+ }
+ } catch (SQLException e) {
+ logger.error(null, e);
+ }
+ try {
+ if (pstmt != null) {
+ pstmt.close();
+ pstmt = null;
+ }
+ } catch (SQLException e) {
+ logger.error(null, e);
+ }
+ }
+
+ /**
+ * Return the persistence context.
+ */
+ public PersistenceContext getPersistenceContext() {
+ return persistenceContext;
+ }
+
+ public void setLoadedBean(Object bean, Object id) {
+ if (id != null && id.equals(loadedBeanId)) {
+ // master/detail loading with master bean
+ // unchanged. NB Using id to avoid any issue
+ // with equals not being implemented
+
+ } else {
+ if (manyIncluded) {
+ if (rowCount > 1) {
+ loadedBeanChanged = true;
}
- }
-
-
- protected boolean hasNextBean(boolean inForeground) throws SQLException {
-
- if (!readBeanInternal(inForeground)) {
- return false;
-
- } else {
- loadedBeanCount++;
- return true;
- }
- }
-
- public String getLoadedRowDetail() {
- if (!manyIncluded) {
- return String.valueOf(rowCount);
- } else {
- return loadedBeanCount + ":" + rowCount;
- }
- }
-
- public void register(String path, EntityBeanIntercept ebi){
-
- path = getPath(path);
- request.getGraphContext().register(path, ebi);
- }
-
- public void register(String path, BeanCollection> bc){
-
- path = getPath(path);
- request.getGraphContext().register(path, bc);
- }
-
-
- public boolean useBackgroundToContinueFetch() {
- return hasHitBackgroundFetchAfter;
- }
-
- /**
- * Return the query name.
- */
- public String getName() {
- return query.getName();
- }
-
- /**
- * Return true if this is a raw sql query as opposed to Ebean generated sql.
- */
- public boolean isRawSql() {
- return rawSql;
- }
-
- /**
- * Return the where predicate for display in the transaction log.
- */
- public String getLogWhereSql() {
- return logWhereSql;
- }
-
- /**
- * Return the property that is associated with the many. There can only be
- * one per SqlSelect. This can be null.
- */
- public BeanPropertyAssocMany> getManyProperty() {
- return manyProperty;
- }
-
- /**
- * Get the summary of the sql.
- */
- public String getSummary() {
- return sqlTree.getSummary();
- }
-
- /**
- * Return the SqlSelectChain. This is the flattened structure that
- * represents this query.
- */
- public SqlTree getSqlTree() {
- return sqlTree;
- }
-
- public String getBindLog() {
- return bindLog;
- }
-
- public SpiTransaction getTransaction() {
- return request.getTransaction();
- }
-
- public String getBeanType() {
- return desc.getFullName();
- }
-
- /**
- * Return the short bean name.
- */
- public String getBeanName() {
- return desc.getName();
+ this.prevLoadedBean = loadedBean;
+ this.loadedBeanId = id;
+ }
+ this.loadedBean = bean;
}
-
- /**
- * Return the generated sql.
- */
- public String getGeneratedSql() {
- return sql;
- }
-
- /**
- * Create a PersistenceException including interesting information like the bindLog and sql used.
- */
- public PersistenceException createPersistenceException(SQLException e) {
-
- return createPersistenceException(e, getTransaction(), bindLog, sql);
+ }
+
+ public void setLoadedManyBean(Object manyValue) {
+ this.loadedManyBean = manyValue;
+ }
+
+ /**
+ * Return the last read bean.
+ */
+ @SuppressWarnings("unchecked")
+ public T getLoadedBean() {
+ if (manyIncluded) {
+ if (prevDetailCollection instanceof BeanCollection>) {
+ ((BeanCollection>) prevDetailCollection).setModifyListening(manyProperty
+ .getModifyListenMode());
+
+ } else if (currentDetailCollection instanceof BeanCollection>) {
+ ((BeanCollection>) currentDetailCollection).setModifyListening(manyProperty
+ .getModifyListenMode());
+ }
}
-
- /**
- * Create a PersistenceException including interesting information like the bindLog and sql used.
- */
- public static PersistenceException createPersistenceException(SQLException e, SpiTransaction t, String bindLog, String sql) {
- if (t.isLogSummary()) {
- // log the error to the transaction log
- String errMsg = StringHelper.replaceStringMulti(e.getMessage(), new String[] { "\r", "\n" }, "\\n ");
- String msg = "ERROR executing query: bindLog[" + bindLog + "] error[" + errMsg + "]";
- t.logInternal(msg);
- }
-
- // ensure 'rollback' is logged if queryOnly transaction
- t.getConnection();
-
- // build a decent error message for the exception
- String m = Message.msg("fetch.sqlerror", e.getMessage(), bindLog, sql);
- return new PersistenceException(m, e);
+ if (prevLoadedBean != null) {
+ return (T) prevLoadedBean;
+ } else {
+ return (T) loadedBean;
}
-
- /**
- * Should we create profileNodes for beans created in this query.
- *
- * This is true for all queries except lazy load bean queries.
- *
- */
- public boolean isAutoFetchProfiling() {
- // need query.isProfiling() because we just take the data
- // from the lazy loaded or refreshed beans and put it into the already
- // existing beans which are already collecting usage information
- return autoFetchProfiling && query.isUsageProfiling();
- }
+ }
- private String getPath(String propertyName) {
-
- if (currentPrefix == null){
- return propertyName;
- } else if (propertyName == null) {
- return currentPrefix;
- }
-
- String path = currentPathMap.get(propertyName);
- if (path != null){
- return path;
- } else {
- return currentPrefix+"."+propertyName;
- }
- }
-
-
- public void profileBean(EntityBeanIntercept ebi, String prefix) {
-
- ObjectGraphNode node = request.getGraphContext().getObjectGraphNode(prefix);
-
- ebi.setNodeUsageCollector(new NodeUsageCollector(node, autoFetchManagerRef));
- }
+ private boolean hasMoreRows() throws SQLException {
+ synchronized (this) {
+ if (cancelled) {
+ return false;
+ }
+ return dataReader.next();
+ }
+ }
+
+ /**
+ * Read a row from the result set returning a bean.
+ *
+ * If the query includes a many then the first object in the returned array is
+ * the one/master and the second the many/detail.
+ *
+ */
+ private boolean readRow() throws SQLException {
+
+ synchronized (this) {
+ if (cancelled) {
+ return false;
+ }
+
+ if (!dataReader.next()) {
+ return false;
+ }
+
+ rowCount++;
+ dataReader.resetColumnPosition();
+
+ if (rowNumberIncluded) {
+ // row_number() column used for limit features
+ dataReader.incrementPos(1);
+ }
+
+ rootNode.load(this, null);
+
+ return true;
+ }
+ }
+
+ public int getQueryExecutionTimeMicros() {
+ return executionTimeMicros;
+ }
+
+ public boolean readBean() throws SQLException {
+
+ boolean result = readBeanInternal(true);
+
+ updateExecutionStatistics();
+
+ return result;
+ }
+
+ private boolean readBeanInternal(boolean inForeground) throws SQLException {
+
+ if (loadedBeanCount >= maxRowsLimit) {
+ collection.setHasMoreRows(hasMoreRows());
+ return false;
+ }
+
+ if (inForeground && loadedBeanCount >= backgroundFetchAfter) {
+ hasHitBackgroundFetchAfter = true;
+ collection.setFinishedFetch(false);
+ return false;
+ }
+
+ if (!manyIncluded) {
+ // simple query... no details...
+ return readRow();
+ }
+
+ if (noMoreRows) {
+ return false;
+ }
+
+ if (rowCount == 0) {
+ if (!readRow()) {
+ // no rows at all...
+ return false;
+ } else {
+ createNewDetailCollection();
+ }
+ }
+
+ if (readIntoCurrentDetailCollection()) {
+ createNewDetailCollection();
+ // return prevLoadedBean
+ return true;
+
+ } else {
+ // return loadedBean
+ prevDetailCollection = null;
+ prevLoadedBean = null;
+ noMoreRows = true;
+ return true;
+ }
+ }
+
+ private boolean readIntoCurrentDetailCollection() throws SQLException {
+ while (readRow()) {
+ if (loadedBeanChanged) {
+ loadedBeanChanged = false;
+ return true;
+ } else {
+ addToCurrentDetailCollection();
+ }
+ }
+ return false;
+ }
+
+ private BeanCollectionAdd currentDetailAdd;
+
+ private void createNewDetailCollection() {
+ prevDetailCollection = currentDetailCollection;
+ if (queryMode.equals(Mode.LAZYLOAD_MANY)) {
+ // just populate the current collection
+ currentDetailCollection = manyPropertyEl.elGetValue(loadedBean);
+ } else {
+ // create a new collection to populate and assign to the bean
+ currentDetailCollection = manyProperty.createEmpty(request.isVanillaMode());
+ manyPropertyEl.elSetValue(loadedBean, currentDetailCollection, false, false);
+ }
+
+ if (filterMany != null && !request.isVanillaMode()) {
+ // remember the for use with a refresh
+ ((BeanCollection>) currentDetailCollection).setFilterMany(filterMany);
+ }
+
+ // the manyKey is always null for this case, just using default mapKey on
+ // the property
+ currentDetailAdd = manyProperty.getBeanCollectionAdd(currentDetailCollection, null);
+ addToCurrentDetailCollection();
+ }
+
+ private void addToCurrentDetailCollection() {
+ if (loadedManyBean != null) {
+ currentDetailAdd.addBean(loadedManyBean);
+ }
+ }
+
+ public BeanCollection continueFetchingInBackground() throws SQLException {
+ readTheRows(false);
+ collection.setFinishedFetch(true);
+ return collection;
+ }
+
+ public BeanCollection readCollection() throws SQLException {
+
+ readTheRows(true);
+
+ updateExecutionStatistics();
+
+ return collection;
+ }
+
+ protected void updateExecutionStatistics() {
+ try {
+ long exeNano = System.nanoTime() - startNano;
+ executionTimeMicros = (int) exeNano / 1000;
+
+ if (autoFetchProfiling) {
+ autoFetchManager
+ .collectQueryInfo(autoFetchParentNode, loadedBeanCount, executionTimeMicros);
+ }
+ queryPlan.executionTime(loadedBeanCount, executionTimeMicros);
+
+ } catch (Exception e) {
+ logger.error(null, e);
+ }
+ }
+
+ public QueryIterator readIterate(int bufferSize, OrmQueryRequest request) {
+
+ if (bufferSize > 0) {
+ return new CQueryIteratorWithBuffer(this, request, bufferSize);
+
+ } else {
+ return new CQueryIteratorSimple(this, request);
+ }
+ }
+
+ private void readTheRows(boolean inForeground) throws SQLException {
+ while (hasNextBean(inForeground)) {
+ if (queryListener != null) {
+ queryListener.process(getLoadedBean());
+
+ } else {
+ // add to the list/set/map
+ help.add(collection, getLoadedBean());
+ }
+ }
+ }
+
+ protected boolean hasNextBean(boolean inForeground) throws SQLException {
+
+ if (!readBeanInternal(inForeground)) {
+ return false;
+
+ } else {
+ loadedBeanCount++;
+ return true;
+ }
+ }
+
+ public String getLoadedRowDetail() {
+ if (!manyIncluded) {
+ return String.valueOf(rowCount);
+ } else {
+ return loadedBeanCount + ":" + rowCount;
+ }
+ }
+
+ public void register(String path, EntityBeanIntercept ebi) {
+
+ path = getPath(path);
+ request.getGraphContext().register(path, ebi);
+ }
+
+ public void register(String path, BeanCollection> bc) {
+
+ path = getPath(path);
+ request.getGraphContext().register(path, bc);
+ }
+
+ public boolean useBackgroundToContinueFetch() {
+ return hasHitBackgroundFetchAfter;
+ }
+
+ /**
+ * Return the query name.
+ */
+ public String getName() {
+ return query.getName();
+ }
+
+ /**
+ * Return true if this is a raw sql query as opposed to Ebean generated sql.
+ */
+ public boolean isRawSql() {
+ return rawSql;
+ }
+
+ /**
+ * Return the where predicate for display in the transaction log.
+ */
+ public String getLogWhereSql() {
+ return logWhereSql;
+ }
+
+ /**
+ * Return the property that is associated with the many. There can only be one
+ * per SqlSelect. This can be null.
+ */
+ public BeanPropertyAssocMany> getManyProperty() {
+ return manyProperty;
+ }
+
+ /**
+ * Get the summary of the sql.
+ */
+ public String getSummary() {
+ return sqlTree.getSummary();
+ }
+
+ /**
+ * Return the SqlSelectChain. This is the flattened structure that represents
+ * this query.
+ */
+ public SqlTree getSqlTree() {
+ return sqlTree;
+ }
+
+ public String getBindLog() {
+ return bindLog;
+ }
+
+ public SpiTransaction getTransaction() {
+ return request.getTransaction();
+ }
+
+ public String getBeanType() {
+ return desc.getFullName();
+ }
+
+ /**
+ * Return the short bean name.
+ */
+ public String getBeanName() {
+ return desc.getName();
+ }
+
+ /**
+ * Return the generated sql.
+ */
+ public String getGeneratedSql() {
+ return sql;
+ }
+
+ /**
+ * Create a PersistenceException including interesting information like the
+ * bindLog and sql used.
+ */
+ public PersistenceException createPersistenceException(SQLException e) {
+
+ return createPersistenceException(e, getTransaction(), bindLog, sql);
+ }
+
+ /**
+ * Create a PersistenceException including interesting information like the
+ * bindLog and sql used.
+ */
+ public static PersistenceException createPersistenceException(SQLException e, SpiTransaction t,
+ String bindLog, String sql) {
+
+ if (t.isLogSummary()) {
+ // log the error to the transaction log
+ String errMsg = StringHelper.replaceStringMulti(e.getMessage(), new String[] { "\r", "\n" },
+ "\\n ");
+ String msg = "ERROR executing query: bindLog[" + bindLog + "] error[" + errMsg + "]";
+ t.logSummary(msg);
+ }
+
+ // ensure 'rollback' is logged if queryOnly transaction
+ t.getConnection();
+
+ // build a decent error message for the exception
+ String m = Message.msg("fetch.sqlerror", e.getMessage(), bindLog, sql);
+ return new PersistenceException(m, e);
+ }
+
+ /**
+ * Should we create profileNodes for beans created in this query.
+ *
+ * This is true for all queries except lazy load bean queries.
+ *
+ */
+ public boolean isAutoFetchProfiling() {
+ // need query.isProfiling() because we just take the data
+ // from the lazy loaded or refreshed beans and put it into the already
+ // existing beans which are already collecting usage information
+ return autoFetchProfiling && query.isUsageProfiling();
+ }
+
+ private String getPath(String propertyName) {
+
+ if (currentPrefix == null) {
+ return propertyName;
+ } else if (propertyName == null) {
+ return currentPrefix;
+ }
+
+ String path = currentPathMap.get(propertyName);
+ if (path != null) {
+ return path;
+ } else {
+ return currentPrefix + "." + propertyName;
+ }
+ }
+
+ public void profileBean(EntityBeanIntercept ebi, String prefix) {
+
+ ObjectGraphNode node = request.getGraphContext().getObjectGraphNode(prefix);
+
+ ebi.setNodeUsageCollector(new NodeUsageCollector(node, autoFetchManagerRef));
+ }
+
+ public void setCurrentPrefix(String currentPrefix, Map currentPathMap) {
+ this.currentPrefix = currentPrefix;
+ this.currentPathMap = currentPathMap;
+ }
- public void setCurrentPrefix(String currentPrefix, Map currentPathMap) {
- this.currentPrefix = currentPrefix;
- this.currentPathMap = currentPathMap;
- }
-
}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryBuilder.java b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryBuilder.java
index 265e40f70..c182cfc56 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryBuilder.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryBuilder.java
@@ -319,8 +319,7 @@ public class CQueryBuilder implements Constants {
sb.append(select.getSelectSql());
}
- sb.append(" ").append(NEW_LINE);
- sb.append("from ");
+ sb.append(" from ");
// build the from clause potentially with joins
// required only for the predicates
@@ -330,7 +329,7 @@ public class CQueryBuilder implements Constants {
boolean hasWhere = false;
if (inheritanceWhere.length() > 0) {
- sb.append(" ").append(NEW_LINE).append("where");
+ sb.append(" where");
sb.append(inheritanceWhere);
hasWhere = true;
}
@@ -339,7 +338,7 @@ public class CQueryBuilder implements Constants {
if (hasWhere) {
sb.append(" and ");
} else {
- sb.append(NEW_LINE).append("where ");
+ sb.append(" where ");
}
BeanDescriptor> desc = request.getBeanDescriptor();
@@ -356,9 +355,9 @@ public class CQueryBuilder implements Constants {
if (!isEmpty(dbWhere)) {
if (!hasWhere) {
hasWhere = true;
- sb.append(" ").append(NEW_LINE).append("where ");
+ sb.append(" where ");
} else {
- sb.append("and ");
+ sb.append(" and ");
}
sb.append(dbWhere);
}
@@ -366,7 +365,7 @@ public class CQueryBuilder implements Constants {
String dbFilterMany = predicates.getDbFilterMany();
if (!isEmpty(dbFilterMany)) {
if (!hasWhere) {
- sb.append(" ").append(NEW_LINE).append("where ");
+ sb.append(" where ");
} else {
sb.append("and ");
}
@@ -375,8 +374,7 @@ public class CQueryBuilder implements Constants {
String dbOrderBy = predicates.getDbOrderBy();
if (dbOrderBy != null) {
- sb.append(" ").append(NEW_LINE);
- sb.append("order by ").append(dbOrderBy);
+ sb.append(" order by ").append(dbOrderBy);
}
if (useSqlLimiter) {
diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryBuilderRawSql.java b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryBuilderRawSql.java
index be2ebe6b6..f9b42bd4d 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryBuilderRawSql.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryBuilderRawSql.java
@@ -60,7 +60,6 @@ public class CQueryBuilderRawSql implements Constants {
StringBuilder sb = new StringBuilder();
sb.append(sql.getPreFrom());
sb.append(" ");
- sb.append(NEW_LINE);
String s = sql.getPreWhere();
BindParams bindParams = request.getQuery().getBindParams();
@@ -95,11 +94,10 @@ public class CQueryBuilderRawSql implements Constants {
}
if (!isEmpty(dynamicWhere)) {
- sb.append(NEW_LINE);
if (sql.isAndWhereExpr()) {
- sb.append("and ");
+ sb.append(" and ");
} else {
- sb.append("where ");
+ sb.append(" where ");
}
sb.append(dynamicWhere);
sb.append(" ");
@@ -107,7 +105,6 @@ public class CQueryBuilderRawSql implements Constants {
String preHaving = sql.getPreHaving();
if (!isEmpty(preHaving)) {
- sb.append(NEW_LINE);
sb.append(preHaving);
sb.append(" ");
}
@@ -115,7 +112,6 @@ public class CQueryBuilderRawSql implements Constants {
String dbHaving = predicates.getDbHaving();
if (!isEmpty(dbHaving)) {
sb.append(" ");
- sb.append(NEW_LINE);
if (sql.isAndHavingExpr()) {
sb.append("and ");
} else {
@@ -126,7 +122,6 @@ public class CQueryBuilderRawSql implements Constants {
}
if (!isEmpty(orderBy)) {
- sb.append(NEW_LINE);
sb.append(" order by ").append(orderBy);
}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryEngine.java b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryEngine.java
index 39231a780..af3ea921e 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryEngine.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryEngine.java
@@ -3,6 +3,9 @@ package com.avaje.ebeaninternal.server.query;
import java.sql.SQLException;
import java.util.concurrent.FutureTask;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import com.avaje.ebean.BackgroundExecutor;
import com.avaje.ebean.QueryIterator;
import com.avaje.ebean.bean.BeanCollection;
@@ -12,10 +15,8 @@ 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.OrmQueryRequest;
-import com.avaje.ebeaninternal.server.jmx.MAdminLogging;
import com.avaje.ebeaninternal.server.persist.Binder;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import com.avaje.ebeaninternal.server.transaction.TransactionManager;
/**
* Handles the Object Relational fetching.
@@ -26,15 +27,12 @@ public class CQueryEngine {
private final CQueryBuilder queryBuilder;
- private final MAdminLogging logControl;
-
private final BackgroundExecutor backgroundExecutor;
private final int defaultSecondaryQueryBatchSize = 100;
- public CQueryEngine(DatabasePlatform dbPlatform, MAdminLogging logControl, Binder binder, BackgroundExecutor backgroundExecutor) {
+ public CQueryEngine(DatabasePlatform dbPlatform, Binder binder, BackgroundExecutor backgroundExecutor) {
- this.logControl = logControl;
this.backgroundExecutor = backgroundExecutor;
this.queryBuilder = new CQueryBuilder(backgroundExecutor, dbPlatform, binder);
}
@@ -51,18 +49,19 @@ public class CQueryEngine {
CQueryFetchIds rcQuery = queryBuilder.buildFetchIdsQuery(request);
try {
- String sql = rcQuery.getGeneratedSql();
- sql = sql.replace(Constants.NEW_LINE, ' ');
-
- if (logControl.isDebugGeneratedSql()) {
- System.out.println(sql);
- }
- request.logSql(sql);
-
+
BeanIdList list = rcQuery.findIds();
+ if (request.isLogSql()) {
+ String logSql = rcQuery.getGeneratedSql();
+ if (TransactionManager.SQL_LOGGER.isTraceEnabled()) {
+ logSql += "; --bind("+rcQuery.getBindLog()+")";
+ }
+ request.logSql(logSql);
+ }
+
if (request.isLogSummary()) {
- request.getTransaction().logInternal(rcQuery.getSummary());
+ request.getTransaction().logSummary(rcQuery.getSummary());
}
if (!list.isFetchingInBackground() && request.getQuery().isFutureFetch()) {
@@ -85,19 +84,19 @@ public class CQueryEngine {
CQueryRowCount rcQuery = queryBuilder.buildRowCountQuery(request);
try {
-
- String sql = rcQuery.getGeneratedSql();
- sql = sql.replace(Constants.NEW_LINE, ' ');
-
- if (logControl.isDebugGeneratedSql()) {
- System.out.println(sql);
- }
- request.logSql(sql);
-
+
int rowCount = rcQuery.findRowCount();
+ if (request.isLogSql()) {
+ String logSql = rcQuery.getGeneratedSql();
+ if (TransactionManager.SQL_LOGGER.isTraceEnabled()) {
+ logSql += "; --bind("+rcQuery.getBindLog()+")";
+ }
+ request.logSql(logSql);
+ }
+
if (request.isLogSummary()) {
- request.getTransaction().logInternal(rcQuery.getSummary());
+ request.getTransaction().logSummary(rcQuery.getSummary());
}
if (request.getQuery().isFutureFetch()) {
@@ -123,20 +122,16 @@ public class CQueryEngine {
try {
- if (logControl.isDebugGeneratedSql()) {
- logSqlToConsole(cquery);
- }
-
- if (request.isLogSql()) {
- logSql(cquery);
- }
-
if (!cquery.prepareBindExecuteQuery()) {
// query has been cancelled already
logger.trace("Future fetch already cancelled");
return null;
}
+ if (request.isLogSql()) {
+ logSql(cquery);
+ }
+
int iterateBufferSize = request.getSecondaryQueriesMinBatchSize(defaultSecondaryQueryBatchSize);
QueryIterator readIterate = cquery.readIterate(iterateBufferSize, request);
@@ -164,19 +159,15 @@ public class CQueryEngine {
request.setCancelableQuery(cquery);
try {
-
- if (logControl.isDebugGeneratedSql()) {
- logSqlToConsole(cquery);
- }
- if (request.isLogSql()) {
- logSql(cquery);
- }
-
if (!cquery.prepareBindExecuteQuery()) {
// query has been cancelled already
logger.trace("Future fetch already cancelled");
return null;
}
+
+ if (request.isLogSql()) {
+ logSql(cquery);
+ }
BeanCollection beanCollection = cquery.readCollection();
@@ -208,10 +199,8 @@ public class CQueryEngine {
return beanCollection;
} catch (SQLException e) {
- throw cquery.createPersistenceException(e);// request, e,
- // cquery.getBindLog(),
- // cquery.getGeneratedSql());
-
+ throw cquery.createPersistenceException(e);
+
} finally {
if (useBackgroundToContinueFetch) {
// left closing resources to BackgroundFetch...
@@ -239,15 +228,12 @@ public class CQueryEngine {
CQuery cquery = queryBuilder.buildQuery(request);
try {
- if (logControl.isDebugGeneratedSql()) {
- logSqlToConsole(cquery);
- }
+ cquery.prepareBindExecuteQuery();
+
if (request.isLogSql()) {
logSql(cquery);
}
- cquery.prepareBindExecuteQuery();
-
if (cquery.readBean()) {
bean = cquery.getLoadedBean();
}
@@ -268,46 +254,16 @@ public class CQueryEngine {
}
}
- /**
- * Log the generated SQL to the console.
- */
- private void logSqlToConsole(CQuery> cquery) {
-
- SpiQuery> query = cquery.getQueryRequest().getQuery();
- String loadMode = query.getLoadMode();
- String loadDesc = query.getLoadDescription();
-
- String sql = cquery.getGeneratedSql();
- String summary = cquery.getSummary();
-
- StringBuilder sb = new StringBuilder(1000);
- sb.append("");
- sb.append(Constants.NEW_LINE);
- sb.append(sql);
- sb.append(Constants.NEW_LINE).append("");
-
- System.out.println(sb.toString());
- }
-
/**
* Log the generated SQL to the transaction log.
*/
private void logSql(CQuery> query) {
String sql = query.getGeneratedSql();
- sql = sql.replace(Constants.NEW_LINE, ' ');
- query.getTransaction().logInternal(sql);
+ if (TransactionManager.SQL_LOGGER.isTraceEnabled()) {
+ sql += "; --bind("+query.getBindLog()+")";
+ }
+ query.getTransaction().logSql(sql);
}
/**
@@ -349,7 +305,7 @@ public class CQueryEngine {
msg.append("] rows[").append(q.getLoadedRowDetail());
msg.append("] bind[").append(q.getBindLog()).append("]");
- q.getTransaction().logInternal(msg.toString());
+ q.getTransaction().logSummary(msg.toString());
}
/**
@@ -394,6 +350,6 @@ public class CQueryEngine {
msg.append("] predicates[").append(q.getLogWhereSql());
msg.append("] bind[").append(q.getBindLog()).append("]");
- q.getTransaction().logInternal(msg.toString());
+ q.getTransaction().logSummary(msg.toString());
}
}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryPredicates.java b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryPredicates.java
index d609ddc51..1f11e6f68 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryPredicates.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryPredicates.java
@@ -151,7 +151,7 @@ public class CQueryPredicates {
Object bindValue = whereExprBindValues.get(i);
binder.bindObject(dataBind, bindValue);
if (i > 0 || idValue != null) {
- bindLog.append(", ");
+ bindLog.append(",");
}
bindLog.append(bindValue);
}
@@ -163,7 +163,7 @@ public class CQueryPredicates {
Object bindValue = filterManyExprBindValues.get(i);
binder.bindObject(dataBind, bindValue);
if (i > 0 || idValue != null) {
- bindLog.append(", ");
+ bindLog.append(",");
}
bindLog.append(bindValue);
}
@@ -182,7 +182,7 @@ public class CQueryPredicates {
Object bindValue = havingExprBindValues.get(i);
binder.bindObject(dataBind, bindValue);
if (i > 0) {
- bindLog.append(", ");
+ bindLog.append(",");
}
bindLog.append(bindValue);
}
@@ -215,10 +215,8 @@ public class CQueryPredicates {
boolean hasRaw = !"".equals(whereRawSql);
if (hasRaw && parseRaw) {
// parse with encrypted property awareness. This means that if we have
- // an
- // encrypted property we will insert special named parameter place
- // holders
- // for binding the encryption key values
+ // an encrypted property we will insert special named parameter place
+ // holders for binding the encryption key values
parser.setEncrypted(true);
whereRawSql = parser.parse(whereRawSql);
parser.setEncrypted(false);
@@ -259,7 +257,6 @@ public class CQueryPredicates {
public void prepare(boolean buildSql) {
DeployParser deployParser = request.createDeployParser();
-
prepare(buildSql, true, deployParser);
}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/Constants.java b/src/main/java/com/avaje/ebeaninternal/server/query/Constants.java
index 10e51db4d..6c0837cd1 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/query/Constants.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/query/Constants.java
@@ -5,19 +5,6 @@ package com.avaje.ebeaninternal.server.query;
*/
public interface Constants {
- /**
- * the new line character used.
- *
- * Note that this is removed for logging sql to the transaction log.
- *
- */
- public static final char NEW_LINE = '\n';
-
- /**
- * The carriage return character.
- */
- public static final char CARRIAGE_RETURN = '\r';
-
/**
* literal used for SQL LIMIT in MySql and Postgres.
*/
diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/DefaultDbSqlContext.java b/src/main/java/com/avaje/ebeaninternal/server/query/DefaultDbSqlContext.java
index 19f38b8bc..39bc1427a 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/query/DefaultDbSqlContext.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/query/DefaultDbSqlContext.java
@@ -11,264 +11,261 @@ import com.avaje.ebeaninternal.server.util.ArrayStack;
public class DefaultDbSqlContext implements DbSqlContext {
- private static final String NEW_LINE = "\n";
+ private static final String COMMA = ", ";
- private static final String COMMA = ", ";
+ private static final String PERIOD = ".";
- private static final String PERIOD = ".";
+ private final String tableAliasPlaceHolder;
- private final String tableAliasPlaceHolder;
+ private final String columnAliasPrefix;
- private final String columnAliasPrefix;
+ private final ArrayStack tableAliasStack = new ArrayStack();
- private final ArrayStack tableAliasStack = new ArrayStack();
+ private final ArrayStack joinStack = new ArrayStack();
- private final ArrayStack joinStack = new ArrayStack();
-
- private final ArrayStack prefixStack = new ArrayStack();
+ private final ArrayStack prefixStack = new ArrayStack();
- private final boolean useColumnAlias;
+ private final boolean useColumnAlias;
- private int columnIndex;
+ private int columnIndex;
- private StringBuilder sb = new StringBuilder(140);
+ private StringBuilder sb = new StringBuilder(140);
- /**
- * A Set used to make sure formula joins are only added once to a query.
- */
- private HashSet formulaJoins;
+ /**
+ * A Set used to make sure formula joins are only added once to a query.
+ */
+ private HashSet formulaJoins;
- private HashSet tableJoins;
+ private HashSet tableJoins;
- private SqlTreeAlias alias;
+ private SqlTreeAlias alias;
- private String currentPrefix;
+ private String currentPrefix;
- private ArrayList encryptedProps;
-
- /**
- * Construct for FROM clause (no column alias used).
- */
- public DefaultDbSqlContext(SqlTreeAlias alias, String tableAliasPlaceHolder) {
- this.tableAliasPlaceHolder = tableAliasPlaceHolder;
- this.columnAliasPrefix = null;
- this.useColumnAlias = false;
- this.alias = alias;
+ private ArrayList encryptedProps;
+
+ /**
+ * Construct for FROM clause (no column alias used).
+ */
+ public DefaultDbSqlContext(SqlTreeAlias alias, String tableAliasPlaceHolder) {
+ this.tableAliasPlaceHolder = tableAliasPlaceHolder;
+ this.columnAliasPrefix = null;
+ this.useColumnAlias = false;
+ this.alias = alias;
+ }
+
+ /**
+ * Construct for SELECT clause (with column alias settings).
+ */
+ public DefaultDbSqlContext(SqlTreeAlias alias, String tableAliasPlaceHolder,
+ String columnAliasPrefix, boolean alwaysUseColumnAlias) {
+ this.alias = alias;
+ this.tableAliasPlaceHolder = tableAliasPlaceHolder;
+ this.columnAliasPrefix = columnAliasPrefix;
+ this.useColumnAlias = alwaysUseColumnAlias;
+ }
+
+ public void addEncryptedProp(BeanProperty p) {
+ if (encryptedProps == null) {
+ encryptedProps = new ArrayList();
+ }
+ encryptedProps.add(p);
+ }
+
+ public BeanProperty[] getEncryptedProps() {
+ if (encryptedProps == null) {
+ return null;
}
- /**
- * Construct for SELECT clause (with column alias settings).
- */
- public DefaultDbSqlContext(SqlTreeAlias alias, String tableAliasPlaceHolder, String columnAliasPrefix,
- boolean alwaysUseColumnAlias) {
- this.alias = alias;
- this.tableAliasPlaceHolder = tableAliasPlaceHolder;
- this.columnAliasPrefix = columnAliasPrefix;
- this.useColumnAlias = alwaysUseColumnAlias;
+ return encryptedProps.toArray(new BeanProperty[encryptedProps.size()]);
+ }
+
+ public String peekJoin() {
+ return joinStack.peek();
+ }
+
+ public void popJoin() {
+ joinStack.pop();
+ }
+
+ public void pushJoin(String node) {
+ joinStack.push(node);
+ }
+
+ public void addJoin(String type, String table, TableJoinColumn[] cols, String a1, String a2) {
+
+ if (tableJoins == null) {
+ tableJoins = new HashSet();
}
- public void addEncryptedProp(BeanProperty p) {
- if (encryptedProps == null){
- encryptedProps = new ArrayList();
- }
- encryptedProps.add(p);
- }
-
- public BeanProperty[] getEncryptedProps() {
- if (encryptedProps == null){
- return null;
- }
-
- return encryptedProps.toArray(new BeanProperty[encryptedProps.size()]);
+ String joinKey = table + "-" + a1 + "-" + a2;
+ if (tableJoins.contains(joinKey)) {
+ return;
}
- public String peekJoin() {
- return joinStack.peek();
+ tableJoins.add(joinKey);
+
+ sb.append(" ");
+ sb.append(type);
+ sb.append(" ").append(table).append(" ");
+ sb.append(a2);
+ sb.append(" on ");
+
+ for (int i = 0; i < cols.length; i++) {
+ TableJoinColumn pair = cols[i];
+ if (i > 0) {
+ sb.append(" and ");
+ }
+
+ sb.append(a2);
+ sb.append(".").append(pair.getForeignDbColumn());
+ sb.append(" = ");
+ sb.append(a1);
+ sb.append(".").append(pair.getLocalDbColumn());
}
- public void popJoin() {
- joinStack.pop();
+ sb.append(" ");
+ }
+
+ public String getTableAlias(String prefix) {
+ return alias.getTableAlias(prefix);
+ }
+
+ public String getTableAliasManyWhere(String prefix) {
+ return alias.getTableAliasManyWhere(prefix);
+ }
+
+ public void pushSecondaryTableAlias(String alias) {
+ tableAliasStack.push(alias);
+ }
+
+ public String getRelativePrefix(String propName) {
+
+ return currentPrefix == null ? propName : currentPrefix + "." + propName;
+ }
+
+ public void pushTableAlias(String prefix) {
+ // store the currentPrefix on a stack
+ prefixStack.push(currentPrefix);
+ currentPrefix = prefix;
+ tableAliasStack.push(getTableAlias(prefix));
+ }
+
+ public void popTableAlias() {
+ tableAliasStack.pop();
+ // pop the currentPrefix from the stack
+ currentPrefix = prefixStack.pop();
+ ;
+ }
+
+ public StringBuilder getBuffer() {
+ return sb;
+ }
+
+ public DefaultDbSqlContext append(String s) {
+ sb.append(s);
+ return this;
+ }
+
+ public DefaultDbSqlContext append(char s) {
+ sb.append(s);
+ return this;
+ }
+
+ public void appendFormulaJoin(String sqlFormulaJoin, boolean forceOuterJoin) {
+
+ // replace ${ta} place holder with the real table alias...
+ String tableAlias = tableAliasStack.peek();
+ String converted = StringHelper
+ .replaceString(sqlFormulaJoin, tableAliasPlaceHolder, tableAlias);
+
+ if (formulaJoins == null) {
+ formulaJoins = new HashSet();
+
+ } else if (formulaJoins.contains(converted)) {
+ // skip adding a formula join because
+ // the same join has already been added.
+ return;
}
- public void pushJoin(String node) {
- joinStack.push(node);
+ // we only want to add this join once
+ formulaJoins.add(converted);
+
+ sb.append(" ");
+ if (forceOuterJoin) {
+ if ("join".equals(sqlFormulaJoin.substring(0, 4).toLowerCase())) {
+ // prepend left outer as we are in the 'many' part
+ append(" left outer ");
+ }
}
- public void addJoin(String type, String table, TableJoinColumn[] cols, String a1, String a2) {
+ sb.append(converted);
+ sb.append(" ");
+ }
- if (tableJoins == null) {
- tableJoins = new HashSet();
- }
+ public void appendFormulaSelect(String sqlFormulaSelect) {
- String joinKey = table + "-" + a1 + "-" + a2;
- if (tableJoins.contains(joinKey)) {
- return;
- }
+ String tableAlias = tableAliasStack.peek();
+ String converted = StringHelper.replaceString(sqlFormulaSelect, tableAliasPlaceHolder,
+ tableAlias);
- tableJoins.add(joinKey);
+ sb.append(COMMA);
+ sb.append(converted);
+ }
- sb.append(NEW_LINE);
- sb.append(type);
+ public void appendColumn(String column) {
+ appendColumn(tableAliasStack.peek(), column);
+ }
- sb.append(" ").append(table).append(" ");
- sb.append(a2);
+ public void appendColumn(String tableAlias, String column) {
+ sb.append(COMMA);
- sb.append(" on ");
-
- for (int i = 0; i < cols.length; i++) {
- TableJoinColumn pair = cols[i];
- if (i > 0) {
- sb.append(" and ");
- }
-
- sb.append(a2);
- sb.append(".").append(pair.getForeignDbColumn());
- sb.append(" = ");
- sb.append(a1);
- sb.append(".").append(pair.getLocalDbColumn());
- }
-
- sb.append(" ");
+ if (column.indexOf("${}") > -1) {
+ // support DB functions such as lower() etc
+ // with the use of secondary columns
+ String x = StringHelper.replaceString(column, "${}", tableAlias);
+ sb.append(x);
+ } else {
+ sb.append(tableAlias);
+ sb.append(PERIOD);
+ sb.append(column);
}
-
- public String getTableAlias(String prefix) {
- return alias.getTableAlias(prefix);
+ if (useColumnAlias) {
+ sb.append(" ");
+ sb.append(columnAliasPrefix);
+ sb.append(columnIndex);
}
+ columnIndex++;
+ }
- public String getTableAliasManyWhere(String prefix) {
- return alias.getTableAliasManyWhere(prefix);
+ public String peekTableAlias() {
+ return tableAliasStack.peek();
+ }
+
+ public void appendRawColumn(String rawcolumnWithTableAlias) {
+ sb.append(COMMA);
+ sb.append(rawcolumnWithTableAlias);
+
+ if (useColumnAlias) {
+ sb.append(" ");
+ sb.append(columnAliasPrefix);
+ sb.append(columnIndex);
}
+ columnIndex++;
+ }
- public void pushSecondaryTableAlias(String alias) {
- tableAliasStack.push(alias);
- }
+ public int length() {
+ return sb.length();
+ }
- public String getRelativePrefix(String propName) {
+ public String getContent() {
+ String s = sb.toString();
+ sb = new StringBuilder();
+ return s;
+ }
- return currentPrefix == null ? propName : currentPrefix + "." + propName;
- }
-
- public void pushTableAlias(String prefix) {
- // store the currentPrefix on a stack
- prefixStack.push(currentPrefix);
- currentPrefix = prefix;
- tableAliasStack.push(getTableAlias(prefix));
- }
-
- public void popTableAlias() {
- tableAliasStack.pop();
- // pop the currentPrefix from the stack
- currentPrefix = prefixStack.pop();;
- }
-
- public StringBuilder getBuffer() {
- return sb;
- }
-
- public DefaultDbSqlContext append(String s) {
- sb.append(s);
- return this;
- }
-
- public DefaultDbSqlContext append(char s) {
- sb.append(s);
- return this;
- }
-
- public void appendFormulaJoin(String sqlFormulaJoin, boolean forceOuterJoin) {
-
- // replace ${ta} place holder with the real table alias...
- String tableAlias = tableAliasStack.peek();
- String converted = StringHelper.replaceString(sqlFormulaJoin, tableAliasPlaceHolder, tableAlias);
-
- if (formulaJoins == null) {
- formulaJoins = new HashSet();
-
- } else if (formulaJoins.contains(converted)) {
- // skip adding a formula join because
- // the same join has already been added.
- return;
- }
-
- // we only want to add this join once
- formulaJoins.add(converted);
-
- sb.append(NEW_LINE);
-
- if (forceOuterJoin) {
- if ("join".equals(sqlFormulaJoin.substring(0, 4).toLowerCase())) {
- // prepend left outer as we are in the 'many' part
- append(" left outer ");
- }
- }
-
- sb.append(converted);
- sb.append(" ");
- }
-
- public void appendFormulaSelect(String sqlFormulaSelect) {
-
- String tableAlias = tableAliasStack.peek();
- String converted = StringHelper.replaceString(sqlFormulaSelect, tableAliasPlaceHolder, tableAlias);
-
- sb.append(COMMA);
- sb.append(converted);
- }
-
- public void appendColumn(String column) {
- appendColumn(tableAliasStack.peek(), column);
- }
-
- public void appendColumn(String tableAlias, String column) {
- sb.append(COMMA);
-
- if (column.indexOf("${}") > -1){
- // support DB functions such as lower() etc
- // with the use of secondary columns
- String x = StringHelper.replaceString(column, "${}", tableAlias);
- sb.append(x);
- } else {
- sb.append(tableAlias);
- sb.append(PERIOD);
- sb.append(column);
- }
- if (useColumnAlias) {
- sb.append(" ");
- sb.append(columnAliasPrefix);
- sb.append(columnIndex);
- }
- columnIndex++;
- }
-
- public String peekTableAlias() {
- return tableAliasStack.peek();
- }
-
- public void appendRawColumn(String rawcolumnWithTableAlias) {
- sb.append(COMMA);
- sb.append(rawcolumnWithTableAlias);
-
- if (useColumnAlias) {
- sb.append(" ");
- sb.append(columnAliasPrefix);
- sb.append(columnIndex);
- }
- columnIndex++;
- }
-
- public int length() {
- return sb.length();
- }
-
- public String getContent() {
- String s = sb.toString();
- sb = new StringBuilder();
- return s;
- }
-
- public String toString() {
- return "DefaultDbSqlContext: "+sb.toString();
- }
-
+ public String toString() {
+ return "DefaultDbSqlContext: " + sb.toString();
+ }
}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/DefaultRelationalQueryEngine.java b/src/main/java/com/avaje/ebeaninternal/server/query/DefaultRelationalQueryEngine.java
index 029b7474b..d51486527 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/query/DefaultRelationalQueryEngine.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/query/DefaultRelationalQueryEngine.java
@@ -9,6 +9,9 @@ import java.util.ArrayList;
import javax.persistence.PersistenceException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import com.avaje.ebean.SqlQueryListener;
import com.avaje.ebean.SqlRow;
import com.avaje.ebean.bean.BeanCollection;
@@ -19,12 +22,10 @@ import com.avaje.ebeaninternal.api.SpiTransaction;
import com.avaje.ebeaninternal.server.core.Message;
import com.avaje.ebeaninternal.server.core.RelationalQueryEngine;
import com.avaje.ebeaninternal.server.core.RelationalQueryRequest;
-import com.avaje.ebeaninternal.server.jmx.MAdminLogging;
import com.avaje.ebeaninternal.server.persist.Binder;
+import com.avaje.ebeaninternal.server.transaction.TransactionManager;
import com.avaje.ebeaninternal.server.type.DataBind;
import com.avaje.ebeaninternal.server.util.BindParamsParser;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
* Perform native sql fetches.
@@ -39,7 +40,7 @@ public class DefaultRelationalQueryEngine implements RelationalQueryEngine {
private final String dbTrueValue;
- public DefaultRelationalQueryEngine(MAdminLogging logControl, Binder binder, String dbTrueValue) {
+ public DefaultRelationalQueryEngine(Binder binder, String dbTrueValue) {
this.binder = binder;
this.defaultMaxRows = GlobalProperties.getInt("nativesql.defaultmaxrows",100000);
this.dbTrueValue = dbTrueValue == null ? "true" : dbTrueValue;
@@ -94,9 +95,11 @@ public class DefaultRelationalQueryEngine implements RelationalQueryEngine {
}
if (request.isLogSql()) {
- String sOut = sql.replace(Constants.NEW_LINE, ' ');
- sOut = sOut.replace(Constants.CARRIAGE_RETURN, ' ');
- t.logInternal(sOut);
+ String logSql = sql;
+ if (TransactionManager.SQL_LOGGER.isTraceEnabled()) {
+ logSql += "; --bind("+bindLog+")";
+ }
+ t.logSql(logSql);
}
rset = pstmt.executeQuery();
@@ -178,7 +181,7 @@ public class DefaultRelationalQueryEngine implements RelationalQueryEngine {
String msg = "SqlQuery rows[" + loadRowCount + "] time[" + exeTime + "] bind["
+ bindLog + "] finished[" + beanColl.isFinishedFetch() + "]";
- t.logInternal(msg);
+ t.logSummary(msg);
}
if (query.isCancelled()){
diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/SqlTree.java b/src/main/java/com/avaje/ebeaninternal/server/query/SqlTree.java
index 6eeabdd53..0065904a5 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/query/SqlTree.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/query/SqlTree.java
@@ -13,160 +13,158 @@ import com.avaje.ebeaninternal.server.el.ElPropertyValue;
*/
public class SqlTree {
- private SqlTreeNode rootNode;
+ private SqlTreeNode rootNode;
-
- /**
- * Property if resultSet contains master and detail rows.
- */
- private BeanPropertyAssocMany> manyProperty;
- private String manyPropertyName;
- private ElPropertyValue manyPropEl;
+ /**
+ * Property if resultSet contains master and detail rows.
+ */
+ private BeanPropertyAssocMany> manyProperty;
+ private String manyPropertyName;
+ private ElPropertyValue manyPropEl;
- private Set includes;
+ private Set includes;
- /**
- * Summary of the select being generated.
- */
- private String summary;
+ /**
+ * Summary of the select being generated.
+ */
+ private String summary;
- private String selectSql;
+ private String selectSql;
- private String fromSql;
+ private String fromSql;
- /**
- * Encrypted Properties require additional binding.
- */
- private BeanProperty[] encryptedProps;
-
- /**
- * Where clause for inheritance.
- */
- private String inheritanceWhereSql;
+ /**
+ * Encrypted Properties require additional binding.
+ */
+ private BeanProperty[] encryptedProps;
-
- /**
- * Create the SqlSelectClause.
- */
- public SqlTree() {
- }
-
- public List buildSelectExpressionChain() {
- ArrayList list = new ArrayList();
- rootNode.buildSelectExpressionChain(list);
- return list;
- }
-
- /**
- * Return the includes. Associated beans lists etc.
- */
- public Set getIncludes() {
- return includes;
- }
-
- /**
- * Set the association includes (Ones and Many's).
- */
- public void setIncludes(Set includes) {
- this.includes = includes;
- }
-
- /**
- * Set the manyProperty used for this query.
- */
- public void setManyProperty(BeanPropertyAssocMany> manyProperty, String manyPropertyName, ElPropertyValue manyPropEl) {
- this.manyProperty = manyProperty;
- this.manyPropertyName = manyPropertyName;
- this.manyPropEl = manyPropEl;
- }
+ /**
+ * Where clause for inheritance.
+ */
+ private String inheritanceWhereSql;
- /**
- * Return the String for the actual SQL.
- */
- public String getSelectSql() {
- return selectSql;
- }
+ /**
+ * Create the SqlSelectClause.
+ */
+ public SqlTree() {
+ }
- /**
- * Set the select sql clause.
- */
- public void setSelectSql(String selectSql) {
- this.selectSql = selectSql;
- }
+ public List buildSelectExpressionChain() {
+ ArrayList list = new ArrayList();
+ rootNode.buildSelectExpressionChain(list);
+ return list;
+ }
-
- public String getFromSql() {
- return fromSql;
- }
+ /**
+ * Return the includes. Associated beans lists etc.
+ */
+ public Set getIncludes() {
+ return includes;
+ }
- public void setFromSql(String fromSql) {
- this.fromSql = fromSql;
- }
-
- /**
- * Return the where clause for inheritance.
- */
- public String getInheritanceWhereSql() {
- return inheritanceWhereSql;
- }
+ /**
+ * Set the association includes (Ones and Many's).
+ */
+ public void setIncludes(Set includes) {
+ this.includes = includes;
+ }
- /**
- * Set where clause(s) for inheritance.
- */
- public void setInheritanceWhereSql(String whereSql) {
- this.inheritanceWhereSql = whereSql;
- }
+ /**
+ * Set the manyProperty used for this query.
+ */
+ public void setManyProperty(BeanPropertyAssocMany> manyProperty, String manyPropertyName,
+ ElPropertyValue manyPropEl) {
+ this.manyProperty = manyProperty;
+ this.manyPropertyName = manyPropertyName;
+ this.manyPropEl = manyPropEl;
+ }
- /**
- * Set the summary description of the query.
- */
- public void setSummary(String summary) {
- this.summary = summary;
- }
+ /**
+ * Return the String for the actual SQL.
+ */
+ public String getSelectSql() {
+ return selectSql;
+ }
- /**
- * Return a summary of the select clause.
- */
- public String getSummary() {
- return summary;
- }
-
- public SqlTreeNode getRootNode() {
- return rootNode;
- }
-
- public void setRootNode(SqlTreeNode rootNode) {
- this.rootNode = rootNode;
- }
+ /**
+ * Set the select sql clause.
+ */
+ public void setSelectSql(String selectSql) {
+ this.selectSql = selectSql;
+ }
- /**
- * Return the property that is associated with the many. There can only be
- * one per SqlSelect. This can be null.
- */
- public BeanPropertyAssocMany> getManyProperty() {
- return manyProperty;
- }
+ public String getFromSql() {
+ return fromSql;
+ }
- public String getManyPropertyName() {
- return manyPropertyName;
- }
+ public void setFromSql(String fromSql) {
+ this.fromSql = fromSql;
+ }
- public ElPropertyValue getManyPropertyEl() {
- return manyPropEl;
- }
+ /**
+ * Return the where clause for inheritance.
+ */
+ public String getInheritanceWhereSql() {
+ return inheritanceWhereSql;
+ }
- /**
- * Return true if this query includes a Many association.
- */
- public boolean isManyIncluded() {
- return (manyProperty != null);
- }
+ /**
+ * Set where clause(s) for inheritance.
+ */
+ public void setInheritanceWhereSql(String whereSql) {
+ this.inheritanceWhereSql = whereSql;
+ }
- public BeanProperty[] getEncryptedProps() {
- return encryptedProps;
- }
+ /**
+ * Set the summary description of the query.
+ */
+ public void setSummary(String summary) {
+ this.summary = summary;
+ }
- public void setEncryptedProps(BeanProperty[] encryptedProps) {
- this.encryptedProps = encryptedProps;
- }
+ /**
+ * Return a summary of the select clause.
+ */
+ public String getSummary() {
+ return summary;
+ }
+
+ public SqlTreeNode getRootNode() {
+ return rootNode;
+ }
+
+ public void setRootNode(SqlTreeNode rootNode) {
+ this.rootNode = rootNode;
+ }
+
+ /**
+ * Return the property that is associated with the many. There can only be one
+ * per SqlSelect. This can be null.
+ */
+ public BeanPropertyAssocMany> getManyProperty() {
+ return manyProperty;
+ }
+
+ public String getManyPropertyName() {
+ return manyPropertyName;
+ }
+
+ public ElPropertyValue getManyPropertyEl() {
+ return manyPropEl;
+ }
+
+ /**
+ * Return true if this query includes a Many association.
+ */
+ public boolean isManyIncluded() {
+ return (manyProperty != null);
+ }
+
+ public BeanProperty[] getEncryptedProps() {
+ return encryptedProps;
+ }
+
+ public void setEncryptedProps(BeanProperty[] encryptedProps) {
+ this.encryptedProps = encryptedProps;
+ }
}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeBuilder.java b/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeBuilder.java
index 5dfa4f2d5..1cf9047ef 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeBuilder.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeBuilder.java
@@ -32,633 +32,647 @@ import org.slf4j.LoggerFactory;
*/
public class SqlTreeBuilder {
- private static final Logger logger = LoggerFactory.getLogger(SqlTreeBuilder.class);
+ private static final Logger logger = LoggerFactory.getLogger(SqlTreeBuilder.class);
- private final SpiQuery> query;
+ private final SpiQuery> query;
+
+ private final BeanDescriptor> desc;
+
+ private final OrmQueryDetail queryDetail;
+
+ private final StringBuilder summary = new StringBuilder();
+
+ private final CQueryPredicates predicates;
+
+ private final boolean subQuery;
+
+ /**
+ * Property if resultSet contains master and detail rows.
+ */
+ private BeanPropertyAssocMany> manyProperty;
+
+ private String manyPropertyName;
+
+ private final SqlTreeAlias alias;
+
+ private final DefaultDbSqlContext ctx;
+
+ private final HashSet selectIncludes = new HashSet();
+
+ private final ManyWhereJoins manyWhereJoins;
+
+ private final TableJoin includeJoin;
+
+ private final boolean rawSql;
+
+ /**
+ * Construct for RawSql query.
+ */
+ public SqlTreeBuilder(OrmQueryRequest> request, CQueryPredicates predicates,
+ OrmQueryDetail queryDetail) {
+
+ this.rawSql = true;
+ this.desc = request.getBeanDescriptor();
+ this.query = null;
+ this.subQuery = false;
+ this.queryDetail = queryDetail;
+ this.predicates = predicates;
+
+ this.includeJoin = null;
+ this.manyWhereJoins = null;
+ this.alias = null;
+ this.ctx = null;
+ }
+
+ /**
+ * The predicates are used to determine if 'extra' joins are required to
+ * support the where and/or order by clause. If so these extra joins are added
+ * to the root node.
+ */
+ public SqlTreeBuilder(String tableAliasPlaceHolder, String columnAliasPrefix,
+ OrmQueryRequest> request, CQueryPredicates predicates) {
+
+ this.rawSql = false;
+ this.desc = request.getBeanDescriptor();
+ this.query = request.getQuery();
+
+ this.subQuery = Type.SUBQUERY.equals(query.getType());
+ this.includeJoin = query.getIncludeTableJoin();
+ this.manyWhereJoins = query.getManyWhereJoins();
+ this.queryDetail = query.getDetail();
+
+ this.predicates = predicates;
+ this.alias = new SqlTreeAlias(request.getBeanDescriptor().getBaseTableAlias());
+ this.ctx = new DefaultDbSqlContext(alias, tableAliasPlaceHolder, columnAliasPrefix, !subQuery);
+ }
+
+ /**
+ * Build based on the includes and using the BeanJoinTree.
+ */
+ public SqlTree build() {
+
+ SqlTree sqlTree = new SqlTree();
+
+ summary.append(desc.getName());
+
+ // build the appropriate chain of SelectAdapter's
+ buildRoot(desc, sqlTree);
+
+ // build the actual String
+ SqlTreeNode rootNode = sqlTree.getRootNode();
+
+ if (!rawSql) {
+ sqlTree.setSelectSql(buildSelectClause(rootNode));
+ sqlTree.setFromSql(buildFromClause(rootNode));
+ sqlTree.setInheritanceWhereSql(buildWhereClause(rootNode));
+ sqlTree.setEncryptedProps(ctx.getEncryptedProps());
+ }
+ sqlTree.setIncludes(queryDetail.getIncludes());
+ sqlTree.setSummary(summary.toString());
+
+ if (manyPropertyName != null) {
+ ElPropertyValue manyPropEl = desc.getElGetValue(manyPropertyName);
+ sqlTree.setManyProperty(manyProperty, manyPropertyName, manyPropEl);
+ }
+
+ return sqlTree;
+ }
+
+ private String buildSelectClause(SqlTreeNode rootNode) {
+
+ if (rawSql) {
+ return "Not Used";
+ }
+ rootNode.appendSelect(ctx, subQuery);
+
+ String selectSql = ctx.getContent();
+
+ // trim off the first comma
+ if (selectSql.length() >= SqlTreeNode.COMMA.length()) {
+ selectSql = selectSql.substring(SqlTreeNode.COMMA.length());
+ }
+
+ return selectSql;
+ }
+
+ private String buildWhereClause(SqlTreeNode rootNode) {
+
+ if (rawSql) {
+ return "Not Used";
+ }
+ rootNode.appendWhere(ctx);
+ return ctx.getContent();
+ }
+
+ private String buildFromClause(SqlTreeNode rootNode) {
+
+ if (rawSql) {
+ return "Not Used";
+ }
+ rootNode.appendFrom(ctx, false);
+ return ctx.getContent();
+ }
+
+ private void buildRoot(BeanDescriptor> desc, SqlTree sqlTree) {
+
+ SqlTreeNode selectRoot = buildSelectChain(null, null, desc, null);
+ sqlTree.setRootNode(selectRoot);
+
+ if (!rawSql) {
+ alias.addJoin(queryDetail.getIncludes(), desc);
+ alias.addJoin(predicates.getPredicateIncludes(), desc);
+ alias.addManyWhereJoins(manyWhereJoins.getJoins());
+
+ // build set of table alias
+ alias.buildAlias();
+
+ predicates.parseTableAlias(alias);
+ }
+ }
+
+ /**
+ * Recursively build the query tree depending on what leaves in the tree
+ * should be included.
+ */
+ private SqlTreeNode buildSelectChain(String prefix, BeanPropertyAssoc> prop,
+ BeanDescriptor> desc, List joinList) {
+
+ List myJoinList = new ArrayList();
+
+ BeanPropertyAssocOne>[] ones = desc.propertiesOne();
+ for (int i = 0; i < ones.length; i++) {
+ String propPrefix = SplitName.add(prefix, ones[i].getName());
+ if (isIncludeBean(propPrefix, ones[i])) {
+ selectIncludes.add(propPrefix);
+ buildSelectChain(propPrefix, ones[i], ones[i].getTargetDescriptor(), myJoinList);
+ }
+ }
+
+ BeanPropertyAssocMany>[] manys = desc.propertiesMany();
+ for (int i = 0; i < manys.length; i++) {
+ String propPrefix = SplitName.add(prefix, manys[i].getName());
+ if (isIncludeMany(prefix, propPrefix, manys[i])) {
+ selectIncludes.add(propPrefix);
+ buildSelectChain(propPrefix, manys[i], manys[i].getTargetDescriptor(), myJoinList);
+ }
+ }
+
+ if (prefix == null && !rawSql) {
+ addManyWhereJoins(myJoinList);
+ }
+
+ SqlTreeNode selectNode = buildNode(prefix, prop, desc, myJoinList);
+ if (joinList != null) {
+ joinList.add(selectNode);
+ }
+ return selectNode;
+ }
+
+ /**
+ * Add joins used to support where clause predicates on 'many' properties.
+ *
+ * These joins are effectively independent of any fetch joins on 'many'
+ * properties.
+ *
+ */
+ private void addManyWhereJoins(List myJoinList) {
+
+ Set includes = manyWhereJoins.getJoins();
+ for (String joinProp : includes) {
+
+ BeanPropertyAssoc> beanProperty = (BeanPropertyAssoc>) desc
+ .getBeanPropertyFromPath(joinProp);
+ SqlTreeNodeManyWhereJoin nodeJoin = new SqlTreeNodeManyWhereJoin(joinProp, beanProperty);
+ myJoinList.add(nodeJoin);
+ }
+ }
+
+ private SqlTreeNode buildNode(String prefix, BeanPropertyAssoc> prop, BeanDescriptor> desc,
+ List myList) {
+
+ OrmQueryProperties queryProps = queryDetail.getChunk(prefix, false);
+
+ SqlTreeProperties props = getBaseSelect(desc, queryProps);
+
+ if (prefix == null) {
+ buildExtraJoins(desc, myList);
+ return new SqlTreeNodeRoot(desc, props, myList, !subQuery, includeJoin);
+
+ } else if (prop instanceof BeanPropertyAssocMany>) {
+ return new SqlTreeNodeManyRoot(prefix, (BeanPropertyAssocMany>) prop, props, myList);
+
+ } else {
+ return new SqlTreeNodeBean(prefix, prop, props, myList, true);
+ }
+ }
+
+ /**
+ * Build extra joins to support properties used in where clause but not
+ * already in select clause.
+ */
+ private void buildExtraJoins(BeanDescriptor> desc, List myList) {
+
+ if (rawSql) {
+ return;
+ }
+
+ Set predicateIncludes = predicates.getPredicateIncludes();
+
+ if (predicateIncludes == null) {
+ return;
+ }
+
+ // Note includes - basically means joins.
+ // The selectIncludes is the set of joins that are required to support
+ // the 'select' part of the query. We may need to add other joins to
+ // support the predicates or order by clauses.
+
+ // remove ManyWhereJoins from the predicateIncludes
+ predicateIncludes.removeAll(manyWhereJoins.getJoins());
+
+ // look for predicateIncludes that are not in selectIncludes and add
+ // them as extra joins to the query
+ IncludesDistiller extraJoinDistill = new IncludesDistiller(desc, selectIncludes,
+ predicateIncludes);
+
+ Collection extraJoins = extraJoinDistill.getExtraJoinRootNodes();
+ if (extraJoins.isEmpty()) {
+ return;
+
+ } else {
+ // add extra joins required to support predicates
+ // and/or order by clause
+ Iterator it = extraJoins.iterator();
+ while (it.hasNext()) {
+ SqlTreeNodeExtraJoin extraJoin = it.next();
+ myList.add(extraJoin);
+
+ if (extraJoin.isManyJoin()) {
+ // as we are now going to join to the many then we need
+ // to add the distinct to the sql query to stop duplicate
+ // rows...
+ query.setDistinct(true);
+ }
+ }
+ }
+ }
+
+ /**
+ * A subQuery has slightly different rules in that it just generates SQL (into
+ * the where clause) and its properties are not required to read the resultSet
+ * etc.
+ *
+ * This means it can included individual properties of an embedded bean.
+ *
+ */
+ private void addPropertyToSubQuery(SqlTreeProperties selectProps, BeanDescriptor> desc,
+ OrmQueryProperties queryProps, String propName) {
+
+ BeanProperty p = desc.findBeanProperty(propName);
+ if (p == null) {
+ logger
+ .error("property [" + propName + "]not found on " + desc + " for query - excluding it.");
+
+ } else if (p instanceof BeanPropertyAssoc> && p.isEmbedded()) {
+ // if the property is embedded we need to lookup the real column name
+ int pos = propName.indexOf(".");
+ if (pos > -1) {
+ String name = propName.substring(pos + 1);
+ p = ((BeanPropertyAssoc>) p).getTargetDescriptor().findBeanProperty(name);
+ }
+ }
+
+ selectProps.add(p);
+ }
+
+ private void addProperty(SqlTreeProperties selectProps, BeanDescriptor> desc,
+ OrmQueryProperties queryProps, String propName) {
+
+ if (subQuery) {
+ addPropertyToSubQuery(selectProps, desc, queryProps, propName);
+ return;
+ }
+
+ int basePos = propName.indexOf('.');
+ if (basePos > -1) {
+ // property on an embedded bean. Embedded beans do not yet
+ // support being partially populated so we include the
+ // 'base' property and make sure we only do that once
+ String baseName = propName.substring(0, basePos);
+
+ // make sure we only included the base/embedded bean once
+ if (!selectProps.containsProperty(baseName)) {
+ BeanProperty p = desc.findBeanProperty(baseName);
+ if (p == null) {
+ String m = "property [" + propName + "] not found on " + desc
+ + " for query - excluding it.";
+ logger.error(m);
+
+ } else if (p.isEmbedded()) {
+ // add the embedded bean (and effectively
+ // all its properties)
+ selectProps.add(p);
+ // also make sure it is added to included properties
+ // to avoid unnecessary lazy loading
+ selectProps.getIncludedProperties().add(baseName);
+
+ } else {
+ String m = "property [" + p.getFullBeanName()
+ + "] expected to be an embedded bean for query - excluding it.";
+ logger.error(m);
+ }
+ }
+
+ } else {
+ // find the property including searching the
+ // sub class hierarchy if required
+ BeanProperty p = desc.findBeanProperty(propName);
+ if (p == null) {
+ logger.error("property [" + propName + "] not found on " + desc
+ + " for query - excluding it.");
+
+ } else if (p.isId()) {
+ // do not bother to include id for normal queries as the
+ // id is always added (except for subQueries)
+
+ } else if (p instanceof BeanPropertyAssoc>) {
+ // need to check if this property should be
+ // excluded. This occurs when this property is
+ // included as a bean join. With a bean join
+ // the property should be excluded as the bean
+ // join has its own node in the SqlTree.
+ if (!queryProps.isIncludedBeanJoin(p.getName())) {
+ // include the property... which basically
+ // means include the foreign key column(s)
+ selectProps.add(p);
+ }
+ } else {
+ selectProps.add(p);
+ }
+ }
+ }
+
+ private SqlTreeProperties getBaseSelectPartial(BeanDescriptor> desc,
+ OrmQueryProperties queryProps) {
+
+ SqlTreeProperties selectProps = new SqlTreeProperties();
+ selectProps.setReadOnly(queryProps.isReadOnly());
+ selectProps.setIncludedProperties(queryProps.getAllIncludedProperties());
+
+ // add properties in the order in which they appear
+ // in the query. Gives predictable sql/properties for
+ // use with SqlSelect type queries.
+
+ // Also note that this can include transient properties.
+ // This makes sense for transient properties used to
+ // hold sum() count() type values (with SqlSelect)
+ Iterator it = queryProps.getSelectProperties();
+ while (it.hasNext()) {
+ String propName = it.next();
+ if (propName.length() > 0) {
+ addProperty(selectProps, desc, queryProps, propName);
+ }
+ }
+
+ return selectProps;
+ }
+
+ private SqlTreeProperties getBaseSelect(BeanDescriptor> desc, OrmQueryProperties queryProps) {
+
+ boolean partial = queryProps != null && !queryProps.allProperties();
+ if (partial) {
+ return getBaseSelectPartial(desc, queryProps);
+ }
+
+ SqlTreeProperties selectProps = new SqlTreeProperties();
+
+ // normal simple properties of the bean
+ selectProps.add(desc.propertiesBaseScalar());
+ selectProps.add(desc.propertiesBaseCompound());
+ selectProps.add(desc.propertiesEmbedded());
+
+ BeanPropertyAssocOne>[] propertiesOne = desc.propertiesOne();
+ for (int i = 0; i < propertiesOne.length; i++) {
+ if (queryProps != null && queryProps.isIncludedBeanJoin(propertiesOne[i].getName())) {
+ // if it is a joined bean... then don't add the property
+ // as it will have its own entire Node in the SqlTree
+ } else {
+ selectProps.add(propertiesOne[i]);
+ }
+ }
+
+ selectProps.setTableJoins(desc.tableJoins());
+
+ InheritInfo inheritInfo = desc.getInheritInfo();
+ if (inheritInfo != null) {
+ // add sub type properties
+ inheritInfo.addChildrenProperties(selectProps);
+
+ }
+ return selectProps;
+ }
+
+ /**
+ * Return true if this many node should be included in the query.
+ */
+ private boolean isIncludeMany(String prefix, String propName, BeanPropertyAssocMany> manyProp) {
+
+ if (queryDetail.isJoinsEmpty()) {
+ return false;
+ }
+
+ if (queryDetail.includes(propName)) {
+
+ if (manyProperty != null) {
+ // only one many associated allowed to be included in fetch
+ if (logger.isDebugEnabled()) {
+ String msg = "Not joining [" + propName + "] as already joined to a Many[" + manyProperty
+ + "].";
+ logger.debug(msg);
+ }
+ return false;
+ }
+
+ manyProperty = manyProp;
+ manyPropertyName = propName;
+ summary.append(" +many:").append(propName);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Test to see if we are including this node into the query.
+ *
+ * Return true if this node is FULLY included resulting in table join. If the
+ * node is not included but its parent has been included then a "bean proxy"
+ * is added and false is returned.
+ *
+ */
+ private boolean isIncludeBean(String prefix, BeanPropertyAssocOne> prop) {
+
+ if (queryDetail.includes(prefix)) {
+ // explicitly included
+ summary.append(", ").append(prefix);
+ String[] splitNames = SplitName.split(prefix);
+ queryDetail.includeBeanJoin(splitNames[0], splitNames[1]);
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Takes the select includes and the predicates includes and determines the
+ * extra joins required to support the predicates (that are not already
+ * supported by the select includes).
+ *
+ * This returns ONLY the leaves. The joins for the leaves
+ *
+ */
+ private static class IncludesDistiller {
+
+ private final Set selectIncludes;
+ private final Set predicateIncludes;
+
+ /**
+ * Contains the 'root' extra joins. We only return the roots back.
+ */
+ private final Map joinRegister = new HashMap();
+
+ /**
+ * Register of all the extra join nodes.
+ */
+ private final Map rootRegister = new HashMap();
private final BeanDescriptor> desc;
- private final OrmQueryDetail queryDetail;
-
- private final StringBuilder summary = new StringBuilder();
-
- private final CQueryPredicates predicates;
-
- private final boolean subQuery;
-
- /**
- * Property if resultSet contains master and detail rows.
- */
- private BeanPropertyAssocMany> manyProperty;
-
- private String manyPropertyName;
-
- private final SqlTreeAlias alias;
-
- private final DefaultDbSqlContext ctx;
-
- private final HashSet selectIncludes = new HashSet();
-
- private final ManyWhereJoins manyWhereJoins;
-
- private final TableJoin includeJoin;
-
- private final boolean rawSql;
-
- /**
- * Construct for RawSql query.
- */
- public SqlTreeBuilder(OrmQueryRequest> request, CQueryPredicates predicates, OrmQueryDetail queryDetail) {
-
- this.rawSql = true;
- this.desc = request.getBeanDescriptor();
- this.query = null;
- this.subQuery = false;
- this.queryDetail = queryDetail;
- this.predicates = predicates;
-
- this.includeJoin = null;
- this.manyWhereJoins = null;
- this.alias = null;
- this.ctx = null;
- }
-
- /**
- * The predicates are used to determine if 'extra' joins are required to
- * support the where and/or order by clause. If so these extra joins are
- * added to the root node.
- */
- public SqlTreeBuilder(String tableAliasPlaceHolder, String columnAliasPrefix, OrmQueryRequest> request, CQueryPredicates predicates) {
-
- this.rawSql = false;
- this.desc = request.getBeanDescriptor();
- this.query = request.getQuery();
-
- this.subQuery = Type.SUBQUERY.equals(query.getType());
- this.includeJoin = query.getIncludeTableJoin();
- this.manyWhereJoins = query.getManyWhereJoins();
- this.queryDetail = query.getDetail();
-
- this.predicates = predicates;
- this.alias = new SqlTreeAlias(request.getBeanDescriptor().getBaseTableAlias());
- this.ctx = new DefaultDbSqlContext(alias, tableAliasPlaceHolder, columnAliasPrefix, !subQuery);
+ private IncludesDistiller(BeanDescriptor> desc, Set selectIncludes,
+ Set predicateIncludes) {
+ this.desc = desc;
+ this.selectIncludes = selectIncludes;
+ this.predicateIncludes = predicateIncludes;
}
/**
- * Build based on the includes and using the BeanJoinTree.
- */
- public SqlTree build() {
-
- SqlTree sqlTree = new SqlTree();
-
- summary.append(desc.getName());
-
- // build the appropriate chain of SelectAdapter's
- buildRoot(desc, sqlTree);
-
- // build the actual String
- SqlTreeNode rootNode = sqlTree.getRootNode();
-
- if (!rawSql){
- sqlTree.setSelectSql(buildSelectClause(rootNode));
- sqlTree.setFromSql(buildFromClause(rootNode));
- sqlTree.setInheritanceWhereSql(buildWhereClause(rootNode));
- sqlTree.setEncryptedProps(ctx.getEncryptedProps());
- }
- sqlTree.setIncludes(queryDetail.getIncludes());
- sqlTree.setSummary(summary.toString());
-
- if (manyPropertyName != null){
- ElPropertyValue manyPropEl = desc.getElGetValue(manyPropertyName);
- sqlTree.setManyProperty(manyProperty, manyPropertyName, manyPropEl);
- }
-
- return sqlTree;
- }
-
- private String buildSelectClause(SqlTreeNode rootNode) {
-
- if (rawSql){
- return "Not Used";
- }
- rootNode.appendSelect(ctx, subQuery);
-
- String selectSql = ctx.getContent();
-
- // trim off the first comma
- if (selectSql.length() >= SqlTreeNode.COMMA.length()) {
- selectSql = selectSql.substring(SqlTreeNode.COMMA.length());
- }
-
- return selectSql;
- }
-
- private String buildWhereClause(SqlTreeNode rootNode) {
-
- if (rawSql){
- return "Not Used";
- }
- rootNode.appendWhere(ctx);
- return ctx.getContent();
- }
-
- private String buildFromClause(SqlTreeNode rootNode) {
-
- if (rawSql){
- return "Not Used";
- }
- rootNode.appendFrom(ctx, false);
- return ctx.getContent();
- }
-
- private void buildRoot(BeanDescriptor> desc, SqlTree sqlTree) {
-
- SqlTreeNode selectRoot = buildSelectChain(null, null, desc, null);
- sqlTree.setRootNode(selectRoot);
-
- if (!rawSql){
- alias.addJoin(queryDetail.getIncludes(), desc);
- alias.addJoin(predicates.getPredicateIncludes(), desc);
- alias.addManyWhereJoins(manyWhereJoins.getJoins());
-
- // build set of table alias
- alias.buildAlias();
-
- predicates.parseTableAlias(alias);
- }
- }
-
- /**
- * Recursively build the query tree depending on what leaves in the tree
- * should be included.
- */
- private SqlTreeNode buildSelectChain(String prefix, BeanPropertyAssoc> prop, BeanDescriptor> desc, List joinList) {
-
- List myJoinList = new ArrayList();
-
- BeanPropertyAssocOne>[] ones = desc.propertiesOne();
- for (int i = 0; i < ones.length; i++) {
- String propPrefix = SplitName.add(prefix, ones[i].getName());
- if (isIncludeBean(propPrefix, ones[i])) {
- selectIncludes.add(propPrefix);
- buildSelectChain(propPrefix, ones[i], ones[i].getTargetDescriptor(), myJoinList);
- }
- }
-
- BeanPropertyAssocMany>[] manys = desc.propertiesMany();
- for (int i = 0; i < manys.length; i++) {
- String propPrefix = SplitName.add(prefix, manys[i].getName());
- if (isIncludeMany(prefix, propPrefix, manys[i])) {
- selectIncludes.add(propPrefix);
- buildSelectChain(propPrefix, manys[i], manys[i].getTargetDescriptor(), myJoinList);
- }
- }
-
- if (prefix == null && !rawSql) {
- addManyWhereJoins(myJoinList);
- }
-
- SqlTreeNode selectNode = buildNode(prefix, prop, desc, myJoinList);
- if (joinList != null) {
- joinList.add(selectNode);
- }
- return selectNode;
- }
-
- /**
- * Add joins used to support where clause predicates on 'many' properties.
+ * Build the collection of extra joins returning just the roots.
*
- * These joins are effectively independent of any fetch joins on 'many' properties.
+ * each root returned here could contain a little tree of joins. This
+ * follows the more natural pattern and allows for forcing outer joins from
+ * a join to a 'many' down through the rest of its tree.
*
*/
- private void addManyWhereJoins(List myJoinList) {
+ private Collection getExtraJoinRootNodes() {
- Set includes = manyWhereJoins.getJoins();
- for (String joinProp : includes) {
-
- BeanPropertyAssoc> beanProperty = (BeanPropertyAssoc>) desc.getBeanPropertyFromPath(joinProp);
- SqlTreeNodeManyWhereJoin nodeJoin = new SqlTreeNodeManyWhereJoin(joinProp, beanProperty);
- myJoinList.add(nodeJoin);
- }
+ String[] extras = findExtras();
+ if (extras.length == 0) {
+ return rootRegister.values();
+ }
+
+ // sort so we process only getting the leaves
+ // excluding nodes between root and the leaf
+ Arrays.sort(extras);
+
+ // reverse order so get the leaves first...
+ for (int i = 0; i < extras.length; i++) {
+ createExtraJoin(extras[i]);
+ }
+
+ return rootRegister.values();
}
- private SqlTreeNode buildNode(String prefix, BeanPropertyAssoc> prop, BeanDescriptor> desc, List myList) {
+ private void createExtraJoin(String includeProp) {
- OrmQueryProperties queryProps = queryDetail.getChunk(prefix, false);
+ SqlTreeNodeExtraJoin extraJoin = createJoinLeaf(includeProp);
+ if (extraJoin != null) {
+ // add the extra join...
- SqlTreeProperties props = getBaseSelect(desc, queryProps);
+ // find root of this extra join... linking back to the
+ // parents (creating the tree) as it goes.
+ SqlTreeNodeExtraJoin root = findExtraJoinRoot(includeProp, extraJoin);
- if (prefix == null) {
- buildExtraJoins(desc, myList);
- return new SqlTreeNodeRoot(desc, props, myList, !subQuery, includeJoin);
-
- } else if (prop instanceof BeanPropertyAssocMany>) {
- return new SqlTreeNodeManyRoot(prefix, (BeanPropertyAssocMany>) prop, props, myList);
-
- } else {
- return new SqlTreeNodeBean(prefix, prop, props, myList, true);
- }
+ // register the root because these are the only ones we
+ // return back.
+ rootRegister.put(root.getName(), root);
+ }
}
/**
- * Build extra joins to support properties used in where clause but not
- * already in select clause.
+ * Create a SqlTreeNodeExtraJoin, register and return it.
*/
- private void buildExtraJoins(BeanDescriptor> desc, List myList) {
+ private SqlTreeNodeExtraJoin createJoinLeaf(String propertyName) {
- if (rawSql){
- return;
- }
-
- Set predicateIncludes = predicates.getPredicateIncludes();
-
- if (predicateIncludes == null) {
- return;
- }
-
- // Note includes - basically means joins.
- // The selectIncludes is the set of joins that are required to support
- // the 'select' part of the query. We may need to add other joins to
- // support the predicates or order by clauses.
-
- // remove ManyWhereJoins from the predicateIncludes
- predicateIncludes.removeAll(manyWhereJoins.getJoins());
-
- // look for predicateIncludes that are not in selectIncludes and add
- // them as extra joins to the query
- IncludesDistiller extraJoinDistill = new IncludesDistiller(desc, selectIncludes, predicateIncludes);
-
- Collection extraJoins = extraJoinDistill.getExtraJoinRootNodes();
- if (extraJoins.isEmpty()) {
- return;
-
- } else {
- // add extra joins required to support predicates
- // and/or order by clause
- Iterator it = extraJoins.iterator();
- while (it.hasNext()) {
- SqlTreeNodeExtraJoin extraJoin = it.next();
- myList.add(extraJoin);
-
- if (extraJoin.isManyJoin()) {
- // as we are now going to join to the many then we need
- // to add the distinct to the sql query to stop duplicate
- // rows...
- query.setDistinct(true);
- }
- }
+ ElPropertyValue elGetValue = desc.getElGetValue(propertyName);
+
+ if (elGetValue == null) {
+ // this can occur for master detail queries
+ // with concatenated keys (so not an error now)
+ return null;
+ }
+ BeanProperty beanProperty = elGetValue.getBeanProperty();
+ if (beanProperty instanceof BeanPropertyAssoc>) {
+ BeanPropertyAssoc> assocProp = (BeanPropertyAssoc>) beanProperty;
+ if (assocProp.isEmbedded()) {
+ // no extra join required for embedded beans
+ return null;
}
+ SqlTreeNodeExtraJoin extraJoin = new SqlTreeNodeExtraJoin(propertyName, assocProp);
+ joinRegister.put(propertyName, extraJoin);
+ return extraJoin;
+ }
+ return null;
}
/**
- * A subQuery has slightly different rules in that it just generates SQL
- * (into the where clause) and its properties are not required to read the
- * resultSet etc.
+ * Find the root the this extra join tree.
*
- * This means it can included individual properties of an embedded bean.
+ * This may need to create a parent join implicitly if a predicate join
+ * 'skips' a level. e.g. where details.user.id = 1 (maybe join to details is
+ * not specified and is implicitly created.
*
*/
- private void addPropertyToSubQuery(SqlTreeProperties selectProps, BeanDescriptor> desc, OrmQueryProperties queryProps, String propName) {
+ private SqlTreeNodeExtraJoin findExtraJoinRoot(String includeProp,
+ SqlTreeNodeExtraJoin childJoin) {
- BeanProperty p = desc.findBeanProperty(propName);
- if (p == null) {
- logger.error("property [" + propName + "]not found on " + desc + " for query - excluding it.");
+ int dotPos = includeProp.lastIndexOf('.');
+ if (dotPos == -1) {
+ // no parent possible(parent is root)
+ return childJoin;
- }
- else if (p instanceof BeanPropertyAssoc> && p.isEmbedded()) {
- // if the property is embedded we need to lookup the real column name
- int pos = propName.indexOf(".");
- if (pos > -1) {
- String name = propName.substring(pos + 1);
- p = ((BeanPropertyAssoc>) p).getTargetDescriptor().findBeanProperty(name);
- }
+ } else {
+ // look in register ...
+ String parentPropertyName = includeProp.substring(0, dotPos);
+ if (selectIncludes.contains(parentPropertyName)) {
+ // parent already handled by select
+ return childJoin;
}
- selectProps.add(p);
- }
-
- private void addProperty(SqlTreeProperties selectProps, BeanDescriptor> desc, OrmQueryProperties queryProps, String propName) {
-
- if (subQuery) {
- addPropertyToSubQuery(selectProps, desc, queryProps, propName);
- return;
+ SqlTreeNodeExtraJoin parentJoin = joinRegister.get(parentPropertyName);
+ if (parentJoin == null) {
+ // we need to create this the parent implicitly...
+ parentJoin = createJoinLeaf(parentPropertyName);
}
- int basePos = propName.indexOf('.');
- if (basePos > -1) {
- // property on an embedded bean. Embedded beans do not yet
- // support being partially populated so we include the
- // 'base' property and make sure we only do that once
- String baseName = propName.substring(0, basePos);
-
- // make sure we only included the base/embedded bean once
- if (!selectProps.containsProperty(baseName)) {
- BeanProperty p = desc.findBeanProperty(baseName);
- if (p == null) {
- String m = "property [" + propName + "] not found on " + desc + " for query - excluding it.";
- logger.error(m);
-
- } else if (p.isEmbedded()) {
- // add the embedded bean (and effectively
- // all its properties)
- selectProps.add(p);
- // also make sure it is added to included properties
- // to avoid unnecessary lazy loading
- selectProps.getIncludedProperties().add(baseName);
-
- } else {
- String m = "property [" + p.getFullBeanName()
- + "] expected to be an embedded bean for query - excluding it.";
- logger.error(m);
- }
- }
-
- } else {
- // find the property including searching the
- // sub class hierarchy if required
- BeanProperty p = desc.findBeanProperty(propName);
- if (p == null) {
- logger.error("property [" + propName + "] not found on " + desc
- + " for query - excluding it.");
-
- } else if (p.isId()) {
- // do not bother to include id for normal queries as the
- // id is always added (except for subQueries)
-
- } else if (p instanceof BeanPropertyAssoc>) {
- // need to check if this property should be
- // excluded. This occurs when this property is
- // included as a bean join. With a bean join
- // the property should be excluded as the bean
- // join has its own node in the SqlTree.
- if (!queryProps.isIncludedBeanJoin(p.getName())) {
- // include the property... which basically
- // means include the foreign key column(s)
- selectProps.add(p);
- }
- } else {
- selectProps.add(p);
- }
- }
- }
-
- private SqlTreeProperties getBaseSelectPartial(BeanDescriptor> desc, OrmQueryProperties queryProps) {
-
- SqlTreeProperties selectProps = new SqlTreeProperties();
- selectProps.setReadOnly(queryProps.isReadOnly());
- selectProps.setIncludedProperties(queryProps.getAllIncludedProperties());
-
- // add properties in the order in which they appear
- // in the query. Gives predictable sql/properties for
- // use with SqlSelect type queries.
-
- // Also note that this can include transient properties.
- // This makes sense for transient properties used to
- // hold sum() count() type values (with SqlSelect)
- Iterator it = queryProps.getSelectProperties();
- while (it.hasNext()) {
- String propName = it.next();
- if (propName.length() > 0) {
- addProperty(selectProps, desc, queryProps, propName);
- }
- }
-
- return selectProps;
- }
-
- private SqlTreeProperties getBaseSelect(BeanDescriptor> desc, OrmQueryProperties queryProps) {
-
- boolean partial = queryProps != null && !queryProps.allProperties();
- if (partial) {
- return getBaseSelectPartial(desc, queryProps);
- }
-
- SqlTreeProperties selectProps = new SqlTreeProperties();
-
- // normal simple properties of the bean
- selectProps.add(desc.propertiesBaseScalar());
- selectProps.add(desc.propertiesBaseCompound());
- selectProps.add(desc.propertiesEmbedded());
-
- BeanPropertyAssocOne>[] propertiesOne = desc.propertiesOne();
- for (int i = 0; i < propertiesOne.length; i++) {
- if (queryProps != null && queryProps.isIncludedBeanJoin(propertiesOne[i].getName())) {
- // if it is a joined bean... then don't add the property
- // as it will have its own entire Node in the SqlTree
- } else {
- selectProps.add(propertiesOne[i]);
- }
- }
-
- selectProps.setTableJoins(desc.tableJoins());
-
- InheritInfo inheritInfo = desc.getInheritInfo();
- if (inheritInfo != null) {
- // add sub type properties
- inheritInfo.addChildrenProperties(selectProps);
-
- }
- return selectProps;
+ parentJoin.addChild(childJoin);
+ return findExtraJoinRoot(parentPropertyName, parentJoin);
+ }
}
/**
- * Return true if this many node should be included in the query.
+ * Find the extra joins required by predicates and not already taken care of
+ * by the select.
*/
- private boolean isIncludeMany(String prefix, String propName, BeanPropertyAssocMany> manyProp) {
+ private String[] findExtras() {
- if (queryDetail.isJoinsEmpty()) {
- return false;
+ List extras = new ArrayList();
+
+ for (String predProp : predicateIncludes) {
+ if (!selectIncludes.contains(predProp)) {
+ extras.add(predProp);
}
-
- if (queryDetail.includes(propName)) {
-
- if (manyProperty != null) {
- // only one many associated allowed to be included in fetch
- if (logger.isDebugEnabled()) {
- String msg = "Not joining [" + propName + "] as already joined to a Many[" + manyProperty + "].";
- logger.debug(msg);
- }
- return false;
- }
-
- manyProperty = manyProp;
- manyPropertyName = propName;
- summary.append(" +many:").append(propName);
- return true;
- }
- return false;
+ }
+ return extras.toArray(new String[extras.size()]);
}
- /**
- * Test to see if we are including this node into the query.
- *
- * Return true if this node is FULLY included resulting in table join. If
- * the node is not included but its parent has been included then a "bean
- * proxy" is added and false is returned.
- *
- */
- private boolean isIncludeBean(String prefix, BeanPropertyAssocOne> prop) {
-
- if (queryDetail.includes(prefix)) {
- // explicitly included
- summary.append(", ").append(prefix);
- String[] splitNames = SplitName.split(prefix);
- queryDetail.includeBeanJoin(splitNames[0], splitNames[1]);
- return true;
- }
-
- return false;
- }
-
- /**
- * Takes the select includes and the predicates includes and determines the
- * extra joins required to support the predicates (that are not already
- * supported by the select includes).
- *
- * This returns ONLY the leaves. The joins for the leaves
- *
- */
- private static class IncludesDistiller {
-
- private final Set selectIncludes;
- private final Set predicateIncludes;
-
- /**
- * Contains the 'root' extra joins. We only return the roots back.
- */
- private final Map joinRegister = new HashMap();
-
- /**
- * Register of all the extra join nodes.
- */
- private final Map rootRegister = new HashMap();
-
- private final BeanDescriptor> desc;
-
- private IncludesDistiller(BeanDescriptor> desc, Set selectIncludes, Set predicateIncludes) {
- this.desc = desc;
- this.selectIncludes = selectIncludes;
- this.predicateIncludes = predicateIncludes;
- }
-
- /**
- * Build the collection of extra joins returning just the roots.
- *
- * each root returned here could contain a little tree of joins. This
- * follows the more natural pattern and allows for forcing outer joins
- * from a join to a 'many' down through the rest of its tree.
- *
- */
- private Collection getExtraJoinRootNodes() {
-
- String[] extras = findExtras();
- if (extras.length == 0) {
- return rootRegister.values();
- }
-
- // sort so we process only getting the leaves
- // excluding nodes between root and the leaf
- Arrays.sort(extras);
-
- // reverse order so get the leaves first...
- for (int i = 0; i < extras.length; i++) {
- createExtraJoin(extras[i]);
- }
-
- return rootRegister.values();
- }
-
- private void createExtraJoin(String includeProp) {
-
- SqlTreeNodeExtraJoin extraJoin = createJoinLeaf(includeProp);
- if (extraJoin != null) {
- // add the extra join...
-
- // find root of this extra join... linking back to the
- // parents (creating the tree) as it goes.
- SqlTreeNodeExtraJoin root = findExtraJoinRoot(includeProp, extraJoin);
-
- // register the root because these are the only ones we
- // return back.
- rootRegister.put(root.getName(), root);
- }
- }
-
- /**
- * Create a SqlTreeNodeExtraJoin, register and return it.
- */
- private SqlTreeNodeExtraJoin createJoinLeaf(String propertyName) {
-
- ElPropertyValue elGetValue = desc.getElGetValue(propertyName);
-
- if (elGetValue == null) {
- // this can occur for master detail queries
- // with concatenated keys (so not an error now)
- return null;
- }
- BeanProperty beanProperty = elGetValue.getBeanProperty();
- if (beanProperty instanceof BeanPropertyAssoc>) {
- BeanPropertyAssoc> assocProp = (BeanPropertyAssoc>) beanProperty;
- if (assocProp.isEmbedded()) {
- // no extra join required for embedded beans
- return null;
- }
- SqlTreeNodeExtraJoin extraJoin = new SqlTreeNodeExtraJoin(propertyName, assocProp);
- joinRegister.put(propertyName, extraJoin);
- return extraJoin;
- }
- return null;
- }
-
- /**
- * Find the root the this extra join tree.
- *
- * This may need to create a parent join implicitly if a predicate join
- * 'skips' a level. e.g. where details.user.id = 1 (maybe join to
- * details is not specified and is implicitly created.
- *
- */
- private SqlTreeNodeExtraJoin findExtraJoinRoot(String includeProp, SqlTreeNodeExtraJoin childJoin) {
-
- int dotPos = includeProp.lastIndexOf('.');
- if (dotPos == -1) {
- // no parent possible(parent is root)
- return childJoin;
-
- } else {
- // look in register ...
- String parentPropertyName = includeProp.substring(0, dotPos);
- if (selectIncludes.contains(parentPropertyName)) {
- // parent already handled by select
- return childJoin;
- }
-
- SqlTreeNodeExtraJoin parentJoin = joinRegister.get(parentPropertyName);
- if (parentJoin == null) {
- // we need to create this the parent implicitly...
- parentJoin = createJoinLeaf(parentPropertyName);
- }
-
- parentJoin.addChild(childJoin);
- return findExtraJoinRoot(parentPropertyName, parentJoin);
- }
- }
-
- /**
- * Find the extra joins required by predicates and not already taken
- * care of by the select.
- */
- private String[] findExtras() {
-
- List extras = new ArrayList();
-
- for (String predProp : predicateIncludes) {
- if (!selectIncludes.contains(predProp)) {
- extras.add(predProp);
- }
- }
- return extras.toArray(new String[extras.size()]);
- }
-
- }
+ }
}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNode.java b/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNode.java
index a9abb27ae..838176cc7 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNode.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNode.java
@@ -8,48 +8,40 @@ import com.avaje.ebeaninternal.server.deploy.DbSqlContext;
public interface SqlTreeNode {
- /**
- * the new line character used.
- *
- * Note that this is removed for logging sql to the transaction log.
- *
- */
- public static final char NEW_LINE = '\n';
+ public static final String PERIOD = ".";
- public static final String PERIOD = ".";
+ public static final String COMMA = ", ";
- public static final String COMMA = ", ";
+ public static final int NORMAL = 0;
+ public static final int SHARED = 1;
+ public static final int READONLY = 2;
- public static final int NORMAL = 0;
- public static final int SHARED = 1;
- public static final int READONLY = 2;
-
- public void buildSelectExpressionChain(List selectChain);
+ public void buildSelectExpressionChain(List selectChain);
- /**
- * Append the required column information to the SELECT part of the sql
- * statement.
- */
- public void appendSelect(DbSqlContext ctx, boolean subQuery);
+ /**
+ * Append the required column information to the SELECT part of the sql
+ * statement.
+ */
+ public void appendSelect(DbSqlContext ctx, boolean subQuery);
- /**
- * Append to the FROM part of the sql.
- */
- public void appendFrom(DbSqlContext ctx, boolean forceOuterJoin);
+ /**
+ * Append to the FROM part of the sql.
+ */
+ public void appendFrom(DbSqlContext ctx, boolean forceOuterJoin);
- /**
- * Append any where predicates for inheritance.
- */
- public void appendWhere(DbSqlContext ctx);
+ /**
+ * Append any where predicates for inheritance.
+ */
+ public void appendWhere(DbSqlContext ctx);
- /**
- * Load the appropriate information from the SqlSelectReader.
- *
- * At a high level this actually controls the reading of the data from the
- * jdbc resultSet and putting it into the bean etc.
- *
- *
- */
- public void load(DbReadContext ctx, Object parentBean) throws SQLException;
+ /**
+ * Load the appropriate information from the SqlSelectReader.
+ *
+ * At a high level this actually controls the reading of the data from the
+ * jdbc resultSet and putting it into the bean etc.
+ *
+ *
+ */
+ public void load(DbReadContext ctx, Object parentBean) throws SQLException;
}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeBean.java b/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeBean.java
index 234a2bd3e..b356b676c 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeBean.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeBean.java
@@ -27,496 +27,490 @@ import com.avaje.ebeaninternal.server.lib.util.StringHelper;
*/
public class SqlTreeNodeBean implements SqlTreeNode {
- private static final SqlTreeNode[] NO_CHILDREN = new SqlTreeNode[0];
+ private static final SqlTreeNode[] NO_CHILDREN = new SqlTreeNode[0];
- final BeanDescriptor> desc;
-
- final IdBinder idBinder;
+ final BeanDescriptor> desc;
- /**
- * The children which will be other SelectBean or SelectProxyBean.
- */
- final SqlTreeNode[] children;
+ final IdBinder idBinder;
- final boolean readOnlyLeaf;
-
- /**
- * Set to true if this is a partial object fetch.
- */
- final boolean partialObject;
-
- /**
- * The set of properties explicitly included in the query.
- * We actually add the manyProp names to this as they are
- * references/proxies we add via createListProxies().
- */
- final Set partialProps;
-
- /**
- * The hash of the partialProps (calculate once).
- */
- final int partialHash;
-
- final BeanProperty[] properties;
-
- /**
- * Extra where clause added by Where annotation on associated many.
- */
- final String extraWhere;
-
- final BeanPropertyAssoc> nodeBeanProp;
+ /**
+ * The children which will be other SelectBean or SelectProxyBean.
+ */
+ final SqlTreeNode[] children;
- final TableJoin[] tableJoins;
+ final boolean readOnlyLeaf;
- /**
- * False if report bean and has no id property.
- */
- final boolean readId;
-
- final boolean disableLazyLoad;
-
- final InheritInfo inheritInfo;
-
- final String prefix;
-
- final Set includedProps;
+ /**
+ * Set to true if this is a partial object fetch.
+ */
+ final boolean partialObject;
- final Map pathMap;
-
- public SqlTreeNodeBean(String prefix, BeanPropertyAssoc> beanProp,
- SqlTreeProperties props, List myChildren, boolean withId) {
-
- this(prefix, beanProp, beanProp.getTargetDescriptor(),props, myChildren, withId);
- }
-
- /**
- * Create with the appropriate node.
- */
- public SqlTreeNodeBean(String prefix, BeanPropertyAssoc> beanProp, BeanDescriptor> desc,
- SqlTreeProperties props, List myChildren, boolean withId) {
+ /**
+ * The set of properties explicitly included in the query. We actually add the
+ * manyProp names to this as they are references/proxies we add via
+ * createListProxies().
+ */
+ final Set partialProps;
- this.prefix = prefix;
- this.nodeBeanProp = beanProp;
- this.desc = desc;
- this.inheritInfo = desc.getInheritInfo();
- this.extraWhere = (beanProp == null) ? null : beanProp.getExtraWhere();
-
- this.idBinder = desc.getIdBinder();
-
- // the bean has an Id property and we want to use it
- this.readId = withId && (desc.propertiesId().length > 0);
- this.disableLazyLoad = !readId || desc.isSqlSelectBased();
-
- this.tableJoins = props.getTableJoins();
-
- this.partialObject = props.isPartialObject();
- this.partialProps = props.getIncludedProperties();
- this.partialHash = partialObject ? partialProps.hashCode() : 0;
-
- this.readOnlyLeaf = props.isReadOnly();
-
- this.properties = props.getProps();
-
- if (partialObject){
- // merge the explicit partialProps with the implicitly added
- // list proxies (that are added by createListProxies()) to get
- // the full set of 'loaded' properties for this bean.
- includedProps = LoadedPropertiesCache.get(partialHash, partialProps, desc);
- } else {
- includedProps = null;
- }
-
- if (myChildren == null) {
- children = NO_CHILDREN;
- } else {
- children = myChildren.toArray(new SqlTreeNode[myChildren.size()]);
- }
-
- pathMap = createPathMap(prefix, desc);
- }
-
- private Map createPathMap(String prefix, BeanDescriptor> desc) {
-
- BeanPropertyAssocMany>[] manys = desc.propertiesMany();
-
- HashMap m = new HashMap();
- for (int i = 0; i < manys.length; i++) {
- String name = manys[i].getName();
- m.put(name, getPath(prefix, name));
- }
-
- return m;
- }
-
- private String getPath(String prefix, String propertyName){
- if (prefix == null){
- return propertyName;
- } else {
- return prefix+"."+propertyName;
- }
- }
+ /**
+ * The hash of the partialProps (calculate once).
+ */
+ final int partialHash;
- protected void postLoad(DbReadContext cquery, Object loadedBean, Object id) {
- }
+ final BeanProperty[] properties;
- public void buildSelectExpressionChain(List selectChain){
- if (readId){
- idBinder.buildSelectExpressionChain(prefix, selectChain);
- }
- for (int i = 0, x = properties.length; i < x; i++) {
- properties[i].buildSelectExpressionChain(prefix, selectChain);
- }
- // recursively continue reading...
- for (int i = 0; i < children.length; i++) {
- // read each child... and let them set their
- // values back to this localBean
- children[i].buildSelectExpressionChain(selectChain);
- }
- }
-
- /**
- * read the properties from the resultSet.
- */
- public void load(DbReadContext ctx, Object parentBean) throws SQLException {
+ /**
+ * Extra where clause added by Where annotation on associated many.
+ */
+ final String extraWhere;
- // bean already existing in the persistence context
- Object contextBean = null;
-
- Class> localType;
- BeanDescriptor> localDesc;
- IdBinder localIdBinder;
- Object localBean;
-
- if (inheritInfo != null){
- InheritInfo localInfo = inheritInfo.readType(ctx);
- if (localInfo == null){
- // the bean must be null
- localIdBinder = idBinder;
- localBean = null;
- localType = null;
- localDesc = desc;
- } else {
- localBean = localInfo.createBean(ctx.isVanillaMode());
- localType = localInfo.getType();
- localIdBinder = localInfo.getIdBinder();
- localDesc = localInfo.getBeanDescriptor();
- }
-
- } else {
- localType = null;
- localDesc = desc;
- localBean = desc.createBean(ctx.isVanillaMode());
- localIdBinder = idBinder;
- }
-
- Mode queryMode = ctx.getQueryMode();
-
- PersistenceContext persistenceContext = ctx.getPersistenceContext();
-
- Object id = null;
- if (!readId){
- // report type bean... or perhaps excluding the id for SqlSelect?
-
- } else {
- id = localIdBinder.readSet(ctx, localBean);
- if (id == null){
- // bean must be null...
- localBean = null;
- } else {
- // check the PersistenceContext to see if the bean already exists
- contextBean = persistenceContext.putIfAbsent(id, localBean);
- if (contextBean == null){
- // bean just added to the persistenceContext
- contextBean = localBean;
- } else {
- // bean already exists in persistenceContext
- if (queryMode.isLoadContextBean()){
- // refresh it anyway (lazy loading for example)
- localBean = contextBean;
- if (localBean instanceof EntityBean){
- // temporarily turn off interception during load
- ((EntityBean)localBean)._ebean_getIntercept().setIntercepting(false);
- }
- } else {
- // ignore the DB data...
- localBean = null;
- }
- }
- }
- }
+ final BeanPropertyAssoc> nodeBeanProp;
- ctx.setCurrentPrefix(prefix, pathMap);
-
- ctx.propagateState(localBean);
-
- SqlBeanLoad sqlBeanLoad = new SqlBeanLoad(ctx, localType, localBean, queryMode);
-
- if (inheritInfo == null){
- // normal behaviour with no inheritance
- for (int i = 0, x = properties.length; i < x; i++) {
- properties[i].load(sqlBeanLoad);
- }
-
- } else {
- // take account of inheritance and due to subclassing approach
- // need to get a 'local' version of the property
- for (int i = 0, x = properties.length; i < x; i++) {
- // get a local version of the BeanProperty
- BeanProperty p = localDesc.getBeanProperty(properties[i].getName());
- if (p != null){
- p.load(sqlBeanLoad);
- } else {
- properties[i].loadIgnore(ctx);
- }
- }
- }
-
- for (int i = 0, x = tableJoins.length; i < x; i++) {
- tableJoins[i].load(sqlBeanLoad);
- }
+ final TableJoin[] tableJoins;
- boolean lazyLoadMany = false;
- if (localBean == null && queryMode.equals(Mode.LAZYLOAD_MANY)){
- // batch lazy load many into existing contextBean
- localBean = contextBean;
- lazyLoadMany = true;
- }
-
- // recursively continue reading...
- for (int i = 0; i < children.length; i++) {
- // read each child... and let them set their
- // values back to this localBean
- children[i].load(ctx, localBean);
- }
+ /**
+ * False if report bean and has no id property.
+ */
+ final boolean readId;
- if (lazyLoadMany){
- // special case where we load children
-
- } else if (localBean != null) {
-
- ctx.setCurrentPrefix(prefix, pathMap);
- if (!ctx.isVanillaMode()){
- // only create lazy loading collection proxies
- // when not in vanilla mode
- createListProxies(localDesc, ctx, localBean);
- }
-
- localDesc.postLoad(localBean, includedProps);
+ final boolean disableLazyLoad;
+ final InheritInfo inheritInfo;
+
+ final String prefix;
+
+ final Set includedProps;
+
+ final Map pathMap;
+
+ public SqlTreeNodeBean(String prefix, BeanPropertyAssoc> beanProp, SqlTreeProperties props,
+ List myChildren, boolean withId) {
+
+ this(prefix, beanProp, beanProp.getTargetDescriptor(), props, myChildren, withId);
+ }
+
+ /**
+ * Create with the appropriate node.
+ */
+ public SqlTreeNodeBean(String prefix, BeanPropertyAssoc> beanProp, BeanDescriptor> desc,
+ SqlTreeProperties props, List myChildren, boolean withId) {
+
+ this.prefix = prefix;
+ this.nodeBeanProp = beanProp;
+ this.desc = desc;
+ this.inheritInfo = desc.getInheritInfo();
+ this.extraWhere = (beanProp == null) ? null : beanProp.getExtraWhere();
+
+ this.idBinder = desc.getIdBinder();
+
+ // the bean has an Id property and we want to use it
+ this.readId = withId && (desc.propertiesId().length > 0);
+ this.disableLazyLoad = !readId || desc.isSqlSelectBased();
+
+ this.tableJoins = props.getTableJoins();
+
+ this.partialObject = props.isPartialObject();
+ this.partialProps = props.getIncludedProperties();
+ this.partialHash = partialObject ? partialProps.hashCode() : 0;
+
+ this.readOnlyLeaf = props.isReadOnly();
+
+ this.properties = props.getProps();
+
+ if (partialObject) {
+ // merge the explicit partialProps with the implicitly added
+ // list proxies (that are added by createListProxies()) to get
+ // the full set of 'loaded' properties for this bean.
+ includedProps = LoadedPropertiesCache.get(partialHash, partialProps, desc);
+ } else {
+ includedProps = null;
+ }
+
+ if (myChildren == null) {
+ children = NO_CHILDREN;
+ } else {
+ children = myChildren.toArray(new SqlTreeNode[myChildren.size()]);
+ }
+
+ pathMap = createPathMap(prefix, desc);
+ }
+
+ private Map createPathMap(String prefix, BeanDescriptor> desc) {
+
+ BeanPropertyAssocMany>[] manys = desc.propertiesMany();
+
+ HashMap m = new HashMap();
+ for (int i = 0; i < manys.length; i++) {
+ String name = manys[i].getName();
+ m.put(name, getPath(prefix, name));
+ }
+
+ return m;
+ }
+
+ private String getPath(String prefix, String propertyName) {
+ if (prefix == null) {
+ return propertyName;
+ } else {
+ return prefix + "." + propertyName;
+ }
+ }
+
+ protected void postLoad(DbReadContext cquery, Object loadedBean, Object id) {
+ }
+
+ public void buildSelectExpressionChain(List selectChain) {
+ if (readId) {
+ idBinder.buildSelectExpressionChain(prefix, selectChain);
+ }
+ for (int i = 0, x = properties.length; i < x; i++) {
+ properties[i].buildSelectExpressionChain(prefix, selectChain);
+ }
+ // recursively continue reading...
+ for (int i = 0; i < children.length; i++) {
+ // read each child... and let them set their
+ // values back to this localBean
+ children[i].buildSelectExpressionChain(selectChain);
+ }
+ }
+
+ /**
+ * read the properties from the resultSet.
+ */
+ public void load(DbReadContext ctx, Object parentBean) throws SQLException {
+
+ // bean already existing in the persistence context
+ Object contextBean = null;
+
+ Class> localType;
+ BeanDescriptor> localDesc;
+ IdBinder localIdBinder;
+ Object localBean;
+
+ if (inheritInfo != null) {
+ InheritInfo localInfo = inheritInfo.readType(ctx);
+ if (localInfo == null) {
+ // the bean must be null
+ localIdBinder = idBinder;
+ localBean = null;
+ localType = null;
+ localDesc = desc;
+ } else {
+ localBean = localInfo.createBean(ctx.isVanillaMode());
+ localType = localInfo.getType();
+ localIdBinder = localInfo.getIdBinder();
+ localDesc = localInfo.getBeanDescriptor();
+ }
+
+ } else {
+ localType = null;
+ localDesc = desc;
+ localBean = desc.createBean(ctx.isVanillaMode());
+ localIdBinder = idBinder;
+ }
+
+ Mode queryMode = ctx.getQueryMode();
+
+ PersistenceContext persistenceContext = ctx.getPersistenceContext();
+
+ Object id = null;
+ if (!readId) {
+ // report type bean... or perhaps excluding the id for SqlSelect?
+
+ } else {
+ id = localIdBinder.readSet(ctx, localBean);
+ if (id == null) {
+ // bean must be null...
+ localBean = null;
+ } else {
+ // check the PersistenceContext to see if the bean already exists
+ contextBean = persistenceContext.putIfAbsent(id, localBean);
+ if (contextBean == null) {
+ // bean just added to the persistenceContext
+ contextBean = localBean;
+ } else {
+ // bean already exists in persistenceContext
+ if (queryMode.isLoadContextBean()) {
+ // refresh it anyway (lazy loading for example)
+ localBean = contextBean;
if (localBean instanceof EntityBean) {
- EntityBeanIntercept ebi = ((EntityBean)localBean)._ebean_getIntercept();
- ebi.setPersistenceContext(persistenceContext);
- ebi.setLoadedProps(includedProps);
- if (Mode.LAZYLOAD_BEAN.equals(queryMode)) {
- // Lazy Load does not reset the dirty state
- ebi.setLoadedLazy();
- } else {
- // normal bean loading
- ebi.setLoaded();
- }
-
- if (partialObject) {
- ctx.register(null, ebi);
- }
-
- if (disableLazyLoad) {
- // bean does not have an Id or is SqlSelect based
- ebi.setDisableLazyLoad(true);
- }
- if (ctx.isAutoFetchProfiling()) {
- // collect autofetch profiling for this bean...
- ctx.profileBean(ebi, prefix);
- }
+ // temporarily turn off interception during load
+ ((EntityBean) localBean)._ebean_getIntercept().setIntercepting(false);
}
-
- }
- if (parentBean != null && contextBean != null) {
- // set this back to the parentBean
- nodeBeanProp.setValue(parentBean, contextBean);
- }
+ } else {
+ // ignore the DB data...
+ localBean = null;
+ }
+ }
+ }
+ }
- if (!readId){
- // a bean with no Id (never found in context)
- postLoad(ctx, localBean, id);
-
- } else {
- // return the contextBean which is either the localBean
- // read from the resultSet and put into the context OR
- // the 'matching' bean that already existed in the context
- postLoad(ctx, contextBean, id);
- }
- }
+ ctx.setCurrentPrefix(prefix, pathMap);
- /**
- * Create lazy loading proxies for the Many's except for the one that is
- * included in the actual query.
- */
- private void createListProxies(BeanDescriptor> localDesc, DbReadContext ctx, Object localBean) {
-
- BeanPropertyAssocMany> fetchedMany = ctx.getManyProperty();
+ ctx.propagateState(localBean);
- // load the List/Set/Map proxy objects (deferred fetching of lists)
- BeanPropertyAssocMany>[] manys = localDesc.propertiesMany();
- for (int i = 0; i < manys.length; i++) {
+ SqlBeanLoad sqlBeanLoad = new SqlBeanLoad(ctx, localType, localBean, queryMode);
- if (fetchedMany != null && fetchedMany.equals(manys[i])) {
- // this many property is included in the query...
- // it is being loaded with real row data (result[1])
- } else {
- // create a proxy for the many (deferred fetching)
- BeanCollection> ref = manys[i].createReferenceIfNull(localBean);
- if (ref != null){
- ctx.register(manys[i].getName(), ref);
- }
- }
- }
- }
+ if (inheritInfo == null) {
+ // normal behavior with no inheritance
+ for (int i = 0, x = properties.length; i < x; i++) {
+ properties[i].load(sqlBeanLoad);
+ }
- /**
- * Append the property columns to the buffer.
- */
- public void appendSelect(DbSqlContext ctx, boolean subQuery) {
-
- ctx.pushJoin(prefix);
- ctx.pushTableAlias(prefix);
+ } else {
+ // take account of inheritance and due to subclassing approach
+ // need to get a 'local' version of the property
+ for (int i = 0, x = properties.length; i < x; i++) {
+ // get a local version of the BeanProperty
+ BeanProperty p = localDesc.getBeanProperty(properties[i].getName());
+ if (p != null) {
+ p.load(sqlBeanLoad);
+ } else {
+ properties[i].loadIgnore(ctx);
+ }
+ }
+ }
- if (nodeBeanProp != null) {
- ctx.append(NEW_LINE).append(" ");
- }
-
- if (!subQuery && inheritInfo != null){
- ctx.appendColumn(inheritInfo.getDiscriminatorColumn());
- }
-
- if (readId) {
- appendSelect(ctx, false, idBinder.getProperties());
- }
- appendSelect(ctx, subQuery, properties);
- appendSelectTableJoins(ctx);
+ for (int i = 0, x = tableJoins.length; i < x; i++) {
+ tableJoins[i].load(sqlBeanLoad);
+ }
- for (int i = 0; i < children.length; i++) {
- // read each child... and let them set their
- // values back to this localBean
- children[i].appendSelect(ctx, subQuery);
- }
-
- ctx.popTableAlias();
- ctx.popJoin();
- }
+ boolean lazyLoadMany = false;
+ if (localBean == null && queryMode.equals(Mode.LAZYLOAD_MANY)) {
+ // batch lazy load many into existing contextBean
+ localBean = contextBean;
+ lazyLoadMany = true;
+ }
- private void appendSelectTableJoins(DbSqlContext ctx) {
+ // recursively continue reading...
+ for (int i = 0; i < children.length; i++) {
+ // read each child... and let them set their
+ // values back to this localBean
+ children[i].load(ctx, localBean);
+ }
- String baseAlias = ctx.getTableAlias(prefix);
-
- for (int i = 0; i < tableJoins.length; i++) {
- TableJoin join = tableJoins[i];
+ if (lazyLoadMany) {
+ // special case where we load children
- String alias = baseAlias+i;
+ } else if (localBean != null) {
- ctx.pushSecondaryTableAlias(alias);
- join.appendSelect(ctx, false);
- ctx.popTableAlias();
- }
- }
+ ctx.setCurrentPrefix(prefix, pathMap);
+ if (!ctx.isVanillaMode()) {
+ // only create lazy loading collection proxies
+ // when not in vanilla mode
+ createListProxies(localDesc, ctx, localBean);
+ }
- /**
- * Append the properties to the buffer.
- */
- private void appendSelect(DbSqlContext ctx, boolean subQuery, BeanProperty[] props) {
+ localDesc.postLoad(localBean, includedProps);
- for (int i = 0; i < props.length; i++) {
- props[i].appendSelect(ctx, subQuery);
- }
- }
-
-
- public void appendWhere(DbSqlContext ctx) {
+ if (localBean instanceof EntityBean) {
+ EntityBeanIntercept ebi = ((EntityBean) localBean)._ebean_getIntercept();
+ ebi.setPersistenceContext(persistenceContext);
+ ebi.setLoadedProps(includedProps);
+ if (Mode.LAZYLOAD_BEAN.equals(queryMode)) {
+ // Lazy Load does not reset the dirty state
+ ebi.setLoadedLazy();
+ } else {
+ // normal bean loading
+ ebi.setLoaded();
+ }
- if (inheritInfo != null) {
- if (inheritInfo.isRoot()) {
- // at root of hierarchy so don't bother
- // adding a where clause because we want
- // all the types...
- } else {
- // restrict to this type and
- // sub types of this type.
- if (ctx.length() > 0){
- ctx.append(" and");
- }
- ctx.append(" ").append(ctx.getTableAlias(prefix)).append(".");//tableAlias
- ctx.append(inheritInfo.getWhere()).append(" ");
- }
- }
- if (extraWhere != null){
- if (ctx.length() > 0){
- ctx.append(" and");
- }
- String ta = ctx.getTableAlias(prefix);
- String ew = StringHelper.replaceString(extraWhere, "${ta}", ta);
- ctx.append(" ").append(ew).append(" ");
- }
-
- for (int i = 0; i < children.length; i++) {
- // recursively add to the where clause any
- // fixed predicates (extraWhere etc)
- children[i].appendWhere(ctx);
- }
- }
-
- /**
- * Append to the FROM clause for this node.
- */
- public void appendFrom(DbSqlContext ctx, boolean forceOuterJoin) {
+ if (partialObject) {
+ ctx.register(null, ebi);
+ }
- ctx.pushJoin(prefix);
- ctx.pushTableAlias(prefix);
+ if (disableLazyLoad) {
+ // bean does not have an Id or is SqlSelect based
+ ebi.setDisableLazyLoad(true);
+ }
+ if (ctx.isAutoFetchProfiling()) {
+ // collect autofetch profiling for this bean...
+ ctx.profileBean(ebi, prefix);
+ }
+ }
- forceOuterJoin = appendFromBaseTable(ctx, forceOuterJoin);
-
- for (int i = 0; i < properties.length; i++) {
- // usually nothing... except for 1-1 Exported
- properties[i].appendFrom(ctx, forceOuterJoin);
- }
-
- for (int i = 0; i < children.length; i++) {
- children[i].appendFrom(ctx, forceOuterJoin);
- }
-
- ctx.popTableAlias();
- ctx.popJoin();
- }
-
- /**
- * Join to base table for this node. This includes a join to
- * the intersection table if this is a ManyToMany node.
- */
- public boolean appendFromBaseTable(DbSqlContext ctx, boolean forceOuterJoin) {
-
- if (nodeBeanProp instanceof BeanPropertyAssocMany>){
- BeanPropertyAssocMany> manyProp = (BeanPropertyAssocMany>)nodeBeanProp;
- if (manyProp.isManyToMany()){
-
- String alias = ctx.getTableAlias(prefix);
- String[] split = SplitName.split(prefix);
- String parentAlias = ctx.getTableAlias(split[0]);
- String alias2 = alias+"z_";
-
- TableJoin manyToManyJoin = manyProp.getIntersectionTableJoin();
- manyToManyJoin.addJoin(forceOuterJoin, parentAlias, alias2, ctx);
-
- return nodeBeanProp.addJoin(forceOuterJoin, alias2, alias, ctx);
- }
-
- }
-
- return nodeBeanProp.addJoin(forceOuterJoin, prefix, ctx);
- }
+ }
+ if (parentBean != null && contextBean != null) {
+ // set this back to the parentBean
+ nodeBeanProp.setValue(parentBean, contextBean);
+ }
-
- /**
- * Summary description.
- */
- public String toString() {
- return "SqlTreeNodeBean: " + desc;
- }
+ if (!readId) {
+ // a bean with no Id (never found in context)
+ postLoad(ctx, localBean, id);
+
+ } else {
+ // return the contextBean which is either the localBean
+ // read from the resultSet and put into the context OR
+ // the 'matching' bean that already existed in the context
+ postLoad(ctx, contextBean, id);
+ }
+ }
+
+ /**
+ * Create lazy loading proxies for the Many's except for the one that is
+ * included in the actual query.
+ */
+ private void createListProxies(BeanDescriptor> localDesc, DbReadContext ctx, Object localBean) {
+
+ BeanPropertyAssocMany> fetchedMany = ctx.getManyProperty();
+
+ // load the List/Set/Map proxy objects (deferred fetching of lists)
+ BeanPropertyAssocMany>[] manys = localDesc.propertiesMany();
+ for (int i = 0; i < manys.length; i++) {
+
+ if (fetchedMany != null && fetchedMany.equals(manys[i])) {
+ // this many property is included in the query...
+ // it is being loaded with real row data (result[1])
+ } else {
+ // create a proxy for the many (deferred fetching)
+ BeanCollection> ref = manys[i].createReferenceIfNull(localBean);
+ if (ref != null) {
+ ctx.register(manys[i].getName(), ref);
+ }
+ }
+ }
+ }
+
+ /**
+ * Append the property columns to the buffer.
+ */
+ public void appendSelect(DbSqlContext ctx, boolean subQuery) {
+
+ ctx.pushJoin(prefix);
+ ctx.pushTableAlias(prefix);
+
+ if (!subQuery && inheritInfo != null) {
+ ctx.appendColumn(inheritInfo.getDiscriminatorColumn());
+ }
+
+ if (readId) {
+ appendSelect(ctx, false, idBinder.getProperties());
+ }
+ appendSelect(ctx, subQuery, properties);
+ appendSelectTableJoins(ctx);
+
+ for (int i = 0; i < children.length; i++) {
+ // read each child... and let them set their
+ // values back to this localBean
+ children[i].appendSelect(ctx, subQuery);
+ }
+
+ ctx.popTableAlias();
+ ctx.popJoin();
+ }
+
+ private void appendSelectTableJoins(DbSqlContext ctx) {
+
+ String baseAlias = ctx.getTableAlias(prefix);
+
+ for (int i = 0; i < tableJoins.length; i++) {
+ TableJoin join = tableJoins[i];
+
+ String alias = baseAlias + i;
+
+ ctx.pushSecondaryTableAlias(alias);
+ join.appendSelect(ctx, false);
+ ctx.popTableAlias();
+ }
+ }
+
+ /**
+ * Append the properties to the buffer.
+ */
+ private void appendSelect(DbSqlContext ctx, boolean subQuery, BeanProperty[] props) {
+
+ for (int i = 0; i < props.length; i++) {
+ props[i].appendSelect(ctx, subQuery);
+ }
+ }
+
+ public void appendWhere(DbSqlContext ctx) {
+
+ if (inheritInfo != null) {
+ if (inheritInfo.isRoot()) {
+ // at root of hierarchy so don't bother
+ // adding a where clause because we want
+ // all the types...
+ } else {
+ // restrict to this type and
+ // sub types of this type.
+ if (ctx.length() > 0) {
+ ctx.append(" and");
+ }
+ ctx.append(" ").append(ctx.getTableAlias(prefix)).append(".");// tableAlias
+ ctx.append(inheritInfo.getWhere()).append(" ");
+ }
+ }
+ if (extraWhere != null) {
+ if (ctx.length() > 0) {
+ ctx.append(" and");
+ }
+ String ta = ctx.getTableAlias(prefix);
+ String ew = StringHelper.replaceString(extraWhere, "${ta}", ta);
+ ctx.append(" ").append(ew).append(" ");
+ }
+
+ for (int i = 0; i < children.length; i++) {
+ // recursively add to the where clause any
+ // fixed predicates (extraWhere etc)
+ children[i].appendWhere(ctx);
+ }
+ }
+
+ /**
+ * Append to the FROM clause for this node.
+ */
+ public void appendFrom(DbSqlContext ctx, boolean forceOuterJoin) {
+
+ ctx.pushJoin(prefix);
+ ctx.pushTableAlias(prefix);
+
+ forceOuterJoin = appendFromBaseTable(ctx, forceOuterJoin);
+
+ for (int i = 0; i < properties.length; i++) {
+ // usually nothing... except for 1-1 Exported
+ properties[i].appendFrom(ctx, forceOuterJoin);
+ }
+
+ for (int i = 0; i < children.length; i++) {
+ children[i].appendFrom(ctx, forceOuterJoin);
+ }
+
+ ctx.popTableAlias();
+ ctx.popJoin();
+ }
+
+ /**
+ * Join to base table for this node. This includes a join to the intersection
+ * table if this is a ManyToMany node.
+ */
+ public boolean appendFromBaseTable(DbSqlContext ctx, boolean forceOuterJoin) {
+
+ if (nodeBeanProp instanceof BeanPropertyAssocMany>) {
+ BeanPropertyAssocMany> manyProp = (BeanPropertyAssocMany>) nodeBeanProp;
+ if (manyProp.isManyToMany()) {
+
+ String alias = ctx.getTableAlias(prefix);
+ String[] split = SplitName.split(prefix);
+ String parentAlias = ctx.getTableAlias(split[0]);
+ String alias2 = alias + "z_";
+
+ TableJoin manyToManyJoin = manyProp.getIntersectionTableJoin();
+ manyToManyJoin.addJoin(forceOuterJoin, parentAlias, alias2, ctx);
+
+ return nodeBeanProp.addJoin(forceOuterJoin, alias2, alias, ctx);
+ }
+
+ }
+
+ return nodeBeanProp.addJoin(forceOuterJoin, prefix, ctx);
+ }
+
+ /**
+ * Summary description.
+ */
+ public String toString() {
+ return "SqlTreeNodeBean: " + desc;
+ }
}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeManyRoot.java b/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeManyRoot.java
index 68e7fe832..0f00639cc 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeManyRoot.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/query/SqlTreeNodeManyRoot.java
@@ -9,33 +9,32 @@ import com.avaje.ebeaninternal.server.deploy.DbSqlContext;
public final class SqlTreeNodeManyRoot extends SqlTreeNodeBean {
- public SqlTreeNodeManyRoot(String prefix, BeanPropertyAssocMany> prop, SqlTreeProperties props, List myList) {
- super(prefix, prop, prop.getTargetDescriptor(), props, myList, true);
- }
+ public SqlTreeNodeManyRoot(String prefix, BeanPropertyAssocMany> prop, SqlTreeProperties props, List myList) {
+ super(prefix, prop, prop.getTargetDescriptor(), props, myList, true);
+ }
- @Override
- protected void postLoad(DbReadContext cquery, Object loadedBean, Object id) {
-
- // put the localBean into the manyValue so that it
- // is added to the collection/map
- cquery.setLoadedManyBean(loadedBean);
- }
+ @Override
+ protected void postLoad(DbReadContext cquery, Object loadedBean, Object id) {
- @Override
- public void load(DbReadContext cquery, Object parentBean) throws SQLException {
- // pass in null for parentBean because the localBean
- // that is built is added to a collection rather than
- // being set to the parentBean directly
- super.load(cquery, null);
- }
+ // put the localBean into the manyValue so that it
+ // is added to the collection/map
+ cquery.setLoadedManyBean(loadedBean);
+ }
+
+ @Override
+ public void load(DbReadContext cquery, Object parentBean) throws SQLException {
+ // pass in null for parentBean because the localBean
+ // that is built is added to a collection rather than
+ // being set to the parentBean directly
+ super.load(cquery, null);
+ }
+
+ /**
+ * Force outer join for everything after the many property.
+ */
+ @Override
+ public void appendFrom(DbSqlContext ctx, boolean forceOuterJoin) {
+ super.appendFrom(ctx, true);
+ }
- /**
- * Force outer join for everything after the many property.
- */
- @Override
- public void appendFrom(DbSqlContext ctx, boolean forceOuterJoin) {
- super.appendFrom(ctx, true);
- }
-
-
}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/transaction/JdbcTransaction.java b/src/main/java/com/avaje/ebeaninternal/server/transaction/JdbcTransaction.java
index fd16ed742..e8a0a76d5 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/transaction/JdbcTransaction.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/transaction/JdbcTransaction.java
@@ -5,13 +5,16 @@ import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
import javax.persistence.PersistenceException;
import javax.persistence.RollbackException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import com.avaje.ebean.LogLevel;
import com.avaje.ebean.bean.PersistenceContext;
import com.avaje.ebeaninternal.api.DerivedRelationshipData;
@@ -19,8 +22,6 @@ import com.avaje.ebeaninternal.api.SpiTransaction;
import com.avaje.ebeaninternal.api.TransactionEvent;
import com.avaje.ebeaninternal.server.persist.BatchControl;
import com.avaje.ebeaninternal.server.transaction.TransactionManager.OnQueryOnly;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
* JDBC Connection based transaction.
@@ -29,6 +30,8 @@ public class JdbcTransaction implements SpiTransaction {
private static final Logger logger = LoggerFactory.getLogger(JdbcTransaction.class);
+ private static final Object PLACEHOLDER = new Object();
+
private static final String illegalStateMessage = "Transaction is Inactive";
/**
@@ -110,20 +113,18 @@ public class JdbcTransaction implements SpiTransaction {
Boolean batchFlushOnMixed;
+ String logPrefix;
+
/**
* The depth used by batch processing to help the ordering of statements.
*/
int depth = 0;
- HashSet