parent
5359a7b5fd
commit
4dd7c280ca
|
@ -10,6 +10,8 @@ import java.io.Serializable;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Function;
|
||||||
import javax.naming.Referenceable;
|
import javax.naming.Referenceable;
|
||||||
import javax.persistence.EntityManagerFactory;
|
import javax.persistence.EntityManagerFactory;
|
||||||
|
|
||||||
|
@ -103,6 +105,108 @@ public interface SessionFactory extends EntityManagerFactory, HibernateEntityMan
|
||||||
*/
|
*/
|
||||||
StatelessSession openStatelessSession(Connection connection);
|
StatelessSession openStatelessSession(Connection connection);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open a Session and perform a action using it
|
||||||
|
*/
|
||||||
|
default void inSession(Consumer<Session> action) {
|
||||||
|
try (Session session = openSession()) {
|
||||||
|
action.accept( session );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open a Session and perform a action using it within the bounds of a transaction
|
||||||
|
*/
|
||||||
|
default void inTransaction(Consumer<Session> action) {
|
||||||
|
inSession(
|
||||||
|
session -> {
|
||||||
|
final Transaction txn = session.beginTransaction();
|
||||||
|
|
||||||
|
try {
|
||||||
|
action.accept( session );
|
||||||
|
|
||||||
|
if ( !txn.isActive() ) {
|
||||||
|
throw new TransactionManagementException( "Execution of action caused managed transaction to be completed" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (RuntimeException e) {
|
||||||
|
// an error happened in the action
|
||||||
|
if ( txn.isActive() ) {
|
||||||
|
try {
|
||||||
|
txn.rollback();
|
||||||
|
}
|
||||||
|
catch (Exception ignore) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
// action completed with no errors - attempt to commit the transaction allowing
|
||||||
|
// any RollbackException to propagate. Note that when we get here we know the
|
||||||
|
// txn is active
|
||||||
|
|
||||||
|
txn.commit();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class TransactionManagementException extends RuntimeException {
|
||||||
|
TransactionManagementException(String message) {
|
||||||
|
super( message );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open a Session and perform a action using it
|
||||||
|
*/
|
||||||
|
default <R> R fromSession(Function<Session,R> action) {
|
||||||
|
try (Session session = openSession()) {
|
||||||
|
return action.apply( session );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open a Session and perform a action using it within the bounds of a transaction
|
||||||
|
*/
|
||||||
|
default <R> R fromTransaction(Function<Session,R> action) {
|
||||||
|
return fromSession(
|
||||||
|
session -> {
|
||||||
|
R result = null;
|
||||||
|
|
||||||
|
final Transaction txn = session.beginTransaction();
|
||||||
|
|
||||||
|
try {
|
||||||
|
result = action.apply( session );
|
||||||
|
|
||||||
|
if ( !txn.isActive() ) {
|
||||||
|
throw new TransactionManagementException( "Execution of action caused managed transaction to be completed" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (RuntimeException e) {
|
||||||
|
// an error happened in the action
|
||||||
|
if ( txn.isActive() ) {
|
||||||
|
try {
|
||||||
|
txn.rollback();
|
||||||
|
}
|
||||||
|
catch (Exception ignore) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
// action completed with no errors - attempt to commit the transaction allowing
|
||||||
|
// any RollbackException to propagate. Note that when we get here we know the
|
||||||
|
// txn is active
|
||||||
|
|
||||||
|
txn.commit();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the statistics fopr this factory.
|
* Retrieve the statistics fopr this factory.
|
||||||
*
|
*
|
||||||
|
|
|
@ -7,24 +7,19 @@
|
||||||
package org.hibernate.metamodel.model.domain;
|
package org.hibernate.metamodel.model.domain;
|
||||||
|
|
||||||
import org.hibernate.Incubating;
|
import org.hibernate.Incubating;
|
||||||
import org.hibernate.metamodel.model.mapping.spi.Writeable;
|
import org.hibernate.metamodel.model.mapping.spi.ModelPart;
|
||||||
|
import org.hibernate.metamodel.model.mapping.spi.ValueMapping;
|
||||||
import org.hibernate.query.Query;
|
import org.hibernate.query.Query;
|
||||||
import org.hibernate.query.sqm.SqmExpressable;
|
|
||||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specialization of DomainType for types that can be used as {@link Query} parameter bind values
|
* Specialization of DomainType for types that can be used as {@link Query} parameter bind values.
|
||||||
*
|
*
|
||||||
* todo (6.0) : extend Writeable? or expose Writeable as "component"?
|
* todo (6.0) : Need a resolution between AllowableParameterType and {@link ValueMapping} / {@link ModelPart}
|
||||||
* i.e.
|
|
||||||
* ````
|
|
||||||
* Writeable getWriteable();
|
|
||||||
* ````
|
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
@Incubating
|
@Incubating
|
||||||
public interface AllowableParameterType<J> extends Writeable, SqmExpressable<J> {
|
public interface AllowableParameterType<J> extends SimpleDomainType<J> {
|
||||||
|
|
||||||
JavaTypeDescriptor<J> getExpressableJavaTypeDescriptor();
|
JavaTypeDescriptor<J> getExpressableJavaTypeDescriptor();
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,17 +6,17 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.metamodel.model.domain.internal;
|
package org.hibernate.metamodel.model.domain.internal;
|
||||||
|
|
||||||
|
import org.hibernate.metamodel.model.domain.AllowableParameterType;
|
||||||
import org.hibernate.metamodel.model.domain.EmbeddableDomainType;
|
import org.hibernate.metamodel.model.domain.EmbeddableDomainType;
|
||||||
import org.hibernate.query.sqm.SqmPathSource;
|
import org.hibernate.query.sqm.SqmPathSource;
|
||||||
import org.hibernate.query.sqm.produce.spi.SqmCreationState;
|
import org.hibernate.query.sqm.produce.spi.SqmCreationState;
|
||||||
import org.hibernate.query.sqm.tree.domain.SqmAnyValuedSimplePath;
|
|
||||||
import org.hibernate.query.sqm.tree.domain.SqmEmbeddedValuedSimplePath;
|
import org.hibernate.query.sqm.tree.domain.SqmEmbeddedValuedSimplePath;
|
||||||
import org.hibernate.query.sqm.tree.domain.SqmPath;
|
import org.hibernate.query.sqm.tree.domain.SqmPath;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class EmbeddedSqmPathSource<J> extends AbstractSqmPathSource<J> {
|
public class EmbeddedSqmPathSource<J> extends AbstractSqmPathSource<J> implements AllowableParameterType<J> {
|
||||||
public EmbeddedSqmPathSource(
|
public EmbeddedSqmPathSource(
|
||||||
String localPathName,
|
String localPathName,
|
||||||
EmbeddableDomainType<J> domainType,
|
EmbeddableDomainType<J> domainType,
|
||||||
|
@ -30,6 +30,16 @@ public class EmbeddedSqmPathSource<J> extends AbstractSqmPathSource<J> {
|
||||||
return (EmbeddableDomainType<J>) super.getSqmPathType();
|
return (EmbeddableDomainType<J>) super.getSqmPathType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PersistenceType getPersistenceType() {
|
||||||
|
return PersistenceType.EMBEDDABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<J> getJavaType() {
|
||||||
|
return getBindableJavaType();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SqmPathSource<?> findSubPathSource(String name) {
|
public SqmPathSource<?> findSubPathSource(String name) {
|
||||||
return (SqmPathSource<?>) getSqmPathType().findAttribute( name );
|
return (SqmPathSource<?>) getSqmPathType().findAttribute( name );
|
||||||
|
|
|
@ -73,14 +73,15 @@ public class StandardCallableStatementSupport implements CallableStatementSuppor
|
||||||
sep = ",";
|
sep = ",";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
parameter.getHibernateType().visitJdbcTypes(
|
throw new NotYetImplementedFor6Exception( getClass() );
|
||||||
sqlExpressableType -> {
|
// parameter.getHibernateType().visitJdbcTypes(
|
||||||
buffer.append( sep ).append( "?" );
|
// sqlExpressableType -> {
|
||||||
sep = ",";
|
// buffer.append( sep ).append( "?" );
|
||||||
},
|
// sep = ",";
|
||||||
Clause.IRRELEVANT,
|
// },
|
||||||
session.getFactory().getTypeConfiguration()
|
// Clause.IRRELEVANT,
|
||||||
);
|
// session.getFactory().getTypeConfiguration()
|
||||||
|
// );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,6 +104,7 @@ import org.hibernate.query.sqm.tree.from.SqmQualifiedJoin;
|
||||||
import org.hibernate.query.sqm.tree.from.SqmRoot;
|
import org.hibernate.query.sqm.tree.from.SqmRoot;
|
||||||
import org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement;
|
import org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement;
|
||||||
import org.hibernate.query.sqm.tree.predicate.SqmAndPredicate;
|
import org.hibernate.query.sqm.tree.predicate.SqmAndPredicate;
|
||||||
|
import org.hibernate.query.sqm.tree.predicate.SqmBetweenPredicate;
|
||||||
import org.hibernate.query.sqm.tree.predicate.SqmComparisonPredicate;
|
import org.hibernate.query.sqm.tree.predicate.SqmComparisonPredicate;
|
||||||
import org.hibernate.query.sqm.tree.predicate.SqmEmptinessPredicate;
|
import org.hibernate.query.sqm.tree.predicate.SqmEmptinessPredicate;
|
||||||
import org.hibernate.query.sqm.tree.predicate.SqmGroupedPredicate;
|
import org.hibernate.query.sqm.tree.predicate.SqmGroupedPredicate;
|
||||||
|
@ -165,9 +166,6 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
|
||||||
private final SqmCreationOptions creationOptions;
|
private final SqmCreationOptions creationOptions;
|
||||||
private final SqmCreationContext creationContext;
|
private final SqmCreationContext creationContext;
|
||||||
|
|
||||||
private final ImplicitAliasGenerator implicitAliasGenerator;
|
|
||||||
private final UniqueIdGenerator uidGenerator;
|
|
||||||
|
|
||||||
private final Stack<DotIdentifierConsumer> dotIdentifierConsumerStack;
|
private final Stack<DotIdentifierConsumer> dotIdentifierConsumerStack;
|
||||||
|
|
||||||
private final Stack<TreatHandler> treatHandlerStack = new StandardStack<>( new TreatHandlerNormal() );
|
private final Stack<TreatHandler> treatHandlerStack = new StandardStack<>( new TreatHandlerNormal() );
|
||||||
|
@ -186,11 +184,7 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
|
||||||
this.creationOptions = creationOptions;
|
this.creationOptions = creationOptions;
|
||||||
this.creationContext = creationContext;
|
this.creationContext = creationContext;
|
||||||
|
|
||||||
this.implicitAliasGenerator = new ImplicitAliasGenerator();
|
|
||||||
this.uidGenerator = new UniqueIdGenerator();
|
|
||||||
|
|
||||||
this.dotIdentifierConsumerStack = new StandardStack<>( new BasicDotIdentifierConsumer( this ) );
|
this.dotIdentifierConsumerStack = new StandardStack<>( new BasicDotIdentifierConsumer( this ) );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1092,6 +1086,18 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SqmBetweenPredicate visitBetweenPredicate(HqlParser.BetweenPredicateContext ctx) {
|
||||||
|
return new SqmBetweenPredicate(
|
||||||
|
(SqmExpression) ctx.expression( 0 ).accept( this ),
|
||||||
|
(SqmExpression) ctx.expression( 1 ).accept( this ),
|
||||||
|
(SqmExpression) ctx.expression( 2 ).accept( this ),
|
||||||
|
ctx.NOT() != null,
|
||||||
|
creationContext.getNodeBuilder()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SqmNullnessPredicate visitIsNullPredicate(HqlParser.IsNullPredicateContext ctx) {
|
public SqmNullnessPredicate visitIsNullPredicate(HqlParser.IsNullPredicateContext ctx) {
|
||||||
return new SqmNullnessPredicate(
|
return new SqmNullnessPredicate(
|
||||||
|
@ -1187,7 +1193,6 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
|
||||||
else {
|
else {
|
||||||
throw new SemanticException( "Path argument to MEMBER OF must be a plural attribute" );
|
throw new SemanticException( "Path argument to MEMBER OF must be a plural attribute" );
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -861,4 +861,14 @@ public class ComponentType extends AbstractType implements CompositeType, Proced
|
||||||
public JavaTypeDescriptor getExpressableJavaTypeDescriptor() {
|
public JavaTypeDescriptor getExpressableJavaTypeDescriptor() {
|
||||||
throw new NotYetImplementedFor6Exception( getClass() );
|
throw new NotYetImplementedFor6Exception( getClass() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PersistenceType getPersistenceType() {
|
||||||
|
return PersistenceType.EMBEDDABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class getJavaType() {
|
||||||
|
return getReturnedClass();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ public class JdbcDateTypeDescriptor extends AbstractTypeDescriptor<Date> {
|
||||||
* @see #DATE_FORMAT
|
* @see #DATE_FORMAT
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static final DateTimeFormatter LITERAL_FORMATTER = DateTimeFormatter.ofPattern( DATE_FORMAT );
|
public static final DateTimeFormatter LITERAL_FORMATTER = DateTimeFormatter.ISO_LOCAL_DATE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Alias for {@link java.time.format.DateTimeFormatter#ISO_LOCAL_DATE}.
|
* Alias for {@link java.time.format.DateTimeFormatter#ISO_LOCAL_DATE}.
|
||||||
|
|
|
@ -28,7 +28,7 @@ public class JdbcTimeTypeDescriptor extends AbstractTypeDescriptor<Date> {
|
||||||
@SuppressWarnings("WeakerAccess")
|
@SuppressWarnings("WeakerAccess")
|
||||||
public static final String TIME_FORMAT = "HH:mm:ss.SSS";
|
public static final String TIME_FORMAT = "HH:mm:ss.SSS";
|
||||||
|
|
||||||
public static final DateTimeFormatter LITERAL_FORMATTER = DateTimeFormatter.ofPattern( TIME_FORMAT );
|
public static final DateTimeFormatter LITERAL_FORMATTER = DateTimeFormatter.ISO_LOCAL_TIME;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Alias for {@link java.time.format.DateTimeFormatter#ISO_LOCAL_TIME}.
|
* Alias for {@link java.time.format.DateTimeFormatter#ISO_LOCAL_TIME}.
|
||||||
|
|
|
@ -34,7 +34,7 @@ public class JdbcTimestampTypeDescriptor extends AbstractTypeDescriptor<Date> {
|
||||||
* @see #TIMESTAMP_FORMAT
|
* @see #TIMESTAMP_FORMAT
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static final DateTimeFormatter LITERAL_FORMATTER = DateTimeFormatter.ofPattern( TIMESTAMP_FORMAT );
|
public static final DateTimeFormatter LITERAL_FORMATTER = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Alias for {@link java.time.format.DateTimeFormatter#ISO_LOCAL_DATE_TIME}.
|
* Alias for {@link java.time.format.DateTimeFormatter#ISO_LOCAL_DATE_TIME}.
|
||||||
|
|
|
@ -17,6 +17,7 @@ import org.hibernate.query.sqm.tree.predicate.SqmComparisonPredicate;
|
||||||
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
|
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
|
||||||
import org.hibernate.query.sqm.tree.select.SqmSelectableNode;
|
import org.hibernate.query.sqm.tree.select.SqmSelectableNode;
|
||||||
|
|
||||||
|
import org.hibernate.testing.orm.junit.FailureExpected;
|
||||||
import org.hibernate.testing.orm.junit.TestingUtil;
|
import org.hibernate.testing.orm.junit.TestingUtil;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
@ -86,6 +87,7 @@ public class CaseExpressionsTest extends BaseSqmUnitTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@FailureExpected( "Support for functions not yet defined" )
|
||||||
public void testBasicCoalesceExpression() {
|
public void testBasicCoalesceExpression() {
|
||||||
SqmSelectStatement select = interpretSelect(
|
SqmSelectStatement select = interpretSelect(
|
||||||
"select coalesce(p.nickName, p.mate.nickName) from Person p"
|
"select coalesce(p.nickName, p.mate.nickName) from Person p"
|
||||||
|
@ -103,6 +105,7 @@ public class CaseExpressionsTest extends BaseSqmUnitTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@FailureExpected( "Support for functions not yet defined" )
|
||||||
public void testBasicNullifExpression() {
|
public void testBasicNullifExpression() {
|
||||||
SqmSelectStatement select = interpretSelect(
|
SqmSelectStatement select = interpretSelect(
|
||||||
"select nullif(p.nickName, p.mate.nickName) from Person p"
|
"select nullif(p.nickName, p.mate.nickName) from Person p"
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* 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.orm.test.query.hql;
|
||||||
|
|
||||||
|
import org.hibernate.boot.MetadataSources;
|
||||||
|
import org.hibernate.orm.test.query.sqm.BaseSqmUnitTest;
|
||||||
|
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
|
||||||
|
|
||||||
|
import org.hibernate.testing.orm.domain.StandardDomainModel;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class LiteralTests extends BaseSqmUnitTest {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void applyMetadataSources(MetadataSources metadataSources) {
|
||||||
|
StandardDomainModel.GAMBIT.getDescriptor().applyDomainModel( metadataSources );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTimestampLiteral() {
|
||||||
|
final SqmSelectStatement sqm = interpretSelect( "from EntityOfBasics e1 where e1.theTimestamp = {ts '2018-01-01T12:30:00'}" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDateLiteral() {
|
||||||
|
final SqmSelectStatement sqm = interpretSelect( "from EntityOfBasics e1 where e1.theDate = {d '2018-01-01'}" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTimeLiteral() {
|
||||||
|
final SqmSelectStatement sqm = interpretSelect( "from EntityOfBasics e1 where e1.theTime = {t '12:30:00'}" );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* 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.orm.test.query.hql;
|
||||||
|
|
||||||
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
|
|
||||||
|
import org.hibernate.testing.orm.domain.StandardDomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.hibernate.orm.test.query.sqm.BaseSqmUnitTest.interpretSelect;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("WeakerAccess")
|
||||||
|
@DomainModel(
|
||||||
|
standardModels = StandardDomainModel.GAMBIT
|
||||||
|
)
|
||||||
|
@ServiceRegistry(
|
||||||
|
settings = @ServiceRegistry.Setting(
|
||||||
|
name = AvailableSettings.HBM2DDL_AUTO,
|
||||||
|
value = "create-drop"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
@SessionFactory
|
||||||
|
public class PagingTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPagingByParameter(SessionFactoryScope scope) {
|
||||||
|
interpretSelect( "select o from SimpleEntity o offset :param", scope.getSessionFactory() );
|
||||||
|
interpretSelect( "select o from SimpleEntity o limit :param", scope.getSessionFactory() );
|
||||||
|
interpretSelect( "select o from SimpleEntity o limit :param offset :param", scope.getSessionFactory() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPagingByConstant(SessionFactoryScope scope) {
|
||||||
|
interpretSelect( "select o from SimpleEntity o offset 1", scope.getSessionFactory() );
|
||||||
|
interpretSelect( "select o from SimpleEntity o limit 1", scope.getSessionFactory() );
|
||||||
|
interpretSelect( "select o from SimpleEntity o limit 1 offset 1", scope.getSessionFactory() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPagingOnSubQuery(SessionFactoryScope scope) {
|
||||||
|
interpretSelect( "select o from SimpleEntity o where o.someString = ( select oSub.someString from SimpleEntity oSub order by oSub.someString limit 1 )", scope.getSessionFactory() );
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,6 +7,8 @@
|
||||||
package org.hibernate.orm.test.query.hql;
|
package org.hibernate.orm.test.query.hql;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
|
import java.util.Date;
|
||||||
import javax.persistence.Embeddable;
|
import javax.persistence.Embeddable;
|
||||||
import javax.persistence.Embedded;
|
import javax.persistence.Embedded;
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
|
@ -15,19 +17,24 @@ import javax.persistence.ManyToOne;
|
||||||
import javax.persistence.Temporal;
|
import javax.persistence.Temporal;
|
||||||
import javax.persistence.TemporalType;
|
import javax.persistence.TemporalType;
|
||||||
|
|
||||||
import org.hibernate.metamodel.model.domain.BasicDomainType;
|
import org.hibernate.Session;
|
||||||
import org.hibernate.metamodel.model.domain.SingularPersistentAttribute;
|
|
||||||
import org.hibernate.metamodel.model.domain.internal.BasicSqmPathSource;
|
import org.hibernate.metamodel.model.domain.internal.BasicSqmPathSource;
|
||||||
|
import org.hibernate.metamodel.model.domain.internal.EmbeddedSqmPathSource;
|
||||||
import org.hibernate.orm.test.query.sqm.BaseSqmUnitTest;
|
import org.hibernate.orm.test.query.sqm.BaseSqmUnitTest;
|
||||||
|
import org.hibernate.query.Query;
|
||||||
import org.hibernate.query.SemanticException;
|
import org.hibernate.query.SemanticException;
|
||||||
|
import org.hibernate.query.spi.QueryParameterBinding;
|
||||||
|
import org.hibernate.query.spi.QueryParameterBindings;
|
||||||
import org.hibernate.query.sqm.tree.expression.SqmParameter;
|
import org.hibernate.query.sqm.tree.expression.SqmParameter;
|
||||||
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
|
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
|
||||||
|
import org.hibernate.sql.exec.spi.DomainParameterBindingContext;
|
||||||
|
|
||||||
import org.hibernate.testing.orm.junit.ExpectedException;
|
import org.hibernate.testing.orm.junit.ExpectedException;
|
||||||
import org.hibernate.testing.orm.junit.ExpectedExceptionExtension;
|
import org.hibernate.testing.orm.junit.ExpectedExceptionExtension;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.equalTo;
|
||||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||||
import static org.hamcrest.CoreMatchers.is;
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
@ -35,6 +42,8 @@ import static org.hibernate.testing.hamcrest.CollectionMatchers.hasSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
|
* @author Andrea Boriero
|
||||||
|
* @author Chris Cranford
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("WeakerAccess")
|
@SuppressWarnings("WeakerAccess")
|
||||||
@ExtendWith( ExpectedExceptionExtension.class )
|
@ExtendWith( ExpectedExceptionExtension.class )
|
||||||
|
@ -81,6 +90,60 @@ public class ParameterTests extends BaseSqmUnitTest {
|
||||||
assertThat( parameter.allowMultiValuedBinding(), is(true) );
|
assertThat( parameter.allowMultiValuedBinding(), is(true) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWideningTemporalPrecision() {
|
||||||
|
try (Session session = sessionFactory().openSession()) {
|
||||||
|
final Query query = session.createQuery( "select p.id from Person p where p.anniversary between :start and :end" );
|
||||||
|
|
||||||
|
query.setParameter( "start", Instant.now().minus( 7, ChronoUnit.DAYS ), TemporalType.TIMESTAMP );
|
||||||
|
query.setParameter( "end", Instant.now().plus( 7, ChronoUnit.DAYS ), TemporalType.TIMESTAMP );
|
||||||
|
|
||||||
|
final QueryParameterBindings bindings = ( (DomainParameterBindingContext) query ).getQueryParameterBindings();
|
||||||
|
|
||||||
|
final QueryParameterBinding<?> startBinding = bindings.getBinding( "start" );
|
||||||
|
assertThat( startBinding.getExplicitTemporalPrecision(), equalTo( TemporalType.TIMESTAMP ) );
|
||||||
|
|
||||||
|
final QueryParameterBinding<?> endBinding = bindings.getBinding( "end" );
|
||||||
|
assertThat( endBinding.getExplicitTemporalPrecision(), equalTo( TemporalType.TIMESTAMP ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNarrowingTemporalPrecision() {
|
||||||
|
try (Session session = sessionFactory().openSession()) {
|
||||||
|
final Query query = session.createQuery( "select p.id from Person p where p.dob between :start and :end" );
|
||||||
|
|
||||||
|
query.setParameter( "start", Instant.now().minus( 7, ChronoUnit.DAYS ), TemporalType.DATE );
|
||||||
|
query.setParameter( "end", Instant.now().plus( 7, ChronoUnit.DAYS ), TemporalType.DATE );
|
||||||
|
|
||||||
|
final QueryParameterBindings bindings = ( (DomainParameterBindingContext) query ).getQueryParameterBindings();
|
||||||
|
|
||||||
|
final QueryParameterBinding<?> startBinding = bindings.getBinding( "start" );
|
||||||
|
assertThat( startBinding.getExplicitTemporalPrecision(), equalTo( TemporalType.DATE ) );
|
||||||
|
|
||||||
|
final QueryParameterBinding<?> endBinding = bindings.getBinding( "end" );
|
||||||
|
assertThat( endBinding.getExplicitTemporalPrecision(), equalTo( TemporalType.DATE ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEmbeddableUseInPredicates() {
|
||||||
|
{
|
||||||
|
final SqmSelectStatement<?> sqm = interpretSelect( "select p.id from Person p where p.name.first = :fname" );
|
||||||
|
assertThat( sqm.getSqmParameters().size(), equalTo( 1 ) );
|
||||||
|
final SqmParameter<?> parameter = sqm.getSqmParameters().iterator().next();
|
||||||
|
assertThat( parameter.getAnticipatedType(), instanceOf( BasicSqmPathSource.class ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
final SqmSelectStatement<?> sqm = interpretSelect( "select p.id from Person p where p.name = :name" );
|
||||||
|
assertThat( sqm.getSqmParameters().size(), equalTo( 1 ) );
|
||||||
|
final SqmParameter<?> parameter = sqm.getSqmParameters().iterator().next();
|
||||||
|
assertThat( parameter.getAnticipatedType(), instanceOf( EmbeddedSqmPathSource.class ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Class[] getAnnotatedClasses() {
|
protected Class[] getAnnotatedClasses() {
|
||||||
return new Class[] {
|
return new Class[] {
|
||||||
|
@ -104,12 +167,15 @@ public class ParameterTests extends BaseSqmUnitTest {
|
||||||
|
|
||||||
public String nickName;
|
public String nickName;
|
||||||
|
|
||||||
@ManyToOne
|
|
||||||
Person mate;
|
|
||||||
|
|
||||||
@Temporal( TemporalType.TIMESTAMP )
|
@Temporal( TemporalType.TIMESTAMP )
|
||||||
public Instant dob;
|
public Instant dob;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
public Person mate;
|
||||||
|
|
||||||
|
@Temporal( TemporalType.DATE )
|
||||||
|
public Date anniversary;
|
||||||
|
|
||||||
public int numberOfToes;
|
public int numberOfToes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.orm.test.query.sqm;
|
||||||
|
|
||||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||||
import org.hibernate.cfg.AvailableSettings;
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.loader.spi.AfterLoadAction;
|
import org.hibernate.loader.spi.AfterLoadAction;
|
||||||
import org.hibernate.metamodel.spi.MetamodelImplementor;
|
import org.hibernate.metamodel.spi.MetamodelImplementor;
|
||||||
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
|
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
|
||||||
|
@ -51,7 +52,11 @@ public abstract class BaseSqmUnitTest
|
||||||
}
|
}
|
||||||
|
|
||||||
protected SqmSelectStatement interpretSelect(String hql) {
|
protected SqmSelectStatement interpretSelect(String hql) {
|
||||||
return (SqmSelectStatement) sessionFactory().getQueryEngine().getSemanticQueryProducer().interpret( hql );
|
return interpretSelect( hql, sessionFactory() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SqmSelectStatement interpretSelect(String hql, SessionFactoryImplementor sessionFactory) {
|
||||||
|
return (SqmSelectStatement) sessionFactory.getQueryEngine().getSemanticQueryProducer().interpret( hql );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
Loading…
Reference in New Issue