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 {
|
||||
|
||||
@@ -89,7 +89,7 @@ public class TestTypeManager extends BaseTestCase {
|
||||
String val;
|
||||
|
||||
public DummyDataReader(String val) {
|
||||
super(null);
|
||||
super(null, null);
|
||||
this.val = val;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ import com.avaje.ebean.text.json.JsonContext;
|
||||
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 javax.persistence.OptimisticLockException;
|
||||
import javax.persistence.PersistenceException;
|
||||
@@ -44,6 +45,11 @@ public class TDSpiEbeanServer implements SpiEbeanServer {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataTimeZone getDataTimeZone() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpiServer getPluginApi() {
|
||||
return null;
|
||||
|
||||
@@ -13,17 +13,14 @@ import java.sql.Timestamp;
|
||||
import java.util.Calendar;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* Must run this manually with various JVM timezones for insert and fetch.
|
||||
*/
|
||||
public class TimezoneTests {
|
||||
|
||||
private final long now = 1460000000000L;
|
||||
|
||||
private final Timestamp nowTs = new Timestamp(now);
|
||||
|
||||
private final Calendar utcCalendar;
|
||||
private final Timestamp nowTs = new Timestamp(1460000000000L);
|
||||
|
||||
public TimezoneTests() {
|
||||
utcCalendar = Calendar.getInstance();
|
||||
utcCalendar.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
}
|
||||
|
||||
@Ignore
|
||||
@@ -34,12 +31,12 @@ public class TimezoneTests {
|
||||
// insert("UTC");
|
||||
// insert("America/Los_Angeles");
|
||||
|
||||
System.out.println("Local");
|
||||
fetch();
|
||||
// System.out.println("Local");
|
||||
// fetch();
|
||||
|
||||
System.out.println("UTC");
|
||||
setZone("UTC");
|
||||
fetch();
|
||||
// System.out.println("UTC");
|
||||
// setZone("UTC");
|
||||
// fetch();
|
||||
|
||||
System.out.println("LA");
|
||||
setZone("America/Los_Angeles");
|
||||
@@ -49,14 +46,15 @@ public class TimezoneTests {
|
||||
private void fetch() throws SQLException {
|
||||
Transaction transaction = Ebean.beginTransaction();
|
||||
Connection connection = transaction.getConnection();
|
||||
|
||||
PreparedStatement statement = connection.prepareStatement("select * from tztest");
|
||||
ResultSet resultSet = statement.executeQuery();
|
||||
while (resultSet.next()) {
|
||||
System.out.println(" zone:"+resultSet.getString("zone"));
|
||||
System.out.println(" ts:"+tsof(resultSet.getTimestamp("ts")));
|
||||
System.out.println(" tstz:"+tsof(resultSet.getTimestamp("tstz")));
|
||||
System.out.println(" ts1:"+tsof(resultSet.getTimestamp("ts1", utcCal())));
|
||||
System.out.println("tstz1:"+tsof(resultSet.getTimestamp("tstz1", utcCal())));
|
||||
System.out.println(" ts1:"+tsof(resultSet.getTimestamp("ts1", cal())));
|
||||
System.out.println("tstz1:"+tsof(resultSet.getTimestamp("tstz1", cal())));
|
||||
}
|
||||
System.out.println("");
|
||||
resultSet.close();
|
||||
@@ -65,7 +63,7 @@ public class TimezoneTests {
|
||||
}
|
||||
|
||||
private String tsof(Timestamp timestamp) {
|
||||
return ""+timestamp.getTime()+","+timestamp.toString();
|
||||
return ""+timestamp.getTime()+", "+timestamp.toString()+", "+timestamp.toInstant();
|
||||
}
|
||||
|
||||
private void setZone(String zone) {
|
||||
@@ -86,14 +84,17 @@ public class TimezoneTests {
|
||||
statement.setString(1, zone);
|
||||
statement.setTimestamp(2, nowTs);
|
||||
statement.setTimestamp(3, nowTs);
|
||||
statement.setTimestamp(4, nowTs, utcCal());
|
||||
statement.setTimestamp(5, nowTs, utcCal());
|
||||
statement.setTimestamp(4, nowTs, cal());
|
||||
statement.setTimestamp(5, nowTs, cal());
|
||||
statement.executeUpdate();
|
||||
|
||||
transaction.commit();
|
||||
}
|
||||
|
||||
private Calendar utcCal() {
|
||||
return (Calendar) utcCalendar.clone();
|
||||
private Calendar cal() {
|
||||
|
||||
Calendar instance = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
|
||||
//Calendar instance = Calendar.getInstance(TimeZone.getDefault());
|
||||
return (Calendar) instance.clone();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.avaje.tests.timezone;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
import java.sql.Timestamp;
|
||||
|
||||
@Entity
|
||||
@Table(name="tz_bean")
|
||||
public class TzBean {
|
||||
|
||||
@Id
|
||||
Long id;
|
||||
|
||||
@Column(name = "mode")
|
||||
String mode;
|
||||
|
||||
Timestamp ts;
|
||||
Timestamp tstz;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
public void setMode(String mode) {
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
public Timestamp getTs() {
|
||||
return ts;
|
||||
}
|
||||
|
||||
public void setTs(Timestamp ts) {
|
||||
this.ts = ts;
|
||||
}
|
||||
|
||||
public Timestamp getTstz() {
|
||||
return tstz;
|
||||
}
|
||||
|
||||
public void setTstz(Timestamp tstz) {
|
||||
this.tstz = tstz;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package com.avaje.tests.timezone;
|
||||
|
||||
import com.avaje.ebean.Ebean;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.List;
|
||||
import java.util.TimeZone;
|
||||
//import java.util.TimeZone;
|
||||
|
||||
|
||||
|
||||
// Postgres
|
||||
// manually create table
|
||||
// create table tz_bean (id serial, mode varchar(40), ts timestamp, tstz timestamp with time zone);
|
||||
|
||||
// MySql
|
||||
// manually create table (note there is no timestamp with time zone type)
|
||||
// create table tz_bean (id serial, mode varchar(40), ts timestamp, tstz timestamp);
|
||||
|
||||
// Oracle
|
||||
// create table tz_bean (id integer, run_mode varchar(40), ts timestamp, tstz timestamp);
|
||||
|
||||
/**
|
||||
* Must run this test manually with various time zones for insert and fetch.
|
||||
*/
|
||||
public class TzBeanTests {
|
||||
|
||||
private final Timestamp nowTs = new Timestamp(1460000000000L);
|
||||
|
||||
public TzBeanTests() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Run this 5 times with different modes.
|
||||
*/
|
||||
@Ignore
|
||||
@Test
|
||||
public void insert_one_at_a_time() {
|
||||
|
||||
//String mode = "noCal + local tz";
|
||||
|
||||
// String mode = "noCal + LA";
|
||||
// TimeZone.setDefault(TimeZone.getTimeZone("America/Los_Angeles"));
|
||||
|
||||
// String mode = "noCal + UTC";
|
||||
// TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
|
||||
|
||||
// System.setProperty("ebean.dataTimeZone", "UTC");
|
||||
// TimeZone.setDefault(TimeZone.getTimeZone("America/Los_Angeles"));
|
||||
// String mode = "UTC + LA";
|
||||
|
||||
System.setProperty("ebean.dataTimeZone", "UTC");
|
||||
String mode = "UTC + NZST";
|
||||
|
||||
TzBean bean = new TzBean();
|
||||
bean.setMode(mode);
|
||||
bean.setTs(nowTs);
|
||||
bean.setTstz(nowTs);
|
||||
|
||||
Ebean.save(bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* In separate JVM/execution fetch the beans with various timezones etc.
|
||||
*/
|
||||
@Ignore
|
||||
@Test
|
||||
public void fetch_beans() {
|
||||
|
||||
|
||||
// set the jvm timezone
|
||||
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
|
||||
// TimeZone.setDefault(TimeZone.getTimeZone("America/Los_Angeles"));
|
||||
|
||||
// set the Calendar time zone to use in JDBC calls
|
||||
System.setProperty("ebean.dataTimeZone", "UTC");
|
||||
|
||||
List<TzBean> list = Ebean.find(TzBean.class)
|
||||
.findList();
|
||||
|
||||
for (TzBean bean : list) {
|
||||
System.out.println(" mode:"+bean.getMode());
|
||||
System.out.println(" ts:"+tsof(bean.getTs()));
|
||||
System.out.println(" tstz:"+tsof(bean.getTstz()));
|
||||
}
|
||||
}
|
||||
|
||||
private String tsof(Timestamp timestamp) {
|
||||
return ""+timestamp.getTime()+", "+timestamp.toString()+", "+timestamp.toInstant();
|
||||
}
|
||||
}
|
||||
@@ -102,6 +102,7 @@ datasource.hsqldb.databaseDriver=org.hsqldb.jdbcDriver
|
||||
datasource.mysql.username=unit
|
||||
datasource.mysql.password=unit
|
||||
datasource.mysql.databaseUrl=jdbc:mysql://127.0.0.1:3306/unit
|
||||
#datasource.mysql.databaseUrl=jdbc:mysql://127.0.0.1:3306/unit?useLegacyDatetimeCode=false
|
||||
datasource.mysql.databaseDriver=com.mysql.jdbc.Driver
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user