HHH-8401 : Support fractional seconds on MySQL 5.7
(cherry picked from commit fe94cda1d1
)
This commit is contained in:
parent
c068b6f70c
commit
fa8383a22e
|
@ -0,0 +1,80 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014, Red Hat Inc. or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat Inc.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.dialect;
|
||||||
|
|
||||||
|
import java.sql.Types;
|
||||||
|
|
||||||
|
import org.hibernate.dialect.function.SQLFunction;
|
||||||
|
import org.hibernate.dialect.function.StaticPrecisionFspTimestampFunction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Gail Badner
|
||||||
|
*/
|
||||||
|
public class MySQL57InnoDBDialect extends MySQL5InnoDBDialect {
|
||||||
|
public MySQL57InnoDBDialect() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
// For details about MySQL 5.7 support for fractional seconds
|
||||||
|
// precision (fsp): http://dev.mysql.com/doc/refman/5.7/en/fractional-seconds.html
|
||||||
|
// Regarding datetime(fsp), "The fsp value, if given, must be
|
||||||
|
// in the range 0 to 6. A value of 0 signifies that there is
|
||||||
|
// no fractional part. If omitted, the default precision is 0.
|
||||||
|
// (This differs from the standard SQL default of 6, for
|
||||||
|
// compatibility with previous MySQL versions.)".
|
||||||
|
|
||||||
|
// The following is defined because Hibernate currently expects
|
||||||
|
// the SQL 1992 default of 6 (which is inconsistent with the MySQL
|
||||||
|
// default).
|
||||||
|
registerColumnType( Types.TIMESTAMP, "datetime(6)" );
|
||||||
|
|
||||||
|
// MySQL also supports fractional seconds precision for time values
|
||||||
|
// (time(fsp)). According to SQL 1992, the default for <time precision>
|
||||||
|
// is 0. The MySQL default is time(0), there's no need to override
|
||||||
|
// the setting for Types.TIME columns.
|
||||||
|
|
||||||
|
// For details about MySQL support for timestamp functions, see:
|
||||||
|
// http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html
|
||||||
|
|
||||||
|
// The following are synonyms for now(fsp), where fsp defaults to 0 on MySQL 5.7:
|
||||||
|
// current_timestamp([fsp]), localtime(fsp), localtimestamp(fsp).
|
||||||
|
// Register the same StaticPrecisionFspTimestampFunction for all 4 functions.
|
||||||
|
final SQLFunction currentTimestampFunction = new StaticPrecisionFspTimestampFunction("now", 6 );
|
||||||
|
|
||||||
|
registerFunction( "now", currentTimestampFunction );
|
||||||
|
registerFunction( "current_timestamp", currentTimestampFunction );
|
||||||
|
registerFunction( "localtime", currentTimestampFunction );
|
||||||
|
registerFunction( "localtimestamp", currentTimestampFunction );
|
||||||
|
|
||||||
|
// sysdate is different from now():
|
||||||
|
// "SYSDATE() returns the time at which it executes. This differs
|
||||||
|
// from the behavior for NOW(), which returns a constant time that
|
||||||
|
// indicates the time at which the statement began to execute.
|
||||||
|
// (Within a stored function or trigger, NOW() returns the time at
|
||||||
|
// which the function or triggering statement began to execute.)
|
||||||
|
registerFunction( "sysdate", new StaticPrecisionFspTimestampFunction( "sysdate", 6 ) );
|
||||||
|
|
||||||
|
// from_unixtime(), timestamp() are functions that return TIMESTAMP that do not support a
|
||||||
|
// fractional seconds precision argument (so there's no need to override them here):
|
||||||
|
}
|
||||||
|
}
|
|
@ -85,4 +85,8 @@ public class NoArgSQLFunction implements SQLFunction {
|
||||||
}
|
}
|
||||||
return hasParenthesesIfNoArguments ? name + "()" : name;
|
return hasParenthesesIfNoArguments ? name + "()" : name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014, Red Hat Inc. or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat Inc.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.dialect.function;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.hibernate.QueryException;
|
||||||
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
|
import org.hibernate.type.StandardBasicTypes;
|
||||||
|
import org.hibernate.type.Type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A function that returns a {@link org.hibernate.type.StandardBasicTypes#TIMESTAMP}
|
||||||
|
* with static fractional seconds precision (fsp).
|
||||||
|
*
|
||||||
|
* @author Gail Badner
|
||||||
|
*/
|
||||||
|
public class StaticPrecisionFspTimestampFunction extends NoArgSQLFunction {
|
||||||
|
private final String renderedString;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a {@link org.hibernate.type.StandardBasicTypes#TIMESTAMP} function using the
|
||||||
|
* default fractional second precision as defined by the database.
|
||||||
|
*
|
||||||
|
* @param name The function name
|
||||||
|
* @param hasParenthesesIfNoArguments Does the function call need parenthesis if there are no arguments?
|
||||||
|
*/
|
||||||
|
public StaticPrecisionFspTimestampFunction(String name, boolean hasParenthesesIfNoArguments) {
|
||||||
|
super( name, StandardBasicTypes.TIMESTAMP, hasParenthesesIfNoArguments );
|
||||||
|
renderedString = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a {@link org.hibernate.type.StandardBasicTypes#TIMESTAMP} function using
|
||||||
|
* the specified fractional seconds precision.
|
||||||
|
* @param name The function name
|
||||||
|
* @param fsp The explicit fractional seconds precision to render
|
||||||
|
*
|
||||||
|
* @throws java.lang.IllegalArgumentException if {@code fsp} < 0.
|
||||||
|
*/
|
||||||
|
public StaticPrecisionFspTimestampFunction(String name, int fsp) {
|
||||||
|
super( name, StandardBasicTypes.TIMESTAMP);
|
||||||
|
if ( fsp < 0 ) {
|
||||||
|
throw new IllegalArgumentException( "fsp must be >= 0" );
|
||||||
|
}
|
||||||
|
renderedString = name + '(' + fsp + ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String render(Type argumentType, List args, SessionFactoryImplementor factory) throws QueryException {
|
||||||
|
if ( args.size() > 0 ) {
|
||||||
|
throw new QueryException( "function takes no arguments: " + getName() );
|
||||||
|
}
|
||||||
|
return renderedString == null ?
|
||||||
|
super.render( argumentType, args, factory ) :
|
||||||
|
renderedString;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,102 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014, Red Hat Inc. or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat Inc.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.temporal;
|
||||||
|
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.hibernate.Query;
|
||||||
|
import org.hibernate.Session;
|
||||||
|
import org.hibernate.Transaction;
|
||||||
|
import org.hibernate.dialect.MySQL57InnoDBDialect;
|
||||||
|
import org.hibernate.testing.RequiresDialect;
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Gail Badner.
|
||||||
|
*/
|
||||||
|
@TestForIssue( jiraKey = "HHH-8401")
|
||||||
|
@RequiresDialect( MySQL57InnoDBDialect.class )
|
||||||
|
public class MySQL57TimestampFspFunctionTest extends BaseCoreFunctionalTestCase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTimeStampFunctions() {
|
||||||
|
// add an entity just so it can be queried.
|
||||||
|
|
||||||
|
Session s=openSession();
|
||||||
|
Transaction tx = s.beginTransaction();
|
||||||
|
s.persist( new Entity() );
|
||||||
|
tx.commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
tx = s.beginTransaction();
|
||||||
|
|
||||||
|
// current_timestamp(), localtime(), and localtimestamp() are synonyms for now(),
|
||||||
|
// which returns the time at which the statement began to execute.
|
||||||
|
// the returned values for now(), current_timestamp(), localtime(), and
|
||||||
|
// localtimestamp() should be the same.
|
||||||
|
// sysdate() is the time at which the function itself is executed, so the
|
||||||
|
// value returned for sysdate() should be different.
|
||||||
|
Query q=s.createQuery(
|
||||||
|
"select now(), current_timestamp(), localtime(), localtimestamp(), sysdate() from MySQL57TimestampFspFunctionTest$Entity"
|
||||||
|
);
|
||||||
|
Object[] oArray = (Object[]) q.uniqueResult();
|
||||||
|
final Timestamp now = (Timestamp) oArray[0];
|
||||||
|
assertEquals( now, oArray[1] );
|
||||||
|
assertEquals( now, oArray[2] );
|
||||||
|
assertEquals( now, oArray[3] );
|
||||||
|
final Timestamp sysdate = (Timestamp) oArray[4];
|
||||||
|
assertTrue( now.compareTo( sysdate ) < 0 );
|
||||||
|
// all should have nanos > 0
|
||||||
|
assertTrue( now.getNanos() > 0 );
|
||||||
|
assertTrue( sysdate.getNanos() > 0 );
|
||||||
|
|
||||||
|
tx.commit();
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
|
return new Class[] { Entity.class };
|
||||||
|
}
|
||||||
|
|
||||||
|
// If MySQL supported something like Oracle's "dual", then this entity wouldn't be needed.
|
||||||
|
@javax.persistence.Entity
|
||||||
|
@Table(name = "DummyEntity")
|
||||||
|
public static class Entity {
|
||||||
|
@GeneratedValue
|
||||||
|
@Id
|
||||||
|
private long id;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,225 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014, Red Hat, Inc. and/or its affiliates or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.temporal;
|
||||||
|
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Temporal;
|
||||||
|
import javax.persistence.TemporalType;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.hibernate.Query;
|
||||||
|
import org.hibernate.Session;
|
||||||
|
import org.hibernate.annotations.ColumnDefault;
|
||||||
|
import org.hibernate.annotations.Generated;
|
||||||
|
import org.hibernate.annotations.GenerationTime;
|
||||||
|
import org.hibernate.dialect.MySQL57InnoDBDialect;
|
||||||
|
import org.hibernate.dialect.MySQLDialect;
|
||||||
|
import org.hibernate.dialect.SybaseDialect;
|
||||||
|
import org.hibernate.testing.RequiresDialect;
|
||||||
|
import org.hibernate.testing.SkipForDialect;
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||||
|
|
||||||
|
import static junit.framework.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Gail Badner
|
||||||
|
*/
|
||||||
|
@RequiresDialect(value = MySQL57InnoDBDialect.class)
|
||||||
|
@TestForIssue( jiraKey = "HHH-8401")
|
||||||
|
public class MySQL57TimestampPropertyTest extends BaseCoreFunctionalTestCase {
|
||||||
|
private final DateFormat timestampFormat = new SimpleDateFormat("HH:mm:ss.SSS");
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTime() {
|
||||||
|
final Entity eOrig = new Entity();
|
||||||
|
eOrig.ts = new Date();
|
||||||
|
|
||||||
|
Session s = openSession();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
s.persist( eOrig );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
final Entity eGotten = (Entity) s.get( Entity.class, eOrig.id );
|
||||||
|
final String tsOrigFormatted = timestampFormat.format( eOrig.ts );
|
||||||
|
final String tsGottenFormatted = timestampFormat.format( eGotten.ts );
|
||||||
|
assertEquals( tsOrigFormatted , tsGottenFormatted );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
final Query queryWithParameter = s.createQuery( "from MySQL57TimestampPropertyTest$Entity where ts=?" ).setParameter( 0, eOrig.ts );
|
||||||
|
final Entity eQueriedWithParameter = (Entity) queryWithParameter.uniqueResult();
|
||||||
|
assertNotNull( eQueriedWithParameter );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
final Query queryWithTimestamp = s.createQuery( "from MySQL57TimestampPropertyTest$Entity where ts=?" ).setTimestamp( 0, eOrig.ts );
|
||||||
|
final Entity eQueriedWithTimestamp = (Entity) queryWithTimestamp.uniqueResult();
|
||||||
|
assertNotNull( eQueriedWithTimestamp );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
s.delete( eQueriedWithTimestamp );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTimeGeneratedByColumnDefault() {
|
||||||
|
final Entity eOrig = new Entity();
|
||||||
|
|
||||||
|
Session s = openSession();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
s.persist( eOrig );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
assertNotNull( eOrig.tsColumnDefault );
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
final Entity eGotten = (Entity) s.get( Entity.class, eOrig.id );
|
||||||
|
final String tsColumnDefaultOrigFormatted = timestampFormat.format( eOrig.tsColumnDefault );
|
||||||
|
final String tsColumnDefaultGottenFormatted = timestampFormat.format( eGotten.tsColumnDefault );
|
||||||
|
assertEquals( tsColumnDefaultOrigFormatted , tsColumnDefaultGottenFormatted );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
final Query queryWithParameter =
|
||||||
|
s.createQuery( "from MySQL57TimestampPropertyTest$Entity where tsColumnDefault=?" )
|
||||||
|
.setParameter( 0, eOrig.tsColumnDefault );
|
||||||
|
final Entity eQueriedWithParameter = (Entity) queryWithParameter.uniqueResult();
|
||||||
|
assertNotNull( eQueriedWithParameter );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
final Query queryWithTimestamp =
|
||||||
|
s.createQuery( "from MySQL57TimestampPropertyTest$Entity where tsColumnDefault=?" )
|
||||||
|
.setTimestamp( 0, eOrig.tsColumnDefault );
|
||||||
|
final Entity eQueriedWithTimestamp = (Entity) queryWithTimestamp.uniqueResult();
|
||||||
|
assertNotNull( eQueriedWithTimestamp );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
s.delete( eQueriedWithTimestamp );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTimeGeneratedByColumnDefinition() {
|
||||||
|
final Entity eOrig = new Entity();
|
||||||
|
|
||||||
|
Session s = openSession();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
s.persist( eOrig );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
assertNotNull( eOrig.tsColumnDefinition );
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
final Entity eGotten = (Entity) s.get( Entity.class, eOrig.id );
|
||||||
|
final String tsColumnDefinitionOrigFormatted = timestampFormat.format( eOrig.tsColumnDefinition );
|
||||||
|
final String tsColumnDefinitionGottenFormatted = timestampFormat.format( eGotten.tsColumnDefinition );
|
||||||
|
assertEquals( tsColumnDefinitionOrigFormatted , tsColumnDefinitionGottenFormatted );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
final Query queryWithParameter =
|
||||||
|
s.createQuery( "from MySQL57TimestampPropertyTest$Entity where tsColumnDefinition=?" )
|
||||||
|
.setParameter( 0, eOrig.tsColumnDefinition );
|
||||||
|
final Entity eQueriedWithParameter = (Entity) queryWithParameter.uniqueResult();
|
||||||
|
assertNotNull( eQueriedWithParameter );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
final Query queryWithTimestamp =
|
||||||
|
s.createQuery( "from MySQL57TimestampPropertyTest$Entity where tsColumnDefinition=?" )
|
||||||
|
.setTimestamp( 0, eOrig.tsColumnDefinition );
|
||||||
|
final Entity eQueriedWithTimestamp = (Entity) queryWithTimestamp.uniqueResult();
|
||||||
|
assertNotNull( eQueriedWithTimestamp );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
s.delete( eQueriedWithTimestamp );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
|
return new Class[] { Entity.class };
|
||||||
|
}
|
||||||
|
|
||||||
|
@javax.persistence.Entity
|
||||||
|
public static class Entity {
|
||||||
|
@GeneratedValue
|
||||||
|
@Id
|
||||||
|
private long id;
|
||||||
|
|
||||||
|
@Temporal( value = TemporalType.TIMESTAMP)
|
||||||
|
private Date ts;
|
||||||
|
|
||||||
|
@Temporal( value = TemporalType.TIMESTAMP )
|
||||||
|
@Generated( value = GenerationTime.INSERT )
|
||||||
|
@ColumnDefault( value = "CURRENT_TIMESTAMP(6)" )
|
||||||
|
private Date tsColumnDefault;
|
||||||
|
|
||||||
|
@Temporal( value = TemporalType.TIMESTAMP )
|
||||||
|
@Generated( value = GenerationTime.INSERT )
|
||||||
|
@Column( columnDefinition = "datetime(6) default NOW(6)" )
|
||||||
|
private Date tsColumnDefinition;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,102 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014, Red Hat, Inc. and/or its affiliates or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.temporal;
|
||||||
|
|
||||||
|
import java.sql.Time;
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Temporal;
|
||||||
|
import javax.persistence.TemporalType;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.hibernate.Query;
|
||||||
|
import org.hibernate.Session;
|
||||||
|
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||||
|
|
||||||
|
import static junit.framework.Assert.assertEquals;
|
||||||
|
import static junit.framework.Assert.assertNotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Gail Badner
|
||||||
|
*/
|
||||||
|
public class TimePropertyTest extends BaseCoreFunctionalTestCase {
|
||||||
|
private final DateFormat timeFormat = new SimpleDateFormat("HH:mm:ss");
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTimeAsDate() {
|
||||||
|
final Entity eOrig = new Entity();
|
||||||
|
eOrig.tAsDate = new Time( new Date().getTime() );
|
||||||
|
|
||||||
|
Session s = openSession();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
s.persist( eOrig );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
final Entity eGotten = (Entity) s.get( Entity.class, eOrig.id );
|
||||||
|
// Some databases retain the milliseconds when being inserted and some don't;
|
||||||
|
final String tAsDateOrigFormatted = timeFormat.format( eOrig.tAsDate );
|
||||||
|
final String tAsDateGottenFormatted = timeFormat.format( eGotten.tAsDate );
|
||||||
|
assertEquals( tAsDateOrigFormatted, tAsDateGottenFormatted );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
final Query query = s.createQuery( "from TimePropertyTest$Entity where tAsDate=?" ).setTime( 0, eOrig.tAsDate );
|
||||||
|
final Entity eQueried = (Entity) query.uniqueResult();
|
||||||
|
assertNotNull( eQueried );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
s.delete( eQueried );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
|
return new Class[] { Entity.class };
|
||||||
|
}
|
||||||
|
|
||||||
|
@javax.persistence.Entity
|
||||||
|
public static class Entity {
|
||||||
|
@GeneratedValue
|
||||||
|
@Id
|
||||||
|
private long id;
|
||||||
|
|
||||||
|
@Temporal( value = TemporalType.TIME )
|
||||||
|
private java.util.Date tAsDate;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,227 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014, Red Hat, Inc. and/or its affiliates or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.temporal;
|
||||||
|
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Temporal;
|
||||||
|
import javax.persistence.TemporalType;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.hibernate.Query;
|
||||||
|
import org.hibernate.Session;
|
||||||
|
import org.hibernate.annotations.ColumnDefault;
|
||||||
|
import org.hibernate.annotations.Generated;
|
||||||
|
import org.hibernate.annotations.GenerationTime;
|
||||||
|
import org.hibernate.dialect.MySQLDialect;
|
||||||
|
import org.hibernate.dialect.SybaseDialect;
|
||||||
|
import org.hibernate.testing.SkipForDialect;
|
||||||
|
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||||
|
|
||||||
|
import static junit.framework.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that persisted timestamp properties have the expected format to milliseconds
|
||||||
|
* and tests that entities can be queried by timestamp value.
|
||||||
|
*
|
||||||
|
* See Mysql57TimestampFspTest for tests using MySQL 5.7. MySQL 5.7 is tested separately
|
||||||
|
* because it requires CURRENT_TIMESTAMP(6) or NOW(6) as a default.
|
||||||
|
*
|
||||||
|
* @author Gail Badner
|
||||||
|
*/
|
||||||
|
@SkipForDialect( value={SybaseDialect.class, MySQLDialect.class}, comment="CURRENT_TIMESTAMP not supported as default value in Sybase or MySQL" )
|
||||||
|
public class TimestampPropertyTest extends BaseCoreFunctionalTestCase {
|
||||||
|
private final DateFormat timestampFormat = new SimpleDateFormat("HH:mm:ss.SSS");
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTime() {
|
||||||
|
final Entity eOrig = new Entity();
|
||||||
|
eOrig.ts = new Date();
|
||||||
|
|
||||||
|
Session s = openSession();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
s.persist( eOrig );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
final Entity eGotten = (Entity) s.get( Entity.class, eOrig.id );
|
||||||
|
final String tsOrigFormatted = timestampFormat.format( eOrig.ts );
|
||||||
|
final String tsGottenFormatted = timestampFormat.format( eGotten.ts );
|
||||||
|
assertEquals( tsOrigFormatted , tsGottenFormatted );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
final Query queryWithParameter = s.createQuery( "from TimestampPropertyTest$Entity where ts=?" ).setParameter( 0, eOrig.ts );
|
||||||
|
final Entity eQueriedWithParameter = (Entity) queryWithParameter.uniqueResult();
|
||||||
|
assertNotNull( eQueriedWithParameter );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
final Query queryWithTimestamp = s.createQuery( "from TimestampPropertyTest$Entity where ts=?" ).setTimestamp( 0, eOrig.ts );
|
||||||
|
final Entity eQueriedWithTimestamp = (Entity) queryWithTimestamp.uniqueResult();
|
||||||
|
assertNotNull( eQueriedWithTimestamp );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
s.delete( eQueriedWithTimestamp );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTimeGeneratedByColumnDefault() {
|
||||||
|
final Entity eOrig = new Entity();
|
||||||
|
|
||||||
|
Session s = openSession();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
s.persist( eOrig );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
assertNotNull( eOrig.tsColumnDefault );
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
final Entity eGotten = (Entity) s.get( Entity.class, eOrig.id );
|
||||||
|
final String tsColumnDefaultOrigFormatted = timestampFormat.format( eOrig.tsColumnDefault );
|
||||||
|
final String tsColumnDefaultGottenFormatted = timestampFormat.format( eGotten.tsColumnDefault );
|
||||||
|
assertEquals( tsColumnDefaultOrigFormatted , tsColumnDefaultGottenFormatted );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
final Query queryWithParameter =
|
||||||
|
s.createQuery( "from TimestampPropertyTest$Entity where tsColumnDefault=?" )
|
||||||
|
.setParameter( 0, eOrig.tsColumnDefault );
|
||||||
|
final Entity eQueriedWithParameter = (Entity) queryWithParameter.uniqueResult();
|
||||||
|
assertNotNull( eQueriedWithParameter );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
final Query queryWithTimestamp =
|
||||||
|
s.createQuery( "from TimestampPropertyTest$Entity where tsColumnDefault=?" )
|
||||||
|
.setTimestamp( 0, eOrig.tsColumnDefault );
|
||||||
|
final Entity eQueriedWithTimestamp = (Entity) queryWithTimestamp.uniqueResult();
|
||||||
|
assertNotNull( eQueriedWithTimestamp );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
s.delete( eQueriedWithTimestamp );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTimeGeneratedByColumnDefinition() {
|
||||||
|
final Entity eOrig = new Entity();
|
||||||
|
|
||||||
|
Session s = openSession();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
s.persist( eOrig );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
assertNotNull( eOrig.tsColumnDefinition );
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
final Entity eGotten = (Entity) s.get( Entity.class, eOrig.id );
|
||||||
|
final String tsColumnDefinitionOrigFormatted = timestampFormat.format( eOrig.tsColumnDefinition );
|
||||||
|
final String tsColumnDefinitionGottenFormatted = timestampFormat.format( eGotten.tsColumnDefinition );
|
||||||
|
assertEquals( tsColumnDefinitionOrigFormatted , tsColumnDefinitionGottenFormatted );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
final Query queryWithParameter =
|
||||||
|
s.createQuery( "from TimestampPropertyTest$Entity where tsColumnDefinition=?" )
|
||||||
|
.setParameter( 0, eOrig.tsColumnDefinition );
|
||||||
|
final Entity eQueriedWithParameter = (Entity) queryWithParameter.uniqueResult();
|
||||||
|
assertNotNull( eQueriedWithParameter );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
final Query queryWithTimestamp =
|
||||||
|
s.createQuery( "from TimestampPropertyTest$Entity where tsColumnDefinition=?" )
|
||||||
|
.setTimestamp( 0, eOrig.tsColumnDefinition );
|
||||||
|
final Entity eQueriedWithTimestamp = (Entity) queryWithTimestamp.uniqueResult();
|
||||||
|
assertNotNull( eQueriedWithTimestamp );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
s.delete( eQueriedWithTimestamp );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
|
return new Class[] { Entity.class };
|
||||||
|
}
|
||||||
|
|
||||||
|
@javax.persistence.Entity
|
||||||
|
public static class Entity {
|
||||||
|
@GeneratedValue
|
||||||
|
@Id
|
||||||
|
private long id;
|
||||||
|
|
||||||
|
@Temporal( value = TemporalType.TIMESTAMP)
|
||||||
|
private Date ts;
|
||||||
|
|
||||||
|
@Temporal( value = TemporalType.TIMESTAMP )
|
||||||
|
@Generated( value = GenerationTime.INSERT )
|
||||||
|
@ColumnDefault( value = "CURRENT_TIMESTAMP" )
|
||||||
|
private Date tsColumnDefault;
|
||||||
|
|
||||||
|
@Temporal( value = TemporalType.TIMESTAMP )
|
||||||
|
@Generated( value = GenerationTime.INSERT )
|
||||||
|
@Column( columnDefinition = "datetime(6) default NOW(6)" )
|
||||||
|
private Date tsColumnDefinition;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue