/* * Hibernate, Relational Persistence for Idiomatic Java * * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>. */ package org.hibernate.jpa.test.procedure; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.sql.Timestamp; import java.util.Calendar; import java.util.Collections; import java.util.Date; import java.util.GregorianCalendar; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.EntityManager; import javax.persistence.Id; import javax.persistence.ParameterMode; import javax.persistence.StoredProcedureQuery; import javax.persistence.Table; import javax.persistence.Temporal; import javax.persistence.TemporalType; import org.hibernate.dialect.DerbyTenSevenDialect; import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess; import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.jpa.AvailableSettings; import org.hibernate.jpa.HibernateEntityManagerFactory; import org.hibernate.jpa.boot.spi.Bootstrap; import org.hibernate.jpa.boot.spi.PersistenceUnitDescriptor; import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; import org.hibernate.testing.junit4.BaseUnitTestCase; import org.junit.After; import org.junit.Before; import org.junit.Test; import static org.junit.Assert.assertEquals; /** * @author Steve Ebersole */ public class DateTimeParameterTest extends BaseUnitTestCase { HibernateEntityManagerFactory entityManagerFactory; private static GregorianCalendar nowCal = new GregorianCalendar(); private static Date now = new Date( nowCal.getTime().getTime() ); @Test public void testBindingCalendarAsDate() { EntityManager em = entityManagerFactory.createEntityManager(); em.getTransaction().begin(); try { StoredProcedureQuery query = em.createStoredProcedureQuery( "findMessagesByDate" ); query.registerStoredProcedureParameter( 1, Calendar.class, ParameterMode.IN ); query.setParameter( 1, nowCal, TemporalType.DATE ); List list = query.getResultList(); assertEquals( 1, list.size() ); } finally { em.getTransaction().rollback(); em.close(); } } @Test public void testBindingCalendarAsTime() { EntityManager em = entityManagerFactory.createEntityManager(); em.getTransaction().begin(); try { StoredProcedureQuery query = em.createStoredProcedureQuery( "findMessagesByTime" ); query.registerStoredProcedureParameter( 1, Calendar.class, ParameterMode.IN ); query.setParameter( 1, nowCal, TemporalType.TIME ); List list = query.getResultList(); assertEquals( 1, list.size() ); } finally { em.getTransaction().rollback(); em.close(); } } @Before public void startUp() { // create the EMF entityManagerFactory = Bootstrap.getEntityManagerFactoryBuilder( buildPersistenceUnitDescriptor(), buildSettingsMap() ).build().unwrap( HibernateEntityManagerFactory.class ); // create the procedures createTestData( entityManagerFactory ); createProcedures( entityManagerFactory ); } private PersistenceUnitDescriptor buildPersistenceUnitDescriptor() { return new BaseEntityManagerFunctionalTestCase.TestingPersistenceUnitDescriptorImpl( getClass().getSimpleName() ); } @SuppressWarnings("unchecked") private Map buildSettingsMap() { Map settings = new HashMap(); settings.put( AvailableSettings.LOADED_CLASSES, Collections.singletonList( Message.class ) ); settings.put( org.hibernate.cfg.AvailableSettings.DIALECT, DerbyTenSevenDialect.class.getName() ); settings.put( org.hibernate.cfg.AvailableSettings.DRIVER, org.apache.derby.jdbc.EmbeddedDriver.class.getName() ); settings.put( org.hibernate.cfg.AvailableSettings.URL, "jdbc:derby:memory:hibernate-orm-testing;create=true" ); settings.put( org.hibernate.cfg.AvailableSettings.USER, "" ); settings.put( org.hibernate.cfg.AvailableSettings.HBM2DDL_AUTO, "create-drop" ); return settings; } @After public void tearDown() { if ( entityManagerFactory == null ) { return; } deleteTestData( entityManagerFactory ); dropProcedures( entityManagerFactory ); entityManagerFactory.close(); } private void createProcedures(HibernateEntityManagerFactory emf) { final SessionFactoryImplementor sf = emf.unwrap( SessionFactoryImplementor.class ); final JdbcConnectionAccess connectionAccess = sf.getServiceRegistry().getService( JdbcServices.class ).getBootstrapJdbcConnectionAccess(); final Connection conn; try { conn = connectionAccess.obtainConnection(); conn.setAutoCommit( false ); try { Statement statement = conn.createStatement(); // drop them, just to be sure try { dropProcedures( statement ); } catch (SQLException ignore) { } statement.execute( "CREATE PROCEDURE findMessagesByDate(IN chkDt DATE) " + "language java " + "dynamic result sets 1 " + "external name 'org.hibernate.jpa.test.procedure.DateTimeParameterTest.findMessagesByDate' " + "parameter style java" ); statement.execute( "CREATE PROCEDURE findMessagesByTime(IN chkTime TIME) " + "language java " + "dynamic result sets 1 " + "external name 'org.hibernate.jpa.test.procedure.DateTimeParameterTest.findMessagesByTime' " + "parameter style java" ); statement.execute( "CREATE PROCEDURE findMessagesByTimestampRange(IN startDt TIMESTAMP, IN endDt TIMESTAMP) " + "language java " + "dynamic result sets 1 " + "external name 'org.hibernate.jpa.test.procedure.DateTimeParameterTest.findMessagesByTimestampRange' " + "parameter style java" ); statement.execute( "CREATE PROCEDURE retrieveTimestamp(IN ts1 TIMESTAMP, OUT ts2 TIMESTAMP) " + "language java " + "dynamic result sets 0 " + "external name 'org.hibernate.jpa.test.procedure.DateTimeParameterTest.retrieveTimestamp' " + "parameter style java" ); try { statement.close(); } catch (SQLException ignore) { } } finally { try { conn.commit(); } catch (SQLException e) { System.out.println( "Unable to commit transaction after creating creating procedures"); } try { connectionAccess.releaseConnection( conn ); } catch (SQLException ignore) { } } } catch (SQLException e) { throw new RuntimeException( "Unable to create stored procedures", e ); } } private void dropProcedures(Statement statement) throws SQLException { statement.execute( "DROP PROCEDURE findMessagesByDate" ); statement.execute( "DROP PROCEDURE findMessagesByTime" ); statement.execute( "DROP PROCEDURE findMessagesByTimestampRange" ); statement.execute( "DROP PROCEDURE retrieveTimestamp" ); } public static void findMessagesByDate(java.sql.Date date, ResultSet[] results) throws SQLException { Connection conn = DriverManager.getConnection( "jdbc:default:connection" ); PreparedStatement ps = conn.prepareStatement( "select * from msg where post_date=?" ); ps.setDate( 1, date ); results[0] = ps.executeQuery(); conn.close(); } public static void findMessagesByTime(java.sql.Time time, ResultSet[] results) throws SQLException { Connection conn = DriverManager.getConnection( "jdbc:default:connection" ); PreparedStatement ps = conn.prepareStatement( "select * from msg where post_time=?" ); ps.setTime( 1, time ); results[0] = ps.executeQuery(); conn.close(); } public static void findMessagesByTimestampRange(Timestamp start, Timestamp end, ResultSet[] results) throws SQLException { Connection conn = DriverManager.getConnection( "jdbc:default:connection" ); PreparedStatement ps = conn.prepareStatement( "select * from msg where ts between ? and ?" ); ps.setDate( 1, new java.sql.Date( start.getTime() ) ); ps.setDate( 2, new java.sql.Date( end.getTime() ) ); results[0] = ps.executeQuery(); conn.close(); } public static void retrieveTimestamp(Timestamp in, Timestamp[] out ) throws SQLException { out[0] = in; } private void createTestData(HibernateEntityManagerFactory entityManagerFactory) { EntityManager em = entityManagerFactory.createEntityManager(); em.getTransaction().begin(); em.persist( new Message( 1, "test", now, now, now ) ); em.getTransaction().commit(); em.close(); } private void deleteTestData(HibernateEntityManagerFactory entityManagerFactory) { EntityManager em = entityManagerFactory.createEntityManager(); em.getTransaction().begin(); em.createQuery( "delete from Message" ).executeUpdate(); em.getTransaction().commit(); em.close(); } private void dropProcedures(HibernateEntityManagerFactory emf) { final SessionFactoryImplementor sf = emf.unwrap( SessionFactoryImplementor.class ); final JdbcConnectionAccess connectionAccess = sf.getServiceRegistry().getService( JdbcServices.class ).getBootstrapJdbcConnectionAccess(); final Connection conn; try { conn = connectionAccess.obtainConnection(); conn.setAutoCommit( false ); try { Statement statement = conn.createStatement(); dropProcedures( statement ); try { statement.close(); } catch (SQLException ignore) { } } finally { try { conn.commit(); } catch (SQLException e) { System.out.println( "Unable to commit transaction after creating dropping procedures"); } try { connectionAccess.releaseConnection( conn ); } catch (SQLException ignore) { } } } catch (SQLException e) { throw new RuntimeException( "Unable to drop stored procedures", e ); } } @Entity( name = "Message" ) @Table( name = "MSG" ) public static class Message { @Id private Integer id; private String body; @Column( name = "POST_DATE" ) @Temporal( TemporalType.DATE ) private Date postDate; @Column( name = "POST_TIME" ) @Temporal( TemporalType.TIME ) private Date postTime; @Column( name = "TS" ) @Temporal( TemporalType.TIMESTAMP ) private Date ts; public Message() { } public Message(Integer id, String body, Date postDate, Date postTime, Date ts) { this.id = id; this.body = body; this.postDate = postDate; this.postTime = postTime; this.ts = ts; } } }