mirror of
https://github.com/hibernate/hibernate-orm
synced 2025-02-16 16:15:06 +00:00
Initial working support for building and executing JdbcSelect operation from simple HQL
This commit is contained in:
parent
5b1df3c6c9
commit
f85fe137b2
@ -9,9 +9,12 @@
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.Serializable;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.metamodel.model.convert.spi.EnumValueConverter;
|
||||
import org.hibernate.type.descriptor.ValueBinder;
|
||||
import org.hibernate.type.descriptor.ValueExtractor;
|
||||
@ -82,4 +85,14 @@ private void readObject(ObjectInputStream stream) throws ClassNotFoundException,
|
||||
this.valueExtractor = sqlTypeDescriptor.getExtractor( relationalTypeDescriptor );
|
||||
this.valueBinder = sqlTypeDescriptor.getBinder( relationalTypeDescriptor );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeValue(
|
||||
PreparedStatement statement,
|
||||
Enum value,
|
||||
int position,
|
||||
SharedSessionContractImplementor session) throws SQLException {
|
||||
final String jdbcValue = value == null ? null : value.name();
|
||||
valueBinder.bind( statement, jdbcValue, position, session );
|
||||
}
|
||||
}
|
||||
|
@ -9,8 +9,11 @@
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.Serializable;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.metamodel.model.convert.spi.EnumValueConverter;
|
||||
import org.hibernate.type.descriptor.ValueBinder;
|
||||
import org.hibernate.type.descriptor.ValueExtractor;
|
||||
@ -82,4 +85,12 @@ private void readObject(ObjectInputStream stream) throws ClassNotFoundException,
|
||||
this.valueExtractor = sqlTypeDescriptor.getExtractor( relationalJavaDescriptor );
|
||||
this.valueBinder = sqlTypeDescriptor.getBinder( relationalJavaDescriptor );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeValue(
|
||||
PreparedStatement statement, Enum value, int position, SharedSessionContractImplementor session)
|
||||
throws SQLException {
|
||||
final Integer jdbcValue = value == null ? null : value.ordinal();
|
||||
valueBinder.bind( statement, jdbcValue, position, session );
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,10 @@
|
||||
*/
|
||||
package org.hibernate.metamodel.model.convert.spi;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.type.descriptor.java.EnumJavaTypeDescriptor;
|
||||
|
||||
/**
|
||||
@ -20,4 +24,10 @@ public interface EnumValueConverter<O extends Enum, R> extends BasicValueConvert
|
||||
int getJdbcTypeCode();
|
||||
|
||||
String toSqlLiteral(Object value);
|
||||
|
||||
void writeValue(
|
||||
PreparedStatement statement,
|
||||
Enum value,
|
||||
int position,
|
||||
SharedSessionContractImplementor session) throws SQLException;
|
||||
}
|
||||
|
@ -172,6 +172,8 @@
|
||||
import org.hibernate.sql.ast.tree.predicate.ComparisonPredicate;
|
||||
import org.hibernate.sql.ast.tree.predicate.Junction;
|
||||
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
||||
import org.hibernate.sql.results.spi.DomainResult;
|
||||
import org.hibernate.sql.results.spi.DomainResultCreationState;
|
||||
import org.hibernate.stat.spi.StatisticsImplementor;
|
||||
import org.hibernate.tuple.GenerationTiming;
|
||||
import org.hibernate.tuple.InDatabaseValueGenerationStrategy;
|
||||
|
@ -12,6 +12,9 @@
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.query.sqm.sql.SqlAstCreationState;
|
||||
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
|
||||
import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.sql.ast.spi.SqlAstWalker;
|
||||
|
||||
@ -74,4 +77,10 @@ public TableReference getPrimaryTableReference() {
|
||||
public List<TableReferenceJoin> getTableReferenceJoins() {
|
||||
return tableJoins;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DomainResultProducer getDomainResultProducer(
|
||||
SqmToSqlAstConverter walker, SqlAstCreationState sqlAstCreationState) {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
|
||||
import org.hibernate.query.sqm.sql.internal.SqmSelectableInterpretation;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.sql.ast.spi.SqlAstWalker;
|
||||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||
@ -27,7 +28,8 @@
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface TableGroup extends SqlAstNode, ColumnReferenceQualifier, DomainResultProducer {
|
||||
public interface TableGroup
|
||||
extends SqlAstNode, ColumnReferenceQualifier, DomainResultProducer, SqmSelectableInterpretation {
|
||||
NavigablePath getNavigablePath();
|
||||
|
||||
ModelPart getModelPart();
|
||||
|
@ -333,9 +333,8 @@ private void verifyConfigured() {
|
||||
|
||||
@Override
|
||||
public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session) throws HibernateException, SQLException {
|
||||
throw new NotYetImplementedFor6Exception( getClass() );
|
||||
// verifyConfigured();
|
||||
// enumValueConverter.writeValue( st, (Enum) value, index, session );
|
||||
verifyConfigured();
|
||||
enumValueConverter.writeValue( st, (Enum) value, index, session );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -87,7 +87,7 @@ public void testBasicSearchedCaseExpression() {
|
||||
}
|
||||
|
||||
@Test
|
||||
@FailureExpected( "Support for functions not yet defined" )
|
||||
@FailureExpected( reason = "Support for functions not yet defined" )
|
||||
public void testBasicCoalesceExpression() {
|
||||
SqmSelectStatement select = interpretSelect(
|
||||
"select coalesce(p.nickName, p.mate.nickName) from Person p"
|
||||
@ -105,7 +105,7 @@ public void testBasicCoalesceExpression() {
|
||||
}
|
||||
|
||||
@Test
|
||||
@FailureExpected( "Support for functions not yet defined" )
|
||||
@FailureExpected( reason = "Support for functions not yet defined" )
|
||||
public void testBasicNullifExpression() {
|
||||
SqmSelectStatement select = interpretSelect(
|
||||
"select nullif(p.nickName, p.mate.nickName) from Person p"
|
||||
|
@ -8,11 +8,11 @@
|
||||
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.metamodel.mapping.MappingModelExpressable;
|
||||
import org.hibernate.metamodel.mapping.internal.BasicValuedSingularAttributeMapping;
|
||||
import org.hibernate.metamodel.model.convert.internal.OrdinalEnumValueConverter;
|
||||
import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
|
||||
import org.hibernate.metamodel.model.convert.spi.EnumValueConverter;
|
||||
import org.hibernate.orm.test.metamodel.mapping.SmokeTests.Gender;
|
||||
import org.hibernate.orm.test.metamodel.mapping.SmokeTests.SimpleEntity;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.query.hql.spi.HqlQueryImplementor;
|
||||
import org.hibernate.query.spi.QueryImplementor;
|
||||
@ -20,6 +20,7 @@
|
||||
import org.hibernate.query.sqm.sql.internal.SqmSelectInterpretation;
|
||||
import org.hibernate.query.sqm.sql.internal.SqmSelectToSqlAstConverter;
|
||||
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
|
||||
import org.hibernate.sql.ast.spi.SqlAstSelectToJdbcSelectConverter;
|
||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||
import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
@ -27,6 +28,7 @@
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.sql.ast.tree.select.SelectClause;
|
||||
import org.hibernate.sql.ast.tree.select.SelectStatement;
|
||||
import org.hibernate.sql.exec.spi.JdbcSelect;
|
||||
import org.hibernate.sql.results.internal.BasicResultAssembler;
|
||||
import org.hibernate.sql.results.internal.ScalarDomainResultImpl;
|
||||
import org.hibernate.sql.results.internal.SqlSelectionImpl;
|
||||
@ -53,7 +55,7 @@
|
||||
*/
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
@DomainModel(
|
||||
annotatedClasses = org.hibernate.orm.test.metamodel.mapping.SmokeTests.SimpleEntity.class
|
||||
annotatedClasses = SimpleEntity.class
|
||||
)
|
||||
@ServiceRegistry(
|
||||
settings = @ServiceRegistry.Setting(
|
||||
@ -67,7 +69,10 @@ public class SmokeTests {
|
||||
public void testSimpleHqlInterpretation(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
final QueryImplementor<String> query = session.createQuery( "select e.name from SimpleEntity e", String.class );
|
||||
final QueryImplementor<String> query = session.createQuery(
|
||||
"select e.name from SimpleEntity e",
|
||||
String.class
|
||||
);
|
||||
final HqlQueryImplementor<String> hqlQuery = (HqlQueryImplementor<String>) query;
|
||||
//noinspection unchecked
|
||||
final SqmSelectStatement<String> sqmStatement = (SqmSelectStatement<String>) hqlQuery.getSqmStatement();
|
||||
@ -105,6 +110,16 @@ public void testSimpleHqlInterpretation(SessionFactoryScope scope) {
|
||||
assertThat( sqlSelection.getJdbcResultSetIndex(), is( 1 ) );
|
||||
assertThat( sqlSelection.getValuesArrayPosition(), is( 0 ) );
|
||||
assertThat( sqlSelection.getJdbcValueExtractor(), notNullValue() );
|
||||
|
||||
final JdbcSelect jdbcSelectOperation = SqlAstSelectToJdbcSelectConverter.interpret(
|
||||
sqlAst,
|
||||
session.getSessionFactory()
|
||||
);
|
||||
|
||||
assertThat(
|
||||
jdbcSelectOperation.getSql(),
|
||||
is( "select s1_0.name from mapping_simple_entity as s1_0" )
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
@ -155,7 +170,7 @@ public void testConvertedHqlInterpretation(SessionFactoryScope scope) {
|
||||
assertThat( rootTableGroup.getPrimaryTableReference().getIdentificationVariable(), is( "s1_0" ) );
|
||||
|
||||
final SelectClause selectClause = sqlAst.getQuerySpec().getSelectClause();
|
||||
assertThat( selectClause.getSqlSelections().size(), is( 1 ) ) ;
|
||||
assertThat( selectClause.getSqlSelections().size(), is( 1 ) );
|
||||
|
||||
final SqlSelection sqlSelection = selectClause.getSqlSelections().get( 0 );
|
||||
assertThat( sqlSelection.getJdbcResultSetIndex(), is( 1 ) );
|
||||
@ -197,6 +212,17 @@ public void testConvertedHqlInterpretation(SessionFactoryScope scope) {
|
||||
final BasicValueConverter valueConverter = ( (BasicResultAssembler) resultAssembler ).getValueConverter();
|
||||
assertThat( valueConverter, notNullValue() );
|
||||
assertThat( valueConverter, instanceOf( OrdinalEnumValueConverter.class ) );
|
||||
|
||||
|
||||
final JdbcSelect jdbcSelectOperation = SqlAstSelectToJdbcSelectConverter.interpret(
|
||||
sqlAst,
|
||||
session.getSessionFactory()
|
||||
);
|
||||
|
||||
assertThat(
|
||||
jdbcSelectOperation.getSql(),
|
||||
is( "select s1_0.gender from mapping_simple_entity as s1_0" )
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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.sql.exec;
|
||||
|
||||
import java.sql.Statement;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.orm.test.metamodel.mapping.SmokeTests.SimpleEntity;
|
||||
import org.hibernate.query.spi.QueryImplementor;
|
||||
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.FailureExpected;
|
||||
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.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hibernate.orm.test.metamodel.mapping.SmokeTests.Gender.FEMALE;
|
||||
import static org.hibernate.orm.test.metamodel.mapping.SmokeTests.Gender.MALE;
|
||||
|
||||
/**
|
||||
* @author Andrea Boriero
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@DomainModel(
|
||||
annotatedClasses = SimpleEntity.class
|
||||
)
|
||||
@ServiceRegistry(
|
||||
settings = @ServiceRegistry.Setting(
|
||||
name = AvailableSettings.HBM2DDL_AUTO,
|
||||
value = "create-drop"
|
||||
)
|
||||
)
|
||||
@SessionFactory
|
||||
public class SmokeTests {
|
||||
|
||||
@BeforeEach
|
||||
public void setUp(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
SimpleEntity simpleEntity = new SimpleEntity();
|
||||
simpleEntity.setId( 1 );
|
||||
simpleEntity.setGender( FEMALE );
|
||||
simpleEntity.setName( "Fab" );
|
||||
simpleEntity.setGender2( MALE );
|
||||
session.save( simpleEntity );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void tearDown(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session ->
|
||||
session.doWork(
|
||||
work -> {
|
||||
Statement statement = work.createStatement();
|
||||
statement.execute( "delete from mapping_simple_entity" );
|
||||
statement.close();
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSelectEntityFieldHqlExecution(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
final QueryImplementor<String> query = session.createQuery(
|
||||
"select e.name from SimpleEntity e",
|
||||
String.class
|
||||
);
|
||||
List<String> simpleEntities = query.list();
|
||||
assertThat( simpleEntities.size(), is( 1 ) );
|
||||
assertThat( simpleEntities.get( 0 ), is( "Fab" ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@FailureExpected( reason = "Support for entity-values DomainResults not yet implemented")
|
||||
public void testSelectEntityHqlExecution(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
final QueryImplementor<SimpleEntity> query = session.createQuery(
|
||||
"select e from SimpleEntity e",
|
||||
SimpleEntity.class
|
||||
);
|
||||
List<SimpleEntity> simpleEntities = query.list();
|
||||
assertThat( simpleEntities.size(), is( 1 ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
@ -45,7 +45,7 @@
|
||||
/**
|
||||
* A reason why the failure is expected
|
||||
*/
|
||||
String value() default "";
|
||||
String reason() default "";
|
||||
|
||||
/**
|
||||
* The key of a JIRA issue which covers this expected failure.
|
||||
|
@ -14,7 +14,6 @@
|
||||
import org.junit.jupiter.api.extension.ExecutionCondition;
|
||||
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||
import org.junit.jupiter.api.extension.TestExecutionExceptionHandler;
|
||||
import org.junit.platform.commons.support.AnnotationSupport;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
@ -58,7 +57,8 @@ public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext con
|
||||
|
||||
log.debugf( "Evaluating context - %s [failureExpectedValidation = %s]", context.getDisplayName(), failureExpectedValidation );
|
||||
|
||||
if ( AnnotationSupport.findAnnotation( context.getElement().get(), FailureExpected.class ).isPresent() ) {
|
||||
if ( TestingUtil.hasEffectiveAnnotation( context, FailureExpected.class )
|
||||
|| TestingUtil.hasEffectiveAnnotation( context, FailureExpectedGroup.class ) ) {
|
||||
// The test is marked as `FailureExpected`...
|
||||
if ( failureExpectedValidation ) {
|
||||
log.debugf( "Executing test marked with `@FailureExpected` for validation" );
|
||||
@ -82,7 +82,8 @@ public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext con
|
||||
public void beforeEach(ExtensionContext context) {
|
||||
log.tracef( "#beforeEach(%s)", context.getDisplayName() );
|
||||
|
||||
final boolean markedExpectedFailure = TestingUtil.hasEffectiveAnnotation( context, FailureExpected.class );
|
||||
final boolean markedExpectedFailure = TestingUtil.hasEffectiveAnnotation( context, FailureExpected.class )
|
||||
|| TestingUtil.hasEffectiveAnnotation( context, FailureExpectedGroup.class );
|
||||
|
||||
log.debugf( "Checking for @FailureExpected [%s] - %s", context.getDisplayName(), markedExpectedFailure );
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user