HHH-4917 - Keyword TYPE not supported
git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@18821 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
parent
1ec20855ee
commit
9f6e1ada66
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.hql.ast;
|
||||
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
/**
|
||||
* Essentially a wrapper around a {@link org.hibernate.persister.entity.DiscriminatorMetadata}
|
||||
* and the proper sql alias to use.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface TypeDiscriminatorMetadata {
|
||||
/**
|
||||
* Get the sql fragment that is used to determine the actual discriminator value for a row.
|
||||
*
|
||||
* @return The fragment
|
||||
*/
|
||||
public String getSqlFragment();
|
||||
|
||||
/**
|
||||
* Get the type used to resolve the actual discriminator value resulting from
|
||||
* {@link #getSqlFragment} back into a {@link Class} reference.
|
||||
*
|
||||
* @return The resolution type.
|
||||
*/
|
||||
public Type getResolutionType();
|
||||
}
|
|
@ -29,6 +29,7 @@ import java.util.List;
|
|||
import java.util.ArrayList;
|
||||
|
||||
import org.hibernate.QueryException;
|
||||
import org.hibernate.hql.ast.TypeDiscriminatorMetadata;
|
||||
import org.hibernate.param.ParameterSpecification;
|
||||
import org.hibernate.engine.JoinSequence;
|
||||
import org.hibernate.hql.QueryTranslator;
|
||||
|
@ -37,6 +38,7 @@ import org.hibernate.hql.antlr.SqlTokenTypes;
|
|||
import org.hibernate.hql.ast.util.ASTUtil;
|
||||
import org.hibernate.hql.ast.HqlSqlWalker;
|
||||
import org.hibernate.persister.collection.QueryableCollection;
|
||||
import org.hibernate.persister.entity.DiscriminatorMetadata;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.persister.entity.PropertyMapping;
|
||||
import org.hibernate.persister.entity.Queryable;
|
||||
|
@ -429,6 +431,58 @@ public class FromElement extends HqlSqlWalkerNode implements DisplayableNode, Pa
|
|||
return origin;
|
||||
}
|
||||
|
||||
public static final String DISCRIMINATOR_PROPERTY_NAME = "class";
|
||||
private TypeDiscriminatorMetadata typeDiscriminatorMetadata;
|
||||
|
||||
private static class TypeDiscriminatorMetadataImpl implements TypeDiscriminatorMetadata {
|
||||
private final DiscriminatorMetadata persisterDiscriminatorMetadata;
|
||||
private final String alias;
|
||||
|
||||
private TypeDiscriminatorMetadataImpl(
|
||||
DiscriminatorMetadata persisterDiscriminatorMetadata,
|
||||
String alias) {
|
||||
this.persisterDiscriminatorMetadata = persisterDiscriminatorMetadata;
|
||||
this.alias = alias;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public String getSqlFragment() {
|
||||
return persisterDiscriminatorMetadata.getSqlFragment( alias );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public Type getResolutionType() {
|
||||
return persisterDiscriminatorMetadata.getResolutionType();
|
||||
}
|
||||
}
|
||||
|
||||
public TypeDiscriminatorMetadata getTypeDiscriminatorMetadata() {
|
||||
if ( typeDiscriminatorMetadata == null ) {
|
||||
typeDiscriminatorMetadata = buildTypeDiscriminatorMetadata();
|
||||
}
|
||||
return typeDiscriminatorMetadata;
|
||||
}
|
||||
|
||||
private TypeDiscriminatorMetadata buildTypeDiscriminatorMetadata() {
|
||||
final String aliasToUse = getTableAlias();
|
||||
Queryable queryable = getQueryable();
|
||||
if ( queryable == null ) {
|
||||
QueryableCollection collection = getQueryableCollection();
|
||||
if ( ! collection.getElementType().isEntityType() ) {
|
||||
throw new QueryException( "type discrimination cannot be applied to value collection [" + collection.getRole() + "]" );
|
||||
}
|
||||
queryable = (Queryable) collection.getElementPersister();
|
||||
}
|
||||
|
||||
handlePropertyBeingDereferenced( getDataType(), DISCRIMINATOR_PROPERTY_NAME );
|
||||
|
||||
return new TypeDiscriminatorMetadataImpl( queryable.getTypeDiscriminatorMetadata(), aliasToUse );
|
||||
}
|
||||
|
||||
public Type getPropertyType(String propertyName, String propertyPath) {
|
||||
return elementType.getPropertyType( propertyName, propertyPath );
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ import java.util.Arrays;
|
|||
import org.hibernate.dialect.function.SQLFunction;
|
||||
import org.hibernate.hql.CollectionProperties;
|
||||
import org.hibernate.hql.antlr.SqlTokenTypes;
|
||||
import org.hibernate.hql.ast.TypeDiscriminatorMetadata;
|
||||
import org.hibernate.hql.ast.util.ASTUtil;
|
||||
import org.hibernate.hql.ast.util.ColumnHelper;
|
||||
import org.hibernate.persister.collection.CollectionPropertyNames;
|
||||
|
@ -83,13 +84,11 @@ public class MethodNode extends AbstractSelectExpression implements SelectExpres
|
|||
}
|
||||
|
||||
FromReferenceNode pathAsFromReferenceNode = (FromReferenceNode) path;
|
||||
FromElement typeFromElement = pathAsFromReferenceNode.getFromElement();
|
||||
Type type = typeFromElement.getPropertyType( "class", "class" );
|
||||
setDataType( type );
|
||||
|
||||
String[] columns = typeFromElement.toColumns( typeFromElement.getTableAlias(), "class", inSelect );
|
||||
setText( columns[0] );
|
||||
FromElement fromElement = pathAsFromReferenceNode.getFromElement();
|
||||
TypeDiscriminatorMetadata typeDiscriminatorMetadata = fromElement.getTypeDiscriminatorMetadata();
|
||||
|
||||
setDataType( typeDiscriminatorMetadata.getResolutionType() );
|
||||
setText( typeDiscriminatorMetadata.getSqlFragment() );
|
||||
setType( SqlTokenTypes.SQL_TOKEN );
|
||||
}
|
||||
|
||||
|
@ -217,7 +216,6 @@ public class MethodNode extends AbstractSelectExpression implements SelectExpres
|
|||
}
|
||||
|
||||
protected void prepareSelectColumns(String[] columns) {
|
||||
return;
|
||||
}
|
||||
|
||||
public FromElement getFromElement() {
|
||||
|
|
|
@ -87,6 +87,7 @@ import org.hibernate.mapping.PersistentClass;
|
|||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.mapping.Selectable;
|
||||
import org.hibernate.metadata.ClassMetadata;
|
||||
import org.hibernate.persister.entity.DiscriminatorMetadata;
|
||||
import org.hibernate.pretty.MessageHelper;
|
||||
import org.hibernate.property.BackrefPropertyAccessor;
|
||||
import org.hibernate.sql.Alias;
|
||||
|
@ -1500,6 +1501,27 @@ public abstract class AbstractEntityPersister
|
|||
}
|
||||
}
|
||||
|
||||
private DiscriminatorMetadata discriminatorMetadata;
|
||||
|
||||
public DiscriminatorMetadata getTypeDiscriminatorMetadata() {
|
||||
if ( discriminatorMetadata == null ) {
|
||||
discriminatorMetadata = buildTypeDiscriminatorMetadata();
|
||||
}
|
||||
return discriminatorMetadata;
|
||||
}
|
||||
|
||||
private DiscriminatorMetadata buildTypeDiscriminatorMetadata() {
|
||||
return new DiscriminatorMetadata() {
|
||||
public String getSqlFragment(String sqlQualificationAlias) {
|
||||
return toColumns( sqlQualificationAlias, ENTITY_CLASS )[0];
|
||||
}
|
||||
|
||||
public Type getResolutionType() {
|
||||
return new DiscriminatorType( getDiscriminatorType(), AbstractEntityPersister.this );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected String generateTableAlias(String rootAlias, int tableNumber) {
|
||||
if ( tableNumber == 0 ) {
|
||||
return rootAlias;
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.persister.entity;
|
||||
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
/**
|
||||
* Provides the information needed to properly handle type discrimination
|
||||
* in HQL queries, either by 'something.class' or 'type(something)' references.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface DiscriminatorMetadata {
|
||||
/**
|
||||
* Get the sql fragment that is used to determine the actual discriminator value for a row.
|
||||
*
|
||||
* @param sqlQualificationAlias The qualification alias to append to any columns references in
|
||||
* the generated fragment.
|
||||
*
|
||||
* @return The fragment
|
||||
*/
|
||||
public String getSqlFragment(String sqlQualificationAlias);
|
||||
|
||||
/**
|
||||
* Get the type used to resolve the actual discriminator value resulting from
|
||||
* {@link #getSqlFragment} back into a {@link Class} reference.
|
||||
*
|
||||
* @return The resolution type.
|
||||
*/
|
||||
public Type getResolutionType();
|
||||
}
|
|
@ -0,0 +1,160 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.persister.entity;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.dom4j.Node;
|
||||
|
||||
import org.hibernate.EntityMode;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.engine.Mapping;
|
||||
import org.hibernate.engine.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.SessionImplementor;
|
||||
import org.hibernate.type.AbstractType;
|
||||
import org.hibernate.type.Type;
|
||||
import org.hibernate.util.ArrayHelper;
|
||||
import org.hibernate.util.EqualsHelper;
|
||||
|
||||
/**
|
||||
* TODO : javadoc
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class DiscriminatorType extends AbstractType {
|
||||
private final Type underlyingType;
|
||||
private final Loadable persister;
|
||||
|
||||
public DiscriminatorType(Type underlyingType, Loadable persister) {
|
||||
this.underlyingType = underlyingType;
|
||||
this.persister = persister;
|
||||
}
|
||||
|
||||
public Class getReturnedClass() {
|
||||
return Class.class;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return getClass().getName();
|
||||
}
|
||||
|
||||
public boolean isMutable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public Object nullSafeGet(
|
||||
ResultSet rs,
|
||||
String[] names,
|
||||
SessionImplementor session,
|
||||
Object owner) throws HibernateException, SQLException {
|
||||
return nullSafeGet( rs, names[0], session, owner );
|
||||
}
|
||||
|
||||
public Object nullSafeGet(
|
||||
ResultSet rs,
|
||||
String name,
|
||||
SessionImplementor session,
|
||||
Object owner) throws HibernateException, SQLException {
|
||||
final Object discriminatorValue = underlyingType.nullSafeGet( rs, name, session, owner );
|
||||
final String entityName = persister.getSubclassForDiscriminatorValue( discriminatorValue );
|
||||
if ( entityName == null ) {
|
||||
throw new HibernateException( "Unable to resolve discriminator value [" + discriminatorValue + "] to entity name" );
|
||||
}
|
||||
if ( EntityMode.POJO.equals( session.getEntityMode() ) ) {
|
||||
return session.getEntityPersister( entityName, null ).getMappedClass( session.getEntityMode() );
|
||||
}
|
||||
else {
|
||||
return entityName;
|
||||
}
|
||||
}
|
||||
|
||||
public void nullSafeSet(
|
||||
PreparedStatement st,
|
||||
Object value,
|
||||
int index,
|
||||
boolean[] settable,
|
||||
SessionImplementor session) throws HibernateException, SQLException {
|
||||
nullSafeSet( st, value, index, session );
|
||||
}
|
||||
|
||||
public void nullSafeSet(
|
||||
PreparedStatement st,
|
||||
Object value,
|
||||
int index,
|
||||
SessionImplementor session) throws HibernateException, SQLException {
|
||||
throw new UnsupportedOperationException(
|
||||
"At the moment this type is not the one actually used to map the discriminator."
|
||||
);
|
||||
}
|
||||
|
||||
public String toLoggableString(Object value, SessionFactoryImplementor factory) throws HibernateException {
|
||||
return value == null ? "[null]" : value.toString();
|
||||
}
|
||||
|
||||
public Object deepCopy(Object value, EntityMode entityMode, SessionFactoryImplementor factory)
|
||||
throws HibernateException {
|
||||
return value;
|
||||
}
|
||||
|
||||
public Object replace(Object original, Object target, SessionImplementor session, Object owner, Map copyCache)
|
||||
throws HibernateException {
|
||||
return original;
|
||||
}
|
||||
|
||||
public boolean[] toColumnNullness(Object value, Mapping mapping) {
|
||||
return value == null
|
||||
? ArrayHelper.FALSE
|
||||
: ArrayHelper.TRUE;
|
||||
}
|
||||
|
||||
public boolean isDirty(Object old, Object current, boolean[] checkable, SessionImplementor session)
|
||||
throws HibernateException {
|
||||
return EqualsHelper.equals( old, current );
|
||||
}
|
||||
|
||||
|
||||
// simple delegation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
public int[] sqlTypes(Mapping mapping) throws MappingException {
|
||||
return underlyingType.sqlTypes( mapping );
|
||||
}
|
||||
|
||||
public int getColumnSpan(Mapping mapping) throws MappingException {
|
||||
return underlyingType.getColumnSpan( mapping );
|
||||
}
|
||||
|
||||
public void setToXMLNode(Node node, Object value, SessionFactoryImplementor factory) throws HibernateException {
|
||||
}
|
||||
|
||||
public Object fromXMLNode(Node xml, Mapping factory) throws HibernateException {
|
||||
// todo : ???
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -49,6 +49,7 @@ import org.hibernate.mapping.Subclass;
|
|||
import org.hibernate.mapping.Table;
|
||||
import org.hibernate.sql.CaseFragment;
|
||||
import org.hibernate.sql.SelectFragment;
|
||||
import org.hibernate.type.AbstractType;
|
||||
import org.hibernate.type.Type;
|
||||
import org.hibernate.util.ArrayHelper;
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
*/
|
||||
package org.hibernate.persister.entity;
|
||||
|
||||
import org.hibernate.persister.entity.DiscriminatorMetadata;
|
||||
import org.hibernate.sql.SelectFragment;
|
||||
|
||||
/**
|
||||
|
@ -165,6 +166,14 @@ public interface Queryable extends Loadable, PropertyMapping, Joinable {
|
|||
*/
|
||||
public String generateFilterConditionAlias(String rootAlias);
|
||||
|
||||
/**
|
||||
* Retrieve the information needed to properly deal with this entity's discriminator
|
||||
* in a query.
|
||||
*
|
||||
* @return The entity discriminator metadata
|
||||
*/
|
||||
public DiscriminatorMetadata getTypeDiscriminatorMetadata();
|
||||
|
||||
public static class Declarer {
|
||||
public static final Declarer CLASS = new Declarer( "class" );
|
||||
public static final Declarer SUBCLASS = new Declarer( "subclass" );
|
||||
|
|
|
@ -38,6 +38,7 @@ import org.hibernate.dialect.SybaseDialect;
|
|||
import org.hibernate.hql.ast.ASTQueryTranslatorFactory;
|
||||
import org.hibernate.junit.functional.FunctionalTestCase;
|
||||
import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
|
||||
import org.hibernate.persister.entity.DiscriminatorType;
|
||||
import org.hibernate.stat.QueryStatistics;
|
||||
import org.hibernate.test.any.IntegerPropertyValue;
|
||||
import org.hibernate.test.any.PropertySet;
|
||||
|
@ -111,11 +112,27 @@ public class ASTParserLoadingTest extends FunctionalTestCase {
|
|||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// where clause
|
||||
// control
|
||||
s.createQuery( "from Animal a where a.class = Dog" ).list();
|
||||
|
||||
// test
|
||||
s.createQuery( "from Animal a where type(a) = Dog" ).list();
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// select clause (at some point we should unify these)
|
||||
// control
|
||||
Query query = s.createQuery( "select a.class from Animal a where a.class = Dog" );
|
||||
query.list(); // checks syntax
|
||||
assertEquals( 1, query.getReturnTypes().length );
|
||||
assertEquals( Integer.class, query.getReturnTypes()[0].getReturnedClass() ); // always integer for joined
|
||||
// test
|
||||
query = s.createQuery( "select type(a) from Animal a where type(a) = Dog" );
|
||||
query.list(); // checks syntax
|
||||
assertEquals( 1, query.getReturnTypes().length );
|
||||
assertEquals( DiscriminatorType.class, query.getReturnTypes()[0].getClass() );
|
||||
assertEquals( Class.class, query.getReturnTypes()[0].getReturnedClass() );
|
||||
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue