From 7cae5ba95bf355d1023c25820e45eaf5f984bcb7 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Thu, 12 May 2016 21:21:31 -0500 Subject: [PATCH] HHH-9340 - Streams API for query result processing. --- .../java/org/hibernate/ScrollableResults.java | 80 ++++++++++--------- .../src/main/java/org/hibernate/Session.java | 2 +- .../java/org/hibernate/StatelessSession.java | 34 ++++---- .../hibernate/engine/HibernateIterator.java | 4 +- .../engine/query/spi/HQLQueryPlan.java | 3 +- .../engine/spi/SessionDelegatorBaseImpl.java | 11 ++- .../spi/SharedSessionContractImplementor.java | 9 ++- .../hql/internal/ast/QueryTranslatorImpl.java | 3 +- .../internal/classic/QueryTranslatorImpl.java | 3 +- .../hibernate/hql/spi/QueryTranslator.java | 3 +- .../internal/AbstractScrollableResults.java | 31 ++++++- .../internal/AbstractSessionImpl.java | 2 - .../AbstractSharedSessionContract.java | 3 +- .../org/hibernate/internal/SessionImpl.java | 7 +- .../internal/StatelessSessionImpl.java | 7 +- .../java/org/hibernate/loader/Loader.java | 3 +- .../loader/criteria/CriteriaLoader.java | 3 +- .../hibernate/loader/custom/CustomLoader.java | 3 +- .../org/hibernate/loader/hql/QueryLoader.java | 3 +- .../main/java/org/hibernate/query/Query.java | 16 ++++ .../query/internal/AbstractProducedQuery.java | 25 +++++- .../query/internal/CollectionFilterImpl.java | 5 +- .../query/internal/NativeQueryImpl.java | 3 +- .../internal/ScrollableResultsIterator.java | 41 ++++++++++ .../query/spi/CloseableIterator.java | 24 ++++++ .../spi/ScrollableResultsImplementor.java | 20 +++++ .../test/stream/basic/BasicStreamTest.java | 61 ++++++++++++++ 27 files changed, 314 insertions(+), 95 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/query/internal/ScrollableResultsIterator.java create mode 100644 hibernate-core/src/main/java/org/hibernate/query/spi/CloseableIterator.java create mode 100644 hibernate-core/src/main/java/org/hibernate/query/spi/ScrollableResultsImplementor.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/stream/basic/BasicStreamTest.java diff --git a/hibernate-core/src/main/java/org/hibernate/ScrollableResults.java b/hibernate-core/src/main/java/org/hibernate/ScrollableResults.java index 012ebe789a..0242684190 100644 --- a/hibernate-core/src/main/java/org/hibernate/ScrollableResults.java +++ b/hibernate-core/src/main/java/org/hibernate/ScrollableResults.java @@ -5,6 +5,7 @@ * See the lgpl.txt file in the root directory or . */ package org.hibernate; + import java.math.BigDecimal; import java.math.BigInteger; import java.sql.Blob; @@ -29,20 +30,26 @@ import org.hibernate.type.Type; * * @author Gavin King */ -public interface ScrollableResults extends java.io.Closeable { +public interface ScrollableResults extends AutoCloseable { + + /** + * Release resources immediately. + */ + void close(); + /** * Advance to the next result. * * @return {@code true} if there is another result */ - public boolean next(); + boolean next(); /** * Retreat to the previous result. * * @return {@code true} if there is a previous result */ - public boolean previous(); + boolean previous(); /** * Scroll the specified number of positions from the current position. @@ -51,53 +58,53 @@ public interface ScrollableResults extends java.io.Closeable { * * @return {@code true} if there is a result at the new location */ - public boolean scroll(int positions); + boolean scroll(int positions); /** * Go to the last result. * * @return {@code true} if there are any results */ - public boolean last(); + boolean last(); /** * Go to the first result. * * @return {@code true} if there are any results */ - public boolean first(); + boolean first(); /** * Go to a location just beforeQuery first result, This is the location of the cursor on a newly returned * scrollable result. */ - public void beforeFirst(); + void beforeFirst(); /** * Go to a location just afterQuery the last result. */ - public void afterLast(); + void afterLast(); /** * Is this the first result? * * @return {@code true} if this is the first row of results, otherwise {@code false} */ - public boolean isFirst(); + boolean isFirst(); /** * Is this the last result? * * @return {@code true} if this is the last row of results. */ - public boolean isLast(); + boolean isLast(); /** * Get the current position in the results. The first position is number 0 (unlike JDBC). * * @return The current position number, numbered from 0; -1 indicates that there is no current row */ - public int getRowNumber(); + int getRowNumber(); /** * Set the current position in the result set. Can be numbered from the first position (positive number) or @@ -108,19 +115,14 @@ public interface ScrollableResults extends java.io.Closeable { * * @return true if there is a row at that row number */ - public boolean setRowNumber(int rowNumber); - - /** - * Release resources immediately. - */ - public void close(); + boolean setRowNumber(int rowNumber); /** * Get the current row of results. * * @return The array of results */ - public Object[] get(); + Object[] get(); /** * Get the ith object in the current row of results, without @@ -134,7 +136,7 @@ public interface ScrollableResults extends java.io.Closeable { * * @throws IndexOutOfBoundsException If i is an invalid index. */ - public Object get(int i); + Object get(int i); /** * Get the type of the ith column of results. @@ -145,7 +147,7 @@ public interface ScrollableResults extends java.io.Closeable { * * @throws IndexOutOfBoundsException If i is an invalid index. */ - public Type getType(int i); + Type getType(int i); /** * Convenience method to read an integer. @@ -156,7 +158,7 @@ public interface ScrollableResults extends java.io.Closeable { * * @throws IndexOutOfBoundsException If col is an invalid index. */ - public Integer getInteger(int col); + Integer getInteger(int col); /** * Convenience method to read a long. @@ -167,7 +169,7 @@ public interface ScrollableResults extends java.io.Closeable { * * @throws IndexOutOfBoundsException If col is an invalid index. */ - public Long getLong(int col); + Long getLong(int col); /** * Convenience method to read a float. @@ -178,7 +180,7 @@ public interface ScrollableResults extends java.io.Closeable { * * @throws IndexOutOfBoundsException If col is an invalid index. */ - public Float getFloat(int col); + Float getFloat(int col); /** * Convenience method to read a boolean. @@ -189,7 +191,7 @@ public interface ScrollableResults extends java.io.Closeable { * * @throws IndexOutOfBoundsException If col is an invalid index. */ - public Boolean getBoolean(int col); + Boolean getBoolean(int col); /** * Convenience method to read a double. @@ -200,7 +202,7 @@ public interface ScrollableResults extends java.io.Closeable { * * @throws IndexOutOfBoundsException If col is an invalid index. */ - public Double getDouble(int col); + Double getDouble(int col); /** * Convenience method to read a short. @@ -211,7 +213,7 @@ public interface ScrollableResults extends java.io.Closeable { * * @throws IndexOutOfBoundsException If col is an invalid index. */ - public Short getShort(int col); + Short getShort(int col); /** * Convenience method to read a byte. @@ -222,7 +224,7 @@ public interface ScrollableResults extends java.io.Closeable { * * @throws IndexOutOfBoundsException If col is an invalid index. */ - public Byte getByte(int col); + Byte getByte(int col); /** * Convenience method to read a char. @@ -233,7 +235,7 @@ public interface ScrollableResults extends java.io.Closeable { * * @throws IndexOutOfBoundsException If col is an invalid index. */ - public Character getCharacter(int col); + Character getCharacter(int col); /** * Convenience method to read a binary (byte[]). @@ -244,7 +246,7 @@ public interface ScrollableResults extends java.io.Closeable { * * @throws IndexOutOfBoundsException If col is an invalid index. */ - public byte[] getBinary(int col); + byte[] getBinary(int col); /** * Convenience method to read a String using streaming. @@ -255,7 +257,7 @@ public interface ScrollableResults extends java.io.Closeable { * * @throws IndexOutOfBoundsException If col is an invalid index. */ - public String getText(int col); + String getText(int col); /** * Convenience method to read a blob. @@ -266,7 +268,7 @@ public interface ScrollableResults extends java.io.Closeable { * * @throws IndexOutOfBoundsException If col is an invalid index. */ - public Blob getBlob(int col); + Blob getBlob(int col); /** * Convenience method to read a clob. @@ -277,7 +279,7 @@ public interface ScrollableResults extends java.io.Closeable { * * @throws IndexOutOfBoundsException If col is an invalid index. */ - public Clob getClob(int col); + Clob getClob(int col); /** * Convenience method to read a string. @@ -288,7 +290,7 @@ public interface ScrollableResults extends java.io.Closeable { * * @throws IndexOutOfBoundsException If col is an invalid index. */ - public String getString(int col); + String getString(int col); /** * Convenience method to read a BigDecimal. @@ -299,7 +301,7 @@ public interface ScrollableResults extends java.io.Closeable { * * @throws IndexOutOfBoundsException If col is an invalid index. */ - public BigDecimal getBigDecimal(int col); + BigDecimal getBigDecimal(int col); /** * Convenience method to read a BigInteger. @@ -310,7 +312,7 @@ public interface ScrollableResults extends java.io.Closeable { * * @throws IndexOutOfBoundsException If col is an invalid index. */ - public BigInteger getBigInteger(int col); + BigInteger getBigInteger(int col); /** * Convenience method to read a Date. @@ -321,7 +323,7 @@ public interface ScrollableResults extends java.io.Closeable { * * @throws IndexOutOfBoundsException If col is an invalid index. */ - public Date getDate(int col); + Date getDate(int col); /** * Convenience method to read a Locale. @@ -332,7 +334,7 @@ public interface ScrollableResults extends java.io.Closeable { * * @throws IndexOutOfBoundsException If col is an invalid index. */ - public Locale getLocale(int col); + Locale getLocale(int col); /** * Convenience method to read a Calendar. @@ -343,7 +345,7 @@ public interface ScrollableResults extends java.io.Closeable { * * @throws IndexOutOfBoundsException If col is an invalid index. */ - public Calendar getCalendar(int col); + Calendar getCalendar(int col); /** * Convenience method to read a TimeZone. @@ -354,5 +356,5 @@ public interface ScrollableResults extends java.io.Closeable { * * @throws IndexOutOfBoundsException If col is an invalid index. */ - public TimeZone getTimeZone(int col); + TimeZone getTimeZone(int col); } diff --git a/hibernate-core/src/main/java/org/hibernate/Session.java b/hibernate-core/src/main/java/org/hibernate/Session.java index 373f7c4192..dafb0fd7b6 100644 --- a/hibernate-core/src/main/java/org/hibernate/Session.java +++ b/hibernate-core/src/main/java/org/hibernate/Session.java @@ -80,7 +80,7 @@ import org.hibernate.stat.SessionStatistics; * @author Gavin King * @author Steve Ebersole */ -public interface Session extends SharedSessionContract, EntityManager, HibernateEntityManager, java.io.Closeable { +public interface Session extends SharedSessionContract, EntityManager, HibernateEntityManager, AutoCloseable { /** * Obtain a {@link Session} builder with the ability to grab certain information from this session. * diff --git a/hibernate-core/src/main/java/org/hibernate/StatelessSession.java b/hibernate-core/src/main/java/org/hibernate/StatelessSession.java index 109aa4a21b..a0ace4eb2b 100755 --- a/hibernate-core/src/main/java/org/hibernate/StatelessSession.java +++ b/hibernate-core/src/main/java/org/hibernate/StatelessSession.java @@ -25,11 +25,11 @@ import java.sql.Connection; * * @author Gavin King */ -public interface StatelessSession extends SharedSessionContract, java.io.Closeable { +public interface StatelessSession extends SharedSessionContract, AutoCloseable { /** * Close the stateless session and release the JDBC connection. */ - public void close(); + void close(); /** * Insert a row. @@ -38,7 +38,7 @@ public interface StatelessSession extends SharedSessionContract, java.io.Closeab * * @return The identifier of the inserted entity */ - public Serializable insert(Object entity); + Serializable insert(Object entity); /** * Insert a row. @@ -48,14 +48,14 @@ public interface StatelessSession extends SharedSessionContract, java.io.Closeab * * @return the identifier of the instance */ - public Serializable insert(String entityName, Object entity); + Serializable insert(String entityName, Object entity); /** * Update a row. * * @param entity a detached entity instance */ - public void update(Object entity); + void update(Object entity); /** * Update a row. @@ -63,14 +63,14 @@ public interface StatelessSession extends SharedSessionContract, java.io.Closeab * @param entityName The entityName for the entity to be updated * @param entity a detached entity instance */ - public void update(String entityName, Object entity); + void update(String entityName, Object entity); /** * Delete a row. * * @param entity a detached entity instance */ - public void delete(Object entity); + void delete(Object entity); /** * Delete a row. @@ -78,7 +78,7 @@ public interface StatelessSession extends SharedSessionContract, java.io.Closeab * @param entityName The entityName for the entity to be deleted * @param entity a detached entity instance */ - public void delete(String entityName, Object entity); + void delete(String entityName, Object entity); /** * Retrieve a row. @@ -88,7 +88,7 @@ public interface StatelessSession extends SharedSessionContract, java.io.Closeab * * @return a detached entity instance */ - public Object get(String entityName, Serializable id); + Object get(String entityName, Serializable id); /** * Retrieve a row. @@ -98,7 +98,7 @@ public interface StatelessSession extends SharedSessionContract, java.io.Closeab * * @return a detached entity instance */ - public Object get(Class entityClass, Serializable id); + Object get(Class entityClass, Serializable id); /** * Retrieve a row, obtaining the specified lock mode. @@ -109,7 +109,7 @@ public interface StatelessSession extends SharedSessionContract, java.io.Closeab * * @return a detached entity instance */ - public Object get(String entityName, Serializable id, LockMode lockMode); + Object get(String entityName, Serializable id, LockMode lockMode); /** * Retrieve a row, obtaining the specified lock mode. @@ -120,14 +120,14 @@ public interface StatelessSession extends SharedSessionContract, java.io.Closeab * * @return a detached entity instance */ - public Object get(Class entityClass, Serializable id, LockMode lockMode); + Object get(Class entityClass, Serializable id, LockMode lockMode); /** * Refresh the entity instance state from the database. * * @param entity The entity to be refreshed. */ - public void refresh(Object entity); + void refresh(Object entity); /** * Refresh the entity instance state from the database. @@ -135,7 +135,7 @@ public interface StatelessSession extends SharedSessionContract, java.io.Closeab * @param entityName The entityName for the entity to be refreshed. * @param entity The entity to be refreshed. */ - public void refresh(String entityName, Object entity); + void refresh(String entityName, Object entity); /** * Refresh the entity instance state from the database. @@ -143,7 +143,7 @@ public interface StatelessSession extends SharedSessionContract, java.io.Closeab * @param entity The entity to be refreshed. * @param lockMode The LockMode to be applied. */ - public void refresh(Object entity, LockMode lockMode); + void refresh(Object entity, LockMode lockMode); /** * Refresh the entity instance state from the database. @@ -152,7 +152,7 @@ public interface StatelessSession extends SharedSessionContract, java.io.Closeab * @param entity The entity to be refreshed. * @param lockMode The LockMode to be applied. */ - public void refresh(String entityName, Object entity, LockMode lockMode); + void refresh(String entityName, Object entity, LockMode lockMode); /** * Returns the current JDBC connection associated with this @@ -168,5 +168,5 @@ public interface StatelessSession extends SharedSessionContract, java.io.Closeab * @return The connection associated with this stateless session */ @Deprecated - public Connection connection(); + Connection connection(); } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/HibernateIterator.java b/hibernate-core/src/main/java/org/hibernate/engine/HibernateIterator.java index 933a15b8a6..5fd5c79194 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/HibernateIterator.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/HibernateIterator.java @@ -18,11 +18,11 @@ import org.hibernate.JDBCException; * * @author Gavin King */ -public interface HibernateIterator extends Iterator, java.io.Closeable { +public interface HibernateIterator extends Iterator, AutoCloseable { /** * Close the Hibernate query result iterator * * @throws JDBCException Indicates a problem releasing the underlying JDBC resources. */ - public void close() throws JDBCException; + void close() throws JDBCException; } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/query/spi/HQLQueryPlan.java b/hibernate-core/src/main/java/org/hibernate/engine/query/spi/HQLQueryPlan.java index 5168eb01af..4b758f40e8 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/query/spi/HQLQueryPlan.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/query/spi/HQLQueryPlan.java @@ -36,6 +36,7 @@ import org.hibernate.internal.util.collections.EmptyIterator; import org.hibernate.internal.util.collections.IdentitySet; import org.hibernate.internal.util.collections.JoinedIterator; import org.hibernate.query.internal.ParameterMetadataImpl; +import org.hibernate.query.spi.ScrollableResultsImplementor; import org.hibernate.type.Type; /** @@ -333,7 +334,7 @@ public class HQLQueryPlan implements Serializable { * * @throws HibernateException Indicates a problem performing the query */ - public ScrollableResults performScroll( + public ScrollableResultsImplementor performScroll( QueryParameters queryParameters, SharedSessionContractImplementor session) throws HibernateException { if ( traceEnabled ) { diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionDelegatorBaseImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionDelegatorBaseImpl.java index a180857eef..ccf9975b08 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionDelegatorBaseImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionDelegatorBaseImpl.java @@ -39,12 +39,10 @@ import org.hibernate.MultiIdentifierLoadAccess; import org.hibernate.NaturalIdLoadAccess; import org.hibernate.ReplicationMode; import org.hibernate.ScrollMode; -import org.hibernate.ScrollableResults; import org.hibernate.Session; import org.hibernate.SessionEventListener; import org.hibernate.SharedSessionBuilder; import org.hibernate.SimpleNaturalIdLoadAccess; -import org.hibernate.StaleStateException; import org.hibernate.Transaction; import org.hibernate.TypeHelper; import org.hibernate.UnknownProfileException; @@ -61,6 +59,7 @@ import org.hibernate.persister.entity.EntityPersister; import org.hibernate.procedure.ProcedureCall; import org.hibernate.query.spi.NativeQueryImplementor; import org.hibernate.query.spi.QueryImplementor; +import org.hibernate.query.spi.ScrollableResultsImplementor; import org.hibernate.resource.jdbc.spi.JdbcSessionContext; import org.hibernate.resource.transaction.spi.TransactionCoordinator; import org.hibernate.stat.SessionStatistics; @@ -199,12 +198,12 @@ public class SessionDelegatorBaseImpl implements SessionImplementor { } @Override - public ScrollableResults scroll(String query, QueryParameters queryParameters) throws HibernateException { + public ScrollableResultsImplementor scroll(String query, QueryParameters queryParameters) throws HibernateException { return delegate.scroll( query, queryParameters ); } @Override - public ScrollableResults scroll(Criteria criteria, ScrollMode scrollMode) { + public ScrollableResultsImplementor scroll(Criteria criteria, ScrollMode scrollMode) { return delegate.scroll( criteria, scrollMode ); } @@ -259,7 +258,7 @@ public class SessionDelegatorBaseImpl implements SessionImplementor { } @Override - public ScrollableResults scrollCustomQuery(CustomQuery customQuery, QueryParameters queryParameters) throws HibernateException { + public ScrollableResultsImplementor scrollCustomQuery(CustomQuery customQuery, QueryParameters queryParameters) throws HibernateException { return delegate.scrollCustomQuery( customQuery, queryParameters ); } @@ -269,7 +268,7 @@ public class SessionDelegatorBaseImpl implements SessionImplementor { } @Override - public ScrollableResults scroll(NativeSQLQuerySpecification spec, QueryParameters queryParameters) throws HibernateException { + public ScrollableResultsImplementor scroll(NativeSQLQuerySpecification spec, QueryParameters queryParameters) throws HibernateException { return delegate.scroll( spec, queryParameters ); } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionContractImplementor.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionContractImplementor.java index 8166fbe28c..81e03d7339 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionContractImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionContractImplementor.java @@ -30,6 +30,7 @@ import org.hibernate.engine.query.spi.sql.NativeSQLQuerySpecification; import org.hibernate.loader.custom.CustomQuery; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.query.spi.QueryProducerImplementor; +import org.hibernate.query.spi.ScrollableResultsImplementor; import org.hibernate.resource.jdbc.spi.JdbcSessionOwner; import org.hibernate.resource.transaction.spi.TransactionCoordinator; import org.hibernate.resource.transaction.spi.TransactionCoordinatorBuilder; @@ -223,12 +224,12 @@ public interface SharedSessionContractImplementor /** * Execute a scroll() query */ - ScrollableResults scroll(String query, QueryParameters queryParameters) throws HibernateException; + ScrollableResultsImplementor scroll(String query, QueryParameters queryParameters) throws HibernateException; /** * Execute a criteria query */ - ScrollableResults scroll(Criteria criteria, ScrollMode scrollMode); + ScrollableResultsImplementor scroll(Criteria criteria, ScrollMode scrollMode); /** * Execute a criteria query @@ -290,7 +291,7 @@ public interface SharedSessionContractImplementor /** * Execute an SQL Query */ - ScrollableResults scrollCustomQuery(CustomQuery customQuery, QueryParameters queryParameters) + ScrollableResultsImplementor scrollCustomQuery(CustomQuery customQuery, QueryParameters queryParameters) throws HibernateException; /** @@ -316,7 +317,7 @@ public interface SharedSessionContractImplementor * * @throws HibernateException */ - ScrollableResults scroll(NativeSQLQuerySpecification spec, QueryParameters queryParameters); + ScrollableResultsImplementor scroll(NativeSQLQuerySpecification spec, QueryParameters queryParameters); int getDontFlushFromFind(); diff --git a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/QueryTranslatorImpl.java b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/QueryTranslatorImpl.java index 35235e23e6..8442a5f94e 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/QueryTranslatorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/QueryTranslatorImpl.java @@ -52,6 +52,7 @@ import org.hibernate.internal.util.collections.IdentitySet; import org.hibernate.loader.hql.QueryLoader; import org.hibernate.param.ParameterSpecification; import org.hibernate.persister.entity.Queryable; +import org.hibernate.query.spi.ScrollableResultsImplementor; import org.hibernate.type.Type; import org.jboss.logging.Logger; @@ -416,7 +417,7 @@ public class QueryTranslatorImpl implements FilterTranslator { * Return the query results, as an instance of ScrollableResults */ @Override - public ScrollableResults scroll(QueryParameters queryParameters, SharedSessionContractImplementor session) + public ScrollableResultsImplementor scroll(QueryParameters queryParameters, SharedSessionContractImplementor session) throws HibernateException { // Delegate to the QueryLoader... errorIfDML(); diff --git a/hibernate-core/src/main/java/org/hibernate/hql/internal/classic/QueryTranslatorImpl.java b/hibernate-core/src/main/java/org/hibernate/hql/internal/classic/QueryTranslatorImpl.java index f3c09251f5..a02d09af9e 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/internal/classic/QueryTranslatorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/internal/classic/QueryTranslatorImpl.java @@ -53,6 +53,7 @@ import org.hibernate.persister.collection.QueryableCollection; import org.hibernate.persister.entity.Loadable; import org.hibernate.persister.entity.PropertyMapping; import org.hibernate.persister.entity.Queryable; +import org.hibernate.query.spi.ScrollableResultsImplementor; import org.hibernate.sql.JoinFragment; import org.hibernate.sql.JoinType; import org.hibernate.sql.QuerySelect; @@ -1219,7 +1220,7 @@ public class QueryTranslatorImpl extends BasicLoader implements FilterTranslator } @Override - public ScrollableResults scroll( + public ScrollableResultsImplementor scroll( final QueryParameters queryParameters, final SharedSessionContractImplementor session) throws HibernateException { HolderInstantiator hi = HolderInstantiator.createClassicHolderInstantiator( diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/QueryTranslator.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/QueryTranslator.java index 9220f832aa..679479ae70 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/spi/QueryTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/spi/QueryTranslator.java @@ -19,6 +19,7 @@ import org.hibernate.ScrollableResults; import org.hibernate.engine.spi.QueryParameters; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.event.spi.EventSource; +import org.hibernate.query.spi.ScrollableResultsImplementor; import org.hibernate.type.Type; /** @@ -73,7 +74,7 @@ public interface QueryTranslator { * @return The ScrollableResults wrapper around the query results. * @throws HibernateException */ - ScrollableResults scroll(QueryParameters queryParameters, SharedSessionContractImplementor session) + ScrollableResultsImplementor scroll(QueryParameters queryParameters, SharedSessionContractImplementor session) throws HibernateException; /** diff --git a/hibernate-core/src/main/java/org/hibernate/internal/AbstractScrollableResults.java b/hibernate-core/src/main/java/org/hibernate/internal/AbstractScrollableResults.java index a8f2ca69d1..6dab2d6ef4 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/AbstractScrollableResults.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/AbstractScrollableResults.java @@ -18,11 +18,11 @@ import java.util.Locale; import java.util.TimeZone; import org.hibernate.HibernateException; -import org.hibernate.ScrollableResults; import org.hibernate.engine.spi.QueryParameters; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.hql.internal.HolderInstantiator; import org.hibernate.loader.Loader; +import org.hibernate.query.spi.ScrollableResultsImplementor; import org.hibernate.type.StandardBasicTypes; import org.hibernate.type.Type; @@ -31,7 +31,7 @@ import org.hibernate.type.Type; * * @author Steve Ebersole */ -public abstract class AbstractScrollableResults implements ScrollableResults { +public abstract class AbstractScrollableResults implements ScrollableResultsImplementor { private static final CoreMessageLogger LOG = CoreLogging.messageLogger( AbstractScrollableResults.class ); private final ResultSet resultSet; @@ -41,6 +41,7 @@ public abstract class AbstractScrollableResults implements ScrollableResults { private final QueryParameters queryParameters; private final Type[] types; private HolderInstantiator holderInstantiator; + private boolean closed; protected AbstractScrollableResults( ResultSet rs, @@ -93,6 +94,11 @@ public abstract class AbstractScrollableResults implements ScrollableResults { @Override public final void close() { + if ( this.closed ) { + // noop if already closed + return; + } + // not absolutely necessary, but does help with aggressive release //session.getJDBCContext().getConnectionManager().closeQueryStatement( ps, resultSet ); session.getJdbcCoordinator().getResourceRegistry().release( ps ); @@ -106,15 +112,28 @@ public abstract class AbstractScrollableResults implements ScrollableResults { LOG.tracev( "Exception trying to cleanup load context : {0}", ignore.getMessage() ); } } + + this.closed = true; + } + + @Override + public boolean isClosed() { + return this.closed; } @Override public final Object[] get() throws HibernateException { + if ( closed ) { + throw new IllegalStateException( "ScrollableResults is closed" ); + } return getCurrentRow(); } @Override public final Object get(int col) throws HibernateException { + if ( closed ) { + throw new IllegalStateException( "ScrollableResults is closed" ); + } return getCurrentRow()[col]; } @@ -127,6 +146,10 @@ public abstract class AbstractScrollableResults implements ScrollableResults { * @param returnType a "final" type */ protected final Object getFinal(int col, Type returnType) throws HibernateException { + if ( closed ) { + throw new IllegalStateException( "ScrollableResults is closed" ); + } + if ( holderInstantiator != null ) { throw new HibernateException( "query specifies a holder class" ); } @@ -148,6 +171,10 @@ public abstract class AbstractScrollableResults implements ScrollableResults { * @param returnType any type */ protected final Object getNonFinal(int col, Type returnType) throws HibernateException { + if ( closed ) { + throw new IllegalStateException( "ScrollableResults is closed" ); + } + if ( holderInstantiator != null ) { throw new HibernateException( "query specifies a holder class" ); } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/AbstractSessionImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/AbstractSessionImpl.java index eeb8fdad4a..eec853c469 100755 --- a/hibernate-core/src/main/java/org/hibernate/internal/AbstractSessionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/AbstractSessionImpl.java @@ -25,8 +25,6 @@ public abstract class AbstractSessionImpl implements Serializable, SharedSessionContractImplementor, JdbcSessionOwner, SessionImplementor, EventSource, Options, WrapperOptions { - private static final CoreMessageLogger log = CoreLogging.messageLogger( AbstractSessionImpl.class ); - protected AbstractSessionImpl(SessionFactoryImpl factory, SessionCreationOptions options) { super( factory, options ); } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java b/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java index 0f9003ceb6..b301e580fa 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java @@ -72,6 +72,7 @@ import org.hibernate.query.internal.NativeQueryImpl; import org.hibernate.query.internal.QueryImpl; import org.hibernate.query.spi.NativeQueryImplementor; import org.hibernate.query.spi.QueryImplementor; +import org.hibernate.query.spi.ScrollableResultsImplementor; import org.hibernate.resource.jdbc.spi.JdbcSessionContext; import org.hibernate.resource.jdbc.spi.StatementInspector; import org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoordinatorImpl; @@ -948,7 +949,7 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont } @Override - public ScrollableResults scroll(NativeSQLQuerySpecification spec, QueryParameters queryParameters) { + public ScrollableResultsImplementor scroll(NativeSQLQuerySpecification spec, QueryParameters queryParameters) { return scrollCustomQuery( getNativeQueryPlan( spec ).getCustomQuery(), queryParameters ); } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java index 4994383a1a..70c68b7080 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java @@ -169,6 +169,7 @@ import org.hibernate.query.criteria.internal.compile.CriteriaCompiler; import org.hibernate.query.criteria.internal.expression.CompoundSelectionImpl; import org.hibernate.query.internal.CollectionFilterImpl; import org.hibernate.query.spi.QueryImplementor; +import org.hibernate.query.spi.ScrollableResultsImplementor; import org.hibernate.resource.transaction.TransactionRequiredForJoinException; import org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoordinatorImpl; import org.hibernate.resource.transaction.backend.jta.internal.synchronization.AfterCompletionAction; @@ -1525,7 +1526,7 @@ public final class SessionImpl } @Override - public ScrollableResults scroll(String query, QueryParameters queryParameters) throws HibernateException { + public ScrollableResultsImplementor scroll(String query, QueryParameters queryParameters) throws HibernateException { checkOpen(); checkTransactionSynchStatus(); @@ -1782,7 +1783,7 @@ public final class SessionImpl } @Override - public ScrollableResults scroll(Criteria criteria, ScrollMode scrollMode) { + public ScrollableResultsImplementor scroll(Criteria criteria, ScrollMode scrollMode) { // TODO: Is this guaranteed to always be CriteriaImpl? CriteriaImpl criteriaImpl = (CriteriaImpl) criteria; @@ -2074,7 +2075,7 @@ public final class SessionImpl } @Override - public ScrollableResults scrollCustomQuery(CustomQuery customQuery, QueryParameters queryParameters) { + public ScrollableResultsImplementor scrollCustomQuery(CustomQuery customQuery, QueryParameters queryParameters) { checkOpen(); // checkTransactionSynchStatus(); diff --git a/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java index 02a2ad8b7a..f109b9236c 100755 --- a/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java @@ -46,6 +46,7 @@ import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.OuterJoinLoadable; import org.hibernate.pretty.MessageHelper; import org.hibernate.proxy.HibernateProxy; +import org.hibernate.query.spi.ScrollableResultsImplementor; /** * @author Gavin King @@ -498,7 +499,7 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen } @Override - public ScrollableResults scroll(Criteria criteria, ScrollMode scrollMode) { + public ScrollableResultsImplementor scroll(Criteria criteria, ScrollMode scrollMode) { // TODO: Is this guaranteed to always be CriteriaImpl? CriteriaImpl criteriaImpl = (CriteriaImpl) criteria; @@ -581,7 +582,7 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen } @Override - public ScrollableResults scrollCustomQuery(CustomQuery customQuery, QueryParameters queryParameters) + public ScrollableResultsImplementor scrollCustomQuery(CustomQuery customQuery, QueryParameters queryParameters) throws HibernateException { checkOpen(); CustomLoader loader = new CustomLoader( customQuery, getFactory() ); @@ -589,7 +590,7 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen } @Override - public ScrollableResults scroll(String query, QueryParameters queryParameters) throws HibernateException { + public ScrollableResultsImplementor scroll(String query, QueryParameters queryParameters) throws HibernateException { checkOpen(); HQLQueryPlan plan = getQueryPlan( query, false ); return plan.performScroll( queryParameters, this ); diff --git a/hibernate-core/src/main/java/org/hibernate/loader/Loader.java b/hibernate-core/src/main/java/org/hibernate/loader/Loader.java index 3c47df3a98..e65a135ef8 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/Loader.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/Loader.java @@ -74,6 +74,7 @@ import org.hibernate.persister.entity.Loadable; import org.hibernate.persister.entity.UniqueKeyLoadable; import org.hibernate.pretty.MessageHelper; import org.hibernate.proxy.HibernateProxy; +import org.hibernate.query.spi.ScrollableResultsImplementor; import org.hibernate.transform.CacheableResultTransformer; import org.hibernate.transform.ResultTransformer; import org.hibernate.type.AssociationType; @@ -2668,7 +2669,7 @@ public abstract class Loader { * @throws HibernateException Indicates an error executing the query, or constructing * the ScrollableResults. */ - protected ScrollableResults scroll( + protected ScrollableResultsImplementor scroll( final QueryParameters queryParameters, final Type[] returnTypes, final HolderInstantiator holderInstantiator, diff --git a/hibernate-core/src/main/java/org/hibernate/loader/criteria/CriteriaLoader.java b/hibernate-core/src/main/java/org/hibernate/loader/criteria/CriteriaLoader.java index 3a31278638..c984248b02 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/criteria/CriteriaLoader.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/criteria/CriteriaLoader.java @@ -33,6 +33,7 @@ import org.hibernate.loader.spi.AfterLoadAction; import org.hibernate.persister.entity.Loadable; import org.hibernate.persister.entity.Lockable; import org.hibernate.persister.entity.OuterJoinLoadable; +import org.hibernate.query.spi.ScrollableResultsImplementor; import org.hibernate.transform.ResultTransformer; import org.hibernate.type.Type; @@ -97,7 +98,7 @@ public class CriteriaLoader extends OuterJoinLoader { } - public ScrollableResults scroll(SharedSessionContractImplementor session, ScrollMode scrollMode) + public ScrollableResultsImplementor scroll(SharedSessionContractImplementor session, ScrollMode scrollMode) throws HibernateException { QueryParameters qp = translator.getQueryParameters(); qp.setScrollMode( scrollMode ); diff --git a/hibernate-core/src/main/java/org/hibernate/loader/custom/CustomLoader.java b/hibernate-core/src/main/java/org/hibernate/loader/custom/CustomLoader.java index 4df3fd732b..026174719a 100755 --- a/hibernate-core/src/main/java/org/hibernate/loader/custom/CustomLoader.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/custom/CustomLoader.java @@ -38,6 +38,7 @@ import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.collection.QueryableCollection; import org.hibernate.persister.entity.Loadable; import org.hibernate.persister.entity.Queryable; +import org.hibernate.query.spi.ScrollableResultsImplementor; import org.hibernate.transform.ResultTransformer; import org.hibernate.type.CollectionType; import org.hibernate.type.EntityType; @@ -369,7 +370,7 @@ public class CustomLoader extends Loader { return sql; } - public ScrollableResults scroll(final QueryParameters queryParameters, final SharedSessionContractImplementor session) + public ScrollableResultsImplementor scroll(final QueryParameters queryParameters, final SharedSessionContractImplementor session) throws HibernateException { return scroll( queryParameters, diff --git a/hibernate-core/src/main/java/org/hibernate/loader/hql/QueryLoader.java b/hibernate-core/src/main/java/org/hibernate/loader/hql/QueryLoader.java index 884589b83c..e83adbace0 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/hql/QueryLoader.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/hql/QueryLoader.java @@ -43,6 +43,7 @@ import org.hibernate.persister.collection.QueryableCollection; import org.hibernate.persister.entity.Loadable; import org.hibernate.persister.entity.Lockable; import org.hibernate.persister.entity.Queryable; +import org.hibernate.query.spi.ScrollableResultsImplementor; import org.hibernate.transform.ResultTransformer; import org.hibernate.type.EntityType; import org.hibernate.type.Type; @@ -563,7 +564,7 @@ public class QueryLoader extends BasicLoader { } - public ScrollableResults scroll( + public ScrollableResultsImplementor scroll( final QueryParameters queryParameters, final SharedSessionContractImplementor session) throws HibernateException { checkQuery( queryParameters ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/Query.java b/hibernate-core/src/main/java/org/hibernate/query/Query.java index aa419060d8..b32903370a 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/Query.java +++ b/hibernate-core/src/main/java/org/hibernate/query/Query.java @@ -12,6 +12,8 @@ import java.time.OffsetDateTime; import java.time.ZonedDateTime; import java.util.Calendar; import java.util.Date; +import java.util.Spliterator; +import java.util.stream.Stream; import javax.persistence.FlushModeType; import javax.persistence.LockModeType; import javax.persistence.Parameter; @@ -48,12 +50,26 @@ public interface Query extends TypedQuery, org.hibernate.Query, BasicQu /** * "QueryOptions" is a better name, I think, than "RowSelection" -> 6.0 * + * @todo 6.0 rename RowSelection to QueryOptions + * * @return Return the encapsulation of this query's options, which includes access to * firstRow, maxRows, timeout and fetchSize. Important because this gives access to * those values in their Integer form rather than the primitive form (int) required by JPA. */ RowSelection getQueryOptions(); + /** + * Retrieve a Stream over the query results. + *

+ * In the initial implementation (5.2) this returns a simple sequential Stream. The plan + * is to return a a smarter stream in 6.0 leveraging the SQM model. + * + * @return The results Stream + * + * @since 5.2 + */ + Stream stream(); + Query setParameter(Parameter param, Instant value, TemporalType temporalType); Query setParameter(Parameter param, LocalDateTime value, TemporalType temporalType); diff --git a/hibernate-core/src/main/java/org/hibernate/query/internal/AbstractProducedQuery.java b/hibernate-core/src/main/java/org/hibernate/query/internal/AbstractProducedQuery.java index 4cce49fbf3..fe842f6044 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/internal/AbstractProducedQuery.java +++ b/hibernate-core/src/main/java/org/hibernate/query/internal/AbstractProducedQuery.java @@ -22,6 +22,10 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.Spliterator; +import java.util.Spliterators; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; import javax.persistence.CacheRetrieveMode; import javax.persistence.CacheStoreMode; import javax.persistence.FlushModeType; @@ -39,7 +43,6 @@ import org.hibernate.LockOptions; import org.hibernate.NonUniqueResultException; import org.hibernate.PropertyNotFoundException; import org.hibernate.ScrollMode; -import org.hibernate.ScrollableResults; import org.hibernate.TypeMismatchException; import org.hibernate.engine.query.spi.EntityGraphQueryHint; import org.hibernate.engine.query.spi.HQLQueryPlan; @@ -67,6 +70,7 @@ import org.hibernate.query.QueryParameter; import org.hibernate.query.spi.QueryImplementor; import org.hibernate.query.spi.QueryParameterBinding; import org.hibernate.query.spi.QueryParameterListBinding; +import org.hibernate.query.spi.ScrollableResultsImplementor; import org.hibernate.transform.ResultTransformer; import org.hibernate.type.Type; @@ -1284,12 +1288,12 @@ public abstract class AbstractProducedQuery implements QueryImplementor { } @Override - public ScrollableResults scroll() { + public ScrollableResultsImplementor scroll() { return scroll( getProducer().getJdbcServices().getJdbcEnvironment().getDialect().defaultScrollMode() ); } @Override - public ScrollableResults scroll(ScrollMode scrollMode) { + public ScrollableResultsImplementor scroll(ScrollMode scrollMode) { beforeQuery(); try { return doScroll( scrollMode ); @@ -1299,7 +1303,7 @@ public abstract class AbstractProducedQuery implements QueryImplementor { } } - protected ScrollableResults doScroll(ScrollMode scrollMode) { + protected ScrollableResultsImplementor doScroll(ScrollMode scrollMode) { QueryParameters queryParameters = getQueryParameters(); queryParameters.setScrollMode( scrollMode ); return getProducer().scroll( @@ -1308,6 +1312,19 @@ public abstract class AbstractProducedQuery implements QueryImplementor { ); } + @Override + @SuppressWarnings("unchecked") + public Stream stream() { + final ScrollableResultsImplementor scrollableResults = scroll( ScrollMode.FORWARD_ONLY ); + final ScrollableResultsIterator iterator = new ScrollableResultsIterator<>( scrollableResults ); + final Spliterator spliterator = Spliterators.spliteratorUnknownSize( iterator, Spliterator.NONNULL ); + + final Stream stream = StreamSupport.stream( spliterator, false ); + stream.onClose( scrollableResults::close ); + + return stream; + } + @Override public List list() { beforeQuery(); diff --git a/hibernate-core/src/main/java/org/hibernate/query/internal/CollectionFilterImpl.java b/hibernate-core/src/main/java/org/hibernate/query/internal/CollectionFilterImpl.java index 8bc5086df2..ee6120a308 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/internal/CollectionFilterImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/internal/CollectionFilterImpl.java @@ -14,6 +14,7 @@ import org.hibernate.ScrollMode; import org.hibernate.ScrollableResults; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.query.Query; +import org.hibernate.query.spi.ScrollableResultsImplementor; import org.hibernate.type.Type; /** @@ -66,12 +67,12 @@ public class CollectionFilterImpl extends org.hibernate.query.internal.AbstractP } @Override - public ScrollableResults scroll() throws HibernateException { + public ScrollableResultsImplementor scroll() throws HibernateException { throw new UnsupportedOperationException( "Can't scroll filters" ); } @Override - public ScrollableResults scroll(ScrollMode scrollMode) { + public ScrollableResultsImplementor scroll(ScrollMode scrollMode) { throw new UnsupportedOperationException( "Can't scroll filters" ); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/internal/NativeQueryImpl.java b/hibernate-core/src/main/java/org/hibernate/query/internal/NativeQueryImpl.java index fac13d4b46..3c22019de7 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/internal/NativeQueryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/internal/NativeQueryImpl.java @@ -40,6 +40,7 @@ import org.hibernate.query.NativeQuery; import org.hibernate.query.ParameterMetadata; import org.hibernate.query.QueryParameter; import org.hibernate.query.spi.NativeQueryImplementor; +import org.hibernate.query.spi.ScrollableResultsImplementor; import org.hibernate.transform.ResultTransformer; import org.hibernate.type.Type; @@ -183,7 +184,7 @@ public class NativeQueryImpl extends AbstractProducedQuery implements Nati } @Override - protected ScrollableResults doScroll(ScrollMode scrollMode) { + protected ScrollableResultsImplementor doScroll(ScrollMode scrollMode) { return getProducer().scroll( generateQuerySpecification(), getQueryParameters() diff --git a/hibernate-core/src/main/java/org/hibernate/query/internal/ScrollableResultsIterator.java b/hibernate-core/src/main/java/org/hibernate/query/internal/ScrollableResultsIterator.java new file mode 100644 index 0000000000..444d78961d --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/query/internal/ScrollableResultsIterator.java @@ -0,0 +1,41 @@ +/* + * 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.query.internal; + +import org.hibernate.Incubating; +import org.hibernate.query.spi.CloseableIterator; +import org.hibernate.query.spi.ScrollableResultsImplementor; + +/** + * @author Steve Ebersole + * + * @since 5.2 + */ +@Incubating +public class ScrollableResultsIterator implements CloseableIterator { + private final ScrollableResultsImplementor scrollableResults; + + public ScrollableResultsIterator(ScrollableResultsImplementor scrollableResults) { + this.scrollableResults = scrollableResults; + } + + @Override + public void close() { + scrollableResults.close(); + } + + @Override + public boolean hasNext() { + return !scrollableResults.isClosed() && scrollableResults.next(); + } + + @Override + @SuppressWarnings("unchecked") + public T next() { + return (T) scrollableResults.get(); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/query/spi/CloseableIterator.java b/hibernate-core/src/main/java/org/hibernate/query/spi/CloseableIterator.java new file mode 100644 index 0000000000..946cae174c --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/query/spi/CloseableIterator.java @@ -0,0 +1,24 @@ +/* + * 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.query.spi; + +import java.util.Iterator; + +import org.hibernate.Incubating; + +/** + * Unification of Iterator and AutoCloseable + * + * @author Steve Ebersole + * + * @since 5.2 + */ +@Incubating +public interface CloseableIterator extends Iterator, AutoCloseable { + @Override + void close(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/query/spi/ScrollableResultsImplementor.java b/hibernate-core/src/main/java/org/hibernate/query/spi/ScrollableResultsImplementor.java new file mode 100644 index 0000000000..c0198cbf82 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/query/spi/ScrollableResultsImplementor.java @@ -0,0 +1,20 @@ +/* + * 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.query.spi; + +import org.hibernate.Incubating; +import org.hibernate.ScrollableResults; + +/** + * @author Steve Ebersole + * + * @since 5.2 + */ +@Incubating +public interface ScrollableResultsImplementor extends ScrollableResults { + boolean isClosed(); +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/stream/basic/BasicStreamTest.java b/hibernate-core/src/test/java/org/hibernate/test/stream/basic/BasicStreamTest.java new file mode 100644 index 0000000000..9b2612911a --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/stream/basic/BasicStreamTest.java @@ -0,0 +1,61 @@ +/* + * 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.test.stream.basic; + +import java.util.stream.Stream; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; + +import org.hibernate.Session; +import org.hibernate.boot.MetadataSources; +import org.hibernate.engine.spi.SessionImplementor; + +import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; +import org.junit.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; + +/** + * @author Steve Ebersole + */ +public class BasicStreamTest extends BaseNonConfigCoreFunctionalTestCase { + + @Override + protected void applyMetadataSources(MetadataSources metadataSources) { + super.applyMetadataSources( metadataSources ); + metadataSources.addAnnotatedClass( MyEntity.class ); + } + + @Test + public void basicStreamTest() { + Session session = openSession(); + session.getTransaction().begin(); + + // mainly we want to make sure that closing the Stream releases the ScrollableResults too + assertThat( ( (SessionImplementor) session ).getJdbcCoordinator().getLogicalConnection().getResourceRegistry().hasRegisteredResources(), is( false ) ); + final Stream stream = session.createQuery( "from MyEntity", MyEntity.class ).stream(); + assertThat( ( (SessionImplementor) session ).getJdbcCoordinator().getLogicalConnection().getResourceRegistry().hasRegisteredResources(), is( true ) ); + stream.forEach( System.out::println ); + assertThat( ( (SessionImplementor) session ).getJdbcCoordinator().getLogicalConnection().getResourceRegistry().hasRegisteredResources(), is( true ) ); + stream.close(); + assertThat( ( (SessionImplementor) session ).getJdbcCoordinator().getLogicalConnection().getResourceRegistry().hasRegisteredResources(), is( false ) ); + + session.getTransaction().commit(); + session.close(); + } + + @Entity(name = "MyEntity") + @Table(name="MyEntity") + public static class MyEntity { + @Id + public Integer id; + public String name; + } + +}