mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
#662 - Postgres Timestamp with time zone testing
This commit is contained in:
@@ -224,6 +224,11 @@ public class ServerConfig {
|
||||
|
||||
private boolean eagerFetchLobs;
|
||||
|
||||
/**
|
||||
* Timezone used to get/set Timestamp values via JDBC.
|
||||
*/
|
||||
private String dataTimeZone;
|
||||
|
||||
private boolean ddlGenerate;
|
||||
|
||||
private boolean ddlRun;
|
||||
@@ -841,6 +846,23 @@ public class ServerConfig {
|
||||
this.migrationConfig = migrationConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the time zone to use when reading/writing Timestamps via JDBC.
|
||||
* <p>
|
||||
* When set a Calendar object is used in JDBC calls when reading/writing Timestamp objects.
|
||||
* </p>
|
||||
*/
|
||||
public String getDataTimeZone() {
|
||||
return System.getProperty("ebean.dataTimeZone", dataTimeZone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the time zone to use when reading/writing Timestamps via JDBC.
|
||||
*/
|
||||
public void setDataTimeZone(String dataTimeZone) {
|
||||
this.dataTimeZone = dataTimeZone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the suffix appended to the base table to derive the view that contains the union
|
||||
* of the base table and the history table in order to support asOf queries.
|
||||
@@ -2369,6 +2391,7 @@ public class ServerConfig {
|
||||
changeLogIncludeInserts = p.getBoolean("changeLogIncludeInserts", changeLogIncludeInserts);
|
||||
expressionEqualsWithNullAsNoop = p.getBoolean("expressionEqualsWithNullAsNoop", expressionEqualsWithNullAsNoop);
|
||||
|
||||
dataTimeZone = p.get("dataTimeZone", dataTimeZone);
|
||||
asOfViewSuffix = p.get("asOfViewSuffix", asOfViewSuffix);
|
||||
asOfSysPeriod = p.get("asOfSysPeriod", asOfSysPeriod);
|
||||
historyTableSuffix = p.get("historyTableSuffix", historyTableSuffix);
|
||||
|
||||
@@ -16,6 +16,7 @@ import com.avaje.ebean.event.readaudit.ReadAuditPrepare;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.query.CQuery;
|
||||
import com.avaje.ebeaninternal.server.transaction.RemoteTransactionEvent;
|
||||
import com.avaje.ebeaninternal.server.core.timezone.DataTimeZone;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -187,4 +188,9 @@ public interface SpiEbeanServer extends EbeanServer, BeanLoader, BeanCollectionL
|
||||
* user context information (user id, user ip address etc).
|
||||
*/
|
||||
ReadAuditPrepare getReadAuditPrepare();
|
||||
|
||||
/**
|
||||
* Return the DataTimeZone to use when reading/writing timestamps via JDBC.
|
||||
*/
|
||||
DataTimeZone getDataTimeZone();
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.avaje.ebeaninternal.server.core;
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.api.SpiTransaction;
|
||||
import com.avaje.ebeaninternal.server.core.timezone.DataTimeZone;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -12,35 +13,35 @@ import org.slf4j.LoggerFactory;
|
||||
public abstract class BeanRequest {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(BeanRequest.class);
|
||||
|
||||
/**
|
||||
* The server processing the request.
|
||||
*/
|
||||
protected final SpiEbeanServer ebeanServer;
|
||||
|
||||
/**
|
||||
* The transaction this is part of.
|
||||
*/
|
||||
protected SpiTransaction transaction;
|
||||
/**
|
||||
* The server processing the request.
|
||||
*/
|
||||
protected final SpiEbeanServer ebeanServer;
|
||||
|
||||
protected boolean createdTransaction;
|
||||
/**
|
||||
* The transaction this is part of.
|
||||
*/
|
||||
protected SpiTransaction transaction;
|
||||
|
||||
public BeanRequest(SpiEbeanServer ebeanServer, SpiTransaction t) {
|
||||
this.ebeanServer = ebeanServer;
|
||||
this.transaction = t;
|
||||
}
|
||||
protected boolean createdTransaction;
|
||||
|
||||
/**
|
||||
* A helper method for creating an implicit transaction is it is required.
|
||||
* <p>
|
||||
* A transaction may have been passed in or active in the thread local. If
|
||||
* not then create one implicitly to handle the request.
|
||||
* </p>
|
||||
public BeanRequest(SpiEbeanServer ebeanServer, SpiTransaction t) {
|
||||
this.ebeanServer = ebeanServer;
|
||||
this.transaction = t;
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper method for creating an implicit transaction is it is required.
|
||||
* <p>
|
||||
* A transaction may have been passed in or active in the thread local. If
|
||||
* not then create one implicitly to handle the request.
|
||||
* </p>
|
||||
*
|
||||
* @return True if a transaction was set (from current or created).
|
||||
*/
|
||||
public boolean createImplicitTransIfRequired() {
|
||||
if (transaction != null) {
|
||||
*/
|
||||
public boolean createImplicitTransIfRequired() {
|
||||
if (transaction != null) {
|
||||
return false;
|
||||
}
|
||||
transaction = ebeanServer.getCurrentServerTransaction();
|
||||
@@ -50,7 +51,7 @@ public abstract class BeanRequest {
|
||||
createdTransaction = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit this transaction if it was created for this request.
|
||||
@@ -61,40 +62,40 @@ public abstract class BeanRequest {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rollback the transaction if it was created for this request.
|
||||
*/
|
||||
public void rollbackTransIfRequired() {
|
||||
if (createdTransaction) {
|
||||
try {
|
||||
transaction.rollback();
|
||||
} catch (Exception e) {
|
||||
// Just log this and carry on. A previous exception has been
|
||||
// thrown and if this rollback throws exception it likely means
|
||||
// that the connection is broken (and the datasource and db will cleanup)
|
||||
log.error("Error trying to rollback a transaction (after a prior exception thrown)", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Rollback the transaction if it was created for this request.
|
||||
*/
|
||||
public void rollbackTransIfRequired() {
|
||||
if (createdTransaction) {
|
||||
try {
|
||||
transaction.rollback();
|
||||
} catch (Exception e) {
|
||||
// Just log this and carry on. A previous exception has been
|
||||
// thrown and if this rollback throws exception it likely means
|
||||
// that the connection is broken (and the datasource and db will cleanup)
|
||||
log.error("Error trying to rollback a transaction (after a prior exception thrown)", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the server processing the request. Made available for
|
||||
* BeanController and BeanFinder.
|
||||
*/
|
||||
public EbeanServer getEbeanServer() {
|
||||
return ebeanServer;
|
||||
}
|
||||
/**
|
||||
* Return the server processing the request. Made available for
|
||||
* BeanController and BeanFinder.
|
||||
*/
|
||||
public EbeanServer getEbeanServer() {
|
||||
return ebeanServer;
|
||||
}
|
||||
|
||||
public SpiEbeanServer getServer() {
|
||||
return ebeanServer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Transaction associated with this request.
|
||||
*/
|
||||
public SpiTransaction getTransaction() {
|
||||
return transaction;
|
||||
}
|
||||
/**
|
||||
* Return the Transaction associated with this request.
|
||||
*/
|
||||
public SpiTransaction getTransaction() {
|
||||
return transaction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if SQL should be logged for this transaction.
|
||||
@@ -109,4 +110,11 @@ public abstract class BeanRequest {
|
||||
public boolean isLogSummary() {
|
||||
return transaction.isLogSummary();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DataTimeZone to use.
|
||||
*/
|
||||
public DataTimeZone getDataTimeZone() {
|
||||
return ebeanServer.getDataTimeZone();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,6 +64,7 @@ import com.avaje.ebeaninternal.server.transaction.DefaultPersistenceContext;
|
||||
import com.avaje.ebeaninternal.server.transaction.RemoteTransactionEvent;
|
||||
import com.avaje.ebeaninternal.server.transaction.TransactionManager;
|
||||
import com.avaje.ebeaninternal.server.transaction.TransactionScopeManager;
|
||||
import com.avaje.ebeaninternal.server.core.timezone.DataTimeZone;
|
||||
import com.avaje.ebeaninternal.util.ParamTypeHelper;
|
||||
import com.avaje.ebeaninternal.util.ParamTypeHelper.TypeInfo;
|
||||
import com.avaje.ebeanservice.docstore.api.DocStoreIntegration;
|
||||
@@ -108,6 +109,8 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
|
||||
private final TransactionScopeManager transactionScopeManager;
|
||||
|
||||
private final DataTimeZone dataTimeZone;
|
||||
|
||||
private final CallStackFactory callStackFactory = new DefaultCallStackFactory();
|
||||
|
||||
private final int maxCallStack;
|
||||
@@ -228,6 +231,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
|
||||
this.beanLoader = new DefaultBeanLoader(this);
|
||||
this.jsonContext = config.createJsonContext(this);
|
||||
this.dataTimeZone = config.getDataTimeZone();
|
||||
|
||||
DocStoreIntegration docStoreComponents = config.createDocStoreIntegration(this);
|
||||
this.transactionManager = config.createTransactionManager(docStoreComponents.updateProcessor());
|
||||
@@ -284,7 +288,12 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
public DatabasePlatform getDatabasePlatform() {
|
||||
return databasePlatform;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public DataTimeZone getDataTimeZone() {
|
||||
return dataTimeZone;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MetaInfoManager getMetaInfoManager() {
|
||||
return metaInfoManager;
|
||||
|
||||
@@ -22,6 +22,9 @@ import com.avaje.ebeaninternal.server.changelog.DefaultChangeLogListener;
|
||||
import com.avaje.ebeaninternal.server.changelog.DefaultChangeLogPrepare;
|
||||
import com.avaje.ebeaninternal.server.changelog.DefaultChangeLogRegister;
|
||||
import com.avaje.ebeaninternal.server.cluster.ClusterManager;
|
||||
import com.avaje.ebeaninternal.server.core.timezone.CloneDataTimeZone;
|
||||
import com.avaje.ebeaninternal.server.core.timezone.NoDataTimeZone;
|
||||
import com.avaje.ebeaninternal.server.core.timezone.SimpleDataTimeZone;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptorManager;
|
||||
import com.avaje.ebeaninternal.server.deploy.DeployOrmXml;
|
||||
import com.avaje.ebeaninternal.server.deploy.generatedproperty.GeneratedPropertyFactory;
|
||||
@@ -29,6 +32,7 @@ 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.core.timezone.DataTimeZone;
|
||||
import org.avaje.datasource.DataSourcePool;
|
||||
import com.avaje.ebeaninternal.server.persist.Binder;
|
||||
import com.avaje.ebeaninternal.server.persist.DefaultPersister;
|
||||
@@ -79,6 +83,8 @@ public class InternalConfiguration {
|
||||
|
||||
private final TypeManager typeManager;
|
||||
|
||||
private final DataTimeZone dataTimeZone;
|
||||
|
||||
private final Binder binder;
|
||||
|
||||
private final DeployCreateProperties deployCreateProperties;
|
||||
@@ -136,7 +142,8 @@ public class InternalConfiguration {
|
||||
|
||||
DatabasePlatform databasePlatform = serverConfig.getDatabasePlatform();
|
||||
|
||||
this.binder = getBinder(typeManager, databasePlatform);
|
||||
this.dataTimeZone = initDataTimeZone();
|
||||
this.binder = getBinder(typeManager, databasePlatform, dataTimeZone);
|
||||
this.cQueryEngine = new CQueryEngine(databasePlatform, binder, asOfTableMapping, serverConfig.getAsOfSysPeriod(), draftTableMap);
|
||||
}
|
||||
|
||||
@@ -218,15 +225,15 @@ public class InternalConfiguration {
|
||||
/**
|
||||
* For 'As Of' queries return the number of bind variables per predicate.
|
||||
*/
|
||||
private Binder getBinder(TypeManager typeManager, DatabasePlatform databasePlatform) {
|
||||
private Binder getBinder(TypeManager typeManager, DatabasePlatform databasePlatform, DataTimeZone dataTimeZone) {
|
||||
|
||||
JsonExpressionHandler jsonHandler = getJsonExpressionHandler(databasePlatform);
|
||||
|
||||
DbHistorySupport historySupport = databasePlatform.getHistorySupport();
|
||||
if (historySupport == null) {
|
||||
return new Binder(typeManager, 0, false, jsonHandler);
|
||||
return new Binder(typeManager, 0, false, jsonHandler, dataTimeZone);
|
||||
}
|
||||
return new Binder(typeManager, historySupport.getBindCount(), historySupport.isBindWithFromClause(), jsonHandler);
|
||||
return new Binder(typeManager, historySupport.getBindCount(), historySupport.isBindWithFromClause(), jsonHandler, dataTimeZone);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -381,4 +388,24 @@ public class InternalConfiguration {
|
||||
return new DefaultTransactionScopeManager(transactionManager);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the DataTimeZone implementation to use.
|
||||
*/
|
||||
private DataTimeZone initDataTimeZone() {
|
||||
|
||||
String tz = serverConfig.getDataTimeZone();
|
||||
if (tz == null) {
|
||||
return new NoDataTimeZone();
|
||||
}
|
||||
if (getDatabasePlatform().getName().toLowerCase().startsWith("oracle")) {
|
||||
return new CloneDataTimeZone(tz);
|
||||
} else {
|
||||
return new SimpleDataTimeZone(tz);
|
||||
}
|
||||
}
|
||||
|
||||
public DataTimeZone getDataTimeZone() {
|
||||
return dataTimeZone;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.avaje.ebeaninternal.server.core.timezone;
|
||||
|
||||
import java.util.Calendar;
|
||||
|
||||
/**
|
||||
* Implementation of DataTimeZone that clones the Calendar instance.
|
||||
* <p>
|
||||
* Used with Oracle JDBC driver as that wants to mutate the Calender.
|
||||
* </p>
|
||||
*/
|
||||
public class CloneDataTimeZone extends SimpleDataTimeZone {
|
||||
|
||||
public CloneDataTimeZone(String zoneId) {
|
||||
super(zoneId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Calendar getTimeZone() {
|
||||
// return cloned copy for Oracle to muck around with
|
||||
return (Calendar)zone.clone();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.avaje.ebeaninternal.server.core.timezone;
|
||||
|
||||
import java.util.Calendar;
|
||||
|
||||
/**
|
||||
* Define if a Calendar representing the time zone should be used in JDBC calls.
|
||||
*/
|
||||
public interface DataTimeZone {
|
||||
|
||||
/**
|
||||
* Return the Calendar to use for Timezone information.
|
||||
*/
|
||||
Calendar getTimeZone();
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.avaje.ebeaninternal.server.core.timezone;
|
||||
|
||||
import java.util.Calendar;
|
||||
|
||||
/**
|
||||
* Implementation of DataTimeZone when no time zone is specified.
|
||||
*/
|
||||
public class NoDataTimeZone implements DataTimeZone {
|
||||
|
||||
@Override
|
||||
public Calendar getTimeZone() {
|
||||
// return null so Calendar is not used
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.avaje.ebeaninternal.server.core.timezone;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* Implementation of DataTimeZone when single Calendar instance is used.
|
||||
*/
|
||||
public class SimpleDataTimeZone implements DataTimeZone {
|
||||
|
||||
protected final Calendar zone;
|
||||
|
||||
public SimpleDataTimeZone(String zoneId) {
|
||||
this.zone = Calendar.getInstance(TimeZone.getTimeZone(zoneId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Calendar getTimeZone() {
|
||||
// return null so Calendar is not used
|
||||
return zone;
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package com.avaje.ebeaninternal.server.persist;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.ArrayList;
|
||||
@@ -13,6 +14,7 @@ import com.avaje.ebean.config.dbplatform.DbType;
|
||||
import com.avaje.ebeaninternal.api.BindParams;
|
||||
import com.avaje.ebeaninternal.server.core.JsonExpressionHandler;
|
||||
import com.avaje.ebeaninternal.server.core.Message;
|
||||
import com.avaje.ebeaninternal.server.core.timezone.DataTimeZone;
|
||||
import com.avaje.ebeaninternal.server.type.DataBind;
|
||||
import com.avaje.ebeaninternal.server.type.ScalarType;
|
||||
import com.avaje.ebeaninternal.server.type.TypeManager;
|
||||
@@ -34,14 +36,19 @@ public class Binder {
|
||||
|
||||
private final JsonExpressionHandler jsonExpressionHandler;
|
||||
|
||||
private final DataTimeZone dataTimeZone;
|
||||
|
||||
/**
|
||||
* Set the PreparedStatement with which to bind variables to.
|
||||
*/
|
||||
public Binder(TypeManager typeManager, int asOfBindCount, boolean bindAsOfWithFromClause, JsonExpressionHandler jsonExpressionHandler) {
|
||||
public Binder(TypeManager typeManager, int asOfBindCount, boolean bindAsOfWithFromClause,
|
||||
JsonExpressionHandler jsonExpressionHandler, DataTimeZone dataTimeZone) {
|
||||
|
||||
this.typeManager = typeManager;
|
||||
this.asOfBindCount = asOfBindCount;
|
||||
this.bindAsOfWithFromClause = bindAsOfWithFromClause;
|
||||
this.jsonExpressionHandler = jsonExpressionHandler;
|
||||
this.dataTimeZone = dataTimeZone;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -91,6 +98,13 @@ public class Binder {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind the parameters to the preparedStatement returning the bind log.
|
||||
*/
|
||||
public String bind(BindParams bindParams, PreparedStatement statement) throws SQLException {
|
||||
return bind(bindParams, new DataBind(dataTimeZone, statement));
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind the list of positionedParameters in BindParams.
|
||||
*/
|
||||
@@ -392,4 +406,11 @@ public class Binder {
|
||||
public JsonExpressionHandler getJsonExpressionHandler() {
|
||||
return jsonExpressionHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return a DataBind for the statement.
|
||||
*/
|
||||
public DataBind dataBind(PreparedStatement stmt) {
|
||||
return new DataBind(dataTimeZone, stmt);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import com.avaje.ebeaninternal.api.BindParams;
|
||||
import com.avaje.ebeaninternal.api.SpiCallableSql;
|
||||
import com.avaje.ebeaninternal.api.SpiTransaction;
|
||||
import com.avaje.ebeaninternal.server.core.PersistRequestCallableSql;
|
||||
import com.avaje.ebeaninternal.server.type.DataBind;
|
||||
import com.avaje.ebeaninternal.server.util.BindParamsParser;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -96,7 +95,7 @@ public class ExeCallableSql {
|
||||
|
||||
String bindLog = null;
|
||||
if (!bindParams.isEmpty()) {
|
||||
bindLog = binder.bind(bindParams, new DataBind(cstmt));
|
||||
bindLog = binder.bind(bindParams, cstmt);
|
||||
}
|
||||
|
||||
request.setBindLog(bindLog);
|
||||
|
||||
@@ -113,7 +113,7 @@ public class ExeOrmUpdate {
|
||||
|
||||
String bindLog = null;
|
||||
if (!bindParams.isEmpty()) {
|
||||
bindLog = binder.bind(bindParams, new DataBind(pstmt));
|
||||
bindLog = binder.bind(bindParams, pstmt);
|
||||
}
|
||||
|
||||
request.setBindLog(bindLog);
|
||||
|
||||
@@ -100,7 +100,7 @@ public class ExeUpdateSql {
|
||||
|
||||
String bindLog = null;
|
||||
if (!bindParams.isEmpty()) {
|
||||
bindLog = binder.bind(bindParams, new DataBind(pstmt));
|
||||
bindLog = binder.bind(bindParams, pstmt);
|
||||
}
|
||||
|
||||
request.setBindLog(bindLog);
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
package com.avaje.ebeaninternal.server.persist.dml;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import javax.persistence.OptimisticLockException;
|
||||
|
||||
import com.avaje.ebeaninternal.api.DerivedRelationshipData;
|
||||
import com.avaje.ebeaninternal.api.SpiTransaction;
|
||||
import com.avaje.ebeaninternal.server.core.PersistRequestBean;
|
||||
import com.avaje.ebeaninternal.server.type.DataBind;
|
||||
|
||||
import javax.persistence.OptimisticLockException;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Delete bean handler.
|
||||
@@ -37,7 +35,7 @@ public class DeleteHandler extends DmlHandler {
|
||||
} else {
|
||||
pstmt = getPstmt(t, sql, false);
|
||||
}
|
||||
dataBind = new DataBind(pstmt);
|
||||
dataBind = bind(pstmt);
|
||||
meta.bind(persistRequest, this);
|
||||
logSql(sql);
|
||||
}
|
||||
|
||||
@@ -74,6 +74,13 @@ public abstract class DmlHandler implements PersistHandler, BindableRequest {
|
||||
return persistRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind to the statement returning the DataBind.
|
||||
*/
|
||||
protected DataBind bind(PreparedStatement stmt) {
|
||||
return new DataBind(persistRequest.getDataTimeZone(), stmt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the sql and bind the statement.
|
||||
*/
|
||||
|
||||
@@ -9,7 +9,6 @@ import com.avaje.ebeaninternal.server.core.PersistRequestBean;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.persist.DmlUtil;
|
||||
import com.avaje.ebeaninternal.server.type.DataBind;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -98,9 +97,7 @@ public class InsertHandler extends DmlHandler {
|
||||
} else {
|
||||
pstmt = getPstmt(t, sql, useGeneratedKeys);
|
||||
}
|
||||
dataBind = new DataBind(pstmt);
|
||||
|
||||
// bind the bean property values
|
||||
dataBind = bind(pstmt);
|
||||
meta.bind(this, bean, withId, persistRequest.isPublish());
|
||||
|
||||
logSql(sql);
|
||||
|
||||
@@ -4,7 +4,6 @@ import com.avaje.ebeaninternal.api.DerivedRelationshipData;
|
||||
import com.avaje.ebeaninternal.api.SpiTransaction;
|
||||
import com.avaje.ebeaninternal.api.SpiUpdatePlan;
|
||||
import com.avaje.ebeaninternal.server.core.PersistRequestBean;
|
||||
import com.avaje.ebeaninternal.server.type.DataBind;
|
||||
|
||||
import javax.persistence.OptimisticLockException;
|
||||
import java.sql.PreparedStatement;
|
||||
@@ -47,8 +46,7 @@ public class UpdateHandler extends DmlHandler {
|
||||
} else {
|
||||
pstmt = getPstmt(t, sql, false);
|
||||
}
|
||||
dataBind = new DataBind(pstmt);
|
||||
|
||||
dataBind = bind(pstmt);
|
||||
meta.bind(persistRequest, this, updatePlan);
|
||||
|
||||
setUpdateGenValues();
|
||||
|
||||
@@ -335,11 +335,7 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
|
||||
pstmt.setFetchSize(query.getBufferFetchSizeHint());
|
||||
}
|
||||
|
||||
DataBind dataBind = new DataBind(pstmt);
|
||||
|
||||
// bind keys for encrypted properties
|
||||
queryPlan.bindEncryptedProperties(dataBind);
|
||||
|
||||
DataBind dataBind = queryPlan.bindEncryptedProperties(pstmt);
|
||||
bindLog = predicates.bind(dataBind);
|
||||
|
||||
// executeQuery
|
||||
|
||||
@@ -105,7 +105,7 @@ public class CQueryDelete {
|
||||
pstmt.setQueryTimeout(query.getTimeout());
|
||||
}
|
||||
|
||||
bindLog = predicates.bind(new DataBind(pstmt));
|
||||
bindLog = predicates.bind(pstmt);
|
||||
rowCount = pstmt.executeUpdate();
|
||||
|
||||
long exeNano = System.nanoTime() - startNano;
|
||||
|
||||
@@ -12,7 +12,6 @@ import com.avaje.ebeaninternal.server.core.OrmQueryRequest;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
import com.avaje.ebeaninternal.server.deploy.DbReadContext;
|
||||
import com.avaje.ebeaninternal.server.type.DataBind;
|
||||
import com.avaje.ebeaninternal.server.type.DataReader;
|
||||
import com.avaje.ebeaninternal.server.type.RsetDataReader;
|
||||
import org.slf4j.Logger;
|
||||
@@ -144,10 +143,10 @@ public class CQueryFetchIds {
|
||||
pstmt.setQueryTimeout(query.getTimeout());
|
||||
}
|
||||
|
||||
bindLog = predicates.bind(new DataBind(pstmt));
|
||||
bindLog = predicates.bind(pstmt);
|
||||
|
||||
ResultSet rset = pstmt.executeQuery();
|
||||
dataReader = new RsetDataReader(rset);
|
||||
dataReader = new RsetDataReader(request.getDataTimeZone(), rset);
|
||||
|
||||
boolean hitMaxRows = false;
|
||||
boolean hasMoreRows = false;
|
||||
|
||||
@@ -9,11 +9,13 @@ import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.query.CQueryPlanStats.Snapshot;
|
||||
import com.avaje.ebeaninternal.server.type.DataBind;
|
||||
import com.avaje.ebeaninternal.server.type.DataReader;
|
||||
import com.avaje.ebeaninternal.server.core.timezone.DataTimeZone;
|
||||
import com.avaje.ebeaninternal.server.type.RsetDataReader;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
@@ -65,6 +67,8 @@ public class CQueryPlan {
|
||||
|
||||
private final Class<?> beanType;
|
||||
|
||||
protected final DataTimeZone dataTimeZone;
|
||||
|
||||
/**
|
||||
* Key used to identify the query plan in audit logging.
|
||||
*/
|
||||
@@ -76,6 +80,7 @@ public class CQueryPlan {
|
||||
public CQueryPlan(OrmQueryRequest<?> request, SqlLimitResponse sqlRes, SqlTree sqlTree, boolean rawSql, String logWhereSql) {
|
||||
|
||||
this.server = request.getServer();
|
||||
this.dataTimeZone = server.getDataTimeZone();
|
||||
this.beanType = request.getBeanDescriptor().getBeanType();
|
||||
this.stats = new CQueryPlanStats(this, server.isCollectQueryOrigins());
|
||||
this.planKey = request.getQueryPlanKey();
|
||||
@@ -100,6 +105,7 @@ public class CQueryPlan {
|
||||
boolean rawSql, boolean rowNumberIncluded, String logWhereSql) {
|
||||
|
||||
this.server = request.getServer();
|
||||
this.dataTimeZone = server.getDataTimeZone();
|
||||
this.beanType = request.getBeanDescriptor().getBeanType();
|
||||
this.stats = new CQueryPlanStats(this, server.isCollectQueryOrigins());
|
||||
this.planKey = buildPlanKey(sql, rawSql, rowNumberIncluded, logWhereSql);
|
||||
@@ -127,17 +133,21 @@ public class CQueryPlan {
|
||||
}
|
||||
|
||||
public DataReader createDataReader(ResultSet rset) {
|
||||
|
||||
return new RsetDataReader(rset);
|
||||
return new RsetDataReader(dataTimeZone, rset);
|
||||
}
|
||||
|
||||
public void bindEncryptedProperties(DataBind dataBind) throws SQLException {
|
||||
/**
|
||||
* Bind keys for encrypted properties if necessary returning the DataBind.
|
||||
*/
|
||||
public DataBind bindEncryptedProperties(PreparedStatement stmt) throws SQLException {
|
||||
DataBind dataBind = new DataBind(dataTimeZone, stmt);
|
||||
if (encryptedProps != null) {
|
||||
for (int i = 0; i < encryptedProps.length; i++) {
|
||||
String key = encryptedProps[i].getEncryptKey().getStringValue();
|
||||
dataBind.setString(key);
|
||||
}
|
||||
}
|
||||
return dataBind;
|
||||
}
|
||||
|
||||
public boolean isAutoTuned() {
|
||||
|
||||
@@ -24,9 +24,9 @@ public class CQueryPlanRawSql extends CQueryPlan {
|
||||
this.rsetIndexPositions = createIndexPositions(request, sqlTree);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataReader createDataReader(ResultSet rset) {
|
||||
|
||||
return new RsetDataReaderIndexed(rset, rsetIndexPositions, isRowNumberIncluded());
|
||||
return new RsetDataReaderIndexed(dataTimeZone, rset, rsetIndexPositions, isRowNumberIncluded());
|
||||
}
|
||||
|
||||
private int[] createIndexPositions(OrmQueryRequest<?> request, SqlTree sqlTree) {
|
||||
|
||||
@@ -17,6 +17,7 @@ import com.avaje.ebeaninternal.server.expression.DefaultExpressionRequest;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.HashSet;
|
||||
@@ -125,6 +126,10 @@ public class CQueryPredicates {
|
||||
this.idValue = query.getId();
|
||||
}
|
||||
|
||||
public String bind(PreparedStatement stmt) throws SQLException {
|
||||
return bind(binder.dataBind(stmt));
|
||||
}
|
||||
|
||||
public String bind(DataBind dataBind) throws SQLException {
|
||||
|
||||
if (query.isVersionsBetween() && binder.isBindAsOfWithFromClause()) {
|
||||
|
||||
@@ -116,8 +116,7 @@ public class CQueryRowCount {
|
||||
pstmt.setQueryTimeout(query.getTimeout());
|
||||
}
|
||||
|
||||
bindLog = predicates.bind(new DataBind(pstmt));
|
||||
|
||||
bindLog = predicates.bind(pstmt);
|
||||
rset = pstmt.executeQuery();
|
||||
|
||||
if (!rset.next()) {
|
||||
|
||||
+1
-1
@@ -81,7 +81,7 @@ public class DefaultRelationalQueryEngine implements RelationalQueryEngine {
|
||||
}
|
||||
|
||||
if (!bindParams.isEmpty()) {
|
||||
bindLog = binder.bind(bindParams, new DataBind(pstmt));
|
||||
bindLog = binder.bind(bindParams, pstmt);
|
||||
}
|
||||
|
||||
if (request.isLogSql()) {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.avaje.ebeaninternal.server.type;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.timezone.DataTimeZone;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
@@ -9,16 +11,20 @@ import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Time;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Calendar;
|
||||
|
||||
public class DataBind {
|
||||
|
||||
private final DataTimeZone dataTimeZone;
|
||||
|
||||
private final PreparedStatement pstmt;
|
||||
|
||||
private final StringBuilder bindLog = new StringBuilder();
|
||||
|
||||
private int pos;
|
||||
|
||||
public DataBind(PreparedStatement pstmt) {
|
||||
public DataBind(DataTimeZone dataTimeZone, PreparedStatement pstmt) {
|
||||
this.dataTimeZone = dataTimeZone;
|
||||
this.pstmt = pstmt;
|
||||
}
|
||||
|
||||
@@ -108,7 +114,12 @@ public class DataBind {
|
||||
}
|
||||
|
||||
public void setTimestamp(Timestamp v) throws SQLException {
|
||||
pstmt.setTimestamp(++pos, v);
|
||||
Calendar timeZone = dataTimeZone.getTimeZone();
|
||||
if (timeZone != null) {
|
||||
pstmt.setTimestamp(++pos, v, timeZone);
|
||||
} else {
|
||||
pstmt.setTimestamp(++pos, v);
|
||||
}
|
||||
}
|
||||
|
||||
public void setTime(Time v) throws SQLException {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.avaje.ebeaninternal.server.type;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.Message;
|
||||
import com.avaje.ebeaninternal.server.core.timezone.DataTimeZone;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
@@ -14,6 +15,7 @@ import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Time;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Calendar;
|
||||
|
||||
public class RsetDataReader implements DataReader {
|
||||
|
||||
@@ -23,11 +25,14 @@ public class RsetDataReader implements DataReader {
|
||||
|
||||
static final int stringInitialSize = 512;
|
||||
|
||||
private final DataTimeZone dataTimeZone;
|
||||
|
||||
private final ResultSet rset;
|
||||
|
||||
protected int pos;
|
||||
|
||||
public RsetDataReader(ResultSet rset) {
|
||||
public RsetDataReader(DataTimeZone dataTimeZone, ResultSet rset) {
|
||||
this.dataTimeZone = dataTimeZone;
|
||||
this.rset = rset;
|
||||
}
|
||||
|
||||
@@ -149,9 +154,13 @@ public class RsetDataReader implements DataReader {
|
||||
return rset.getTime(pos());
|
||||
}
|
||||
|
||||
|
||||
public Timestamp getTimestamp() throws SQLException {
|
||||
return rset.getTimestamp(pos());
|
||||
Calendar cal = dataTimeZone.getTimeZone();
|
||||
if (cal != null) {
|
||||
return rset.getTimestamp(pos(), cal);
|
||||
} else {
|
||||
return rset.getTimestamp(pos());
|
||||
}
|
||||
}
|
||||
|
||||
public String getStringFromStream() throws SQLException {
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
package com.avaje.ebeaninternal.server.type;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.timezone.DataTimeZone;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
|
||||
public class RsetDataReaderIndexed extends RsetDataReader {
|
||||
|
||||
private final int[] rsetIndexPositions;
|
||||
|
||||
public RsetDataReaderIndexed(ResultSet rset, int[] rsetIndexPositions, boolean rowNumberIncluded) {
|
||||
super(rset);
|
||||
public RsetDataReaderIndexed(DataTimeZone dataTimeZone, ResultSet rset, int[] rsetIndexPositions, boolean rowNumberIncluded) {
|
||||
super(dataTimeZone, rset);
|
||||
if (!rowNumberIncluded) {
|
||||
this.rsetIndexPositions = rsetIndexPositions;
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user