HHH-5946 - Wrong SQL generated when composites are compared using not-equal operator
(cherry picked from commit cd2b031b6b
)
This commit is contained in:
parent
7612f8c183
commit
92a830a5dd
|
@ -12,6 +12,7 @@ import org.hibernate.HibernateException;
|
||||||
import org.hibernate.TypeMismatchException;
|
import org.hibernate.TypeMismatchException;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.hql.internal.antlr.HqlSqlTokenTypes;
|
import org.hibernate.hql.internal.antlr.HqlSqlTokenTypes;
|
||||||
|
import org.hibernate.hql.internal.ast.QuerySyntaxException;
|
||||||
import org.hibernate.hql.internal.ast.util.ColumnHelper;
|
import org.hibernate.hql.internal.ast.util.ColumnHelper;
|
||||||
import org.hibernate.internal.util.StringHelper;
|
import org.hibernate.internal.util.StringHelper;
|
||||||
import org.hibernate.param.ParameterSpecification;
|
import org.hibernate.param.ParameterSpecification;
|
||||||
|
@ -110,8 +111,22 @@ public class BinaryLogicOperatorNode extends AbstractSelectExpression implements
|
||||||
// mutation depends on the types of nodes involved...
|
// mutation depends on the types of nodes involved...
|
||||||
int comparisonType = getType();
|
int comparisonType = getType();
|
||||||
String comparisonText = getText();
|
String comparisonText = getText();
|
||||||
setType( HqlSqlTokenTypes.AND );
|
|
||||||
setText( "AND" );
|
switch ( comparisonType ) {
|
||||||
|
case HqlSqlTokenTypes.EQ:
|
||||||
|
setType( HqlSqlTokenTypes.AND );
|
||||||
|
setText( "AND" );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HqlSqlTokenTypes.NE:
|
||||||
|
setType( HqlSqlTokenTypes.OR );
|
||||||
|
setText( "OR" );
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new QuerySyntaxException( comparisonText + " operator not supported on composite types." );
|
||||||
|
}
|
||||||
|
|
||||||
String[] lhsElementTexts = extractMutationTexts( getLeftHandOperand(), valueElements );
|
String[] lhsElementTexts = extractMutationTexts( getLeftHandOperand(), valueElements );
|
||||||
String[] rhsElementTexts = extractMutationTexts( getRightHandOperand(), valueElements );
|
String[] rhsElementTexts = extractMutationTexts( getRightHandOperand(), valueElements );
|
||||||
|
|
||||||
|
@ -175,7 +190,7 @@ public class BinaryLogicOperatorNode extends AbstractSelectExpression implements
|
||||||
AST rhs = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, rhsElementTexts[i] );
|
AST rhs = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, rhsElementTexts[i] );
|
||||||
op.setFirstChild( lhs );
|
op.setFirstChild( lhs );
|
||||||
lhs.setNextSibling( rhs );
|
lhs.setNextSibling( rhs );
|
||||||
AST newContainer = getASTFactory().create( HqlSqlTokenTypes.AND, "AND" );
|
AST newContainer = getASTFactory().create( container.getType(), container.getText() );
|
||||||
container.setFirstChild( newContainer );
|
container.setFirstChild( newContainer );
|
||||||
newContainer.setNextSibling( op );
|
newContainer.setNextSibling( op );
|
||||||
container = newContainer;
|
container = newContainer;
|
||||||
|
|
|
@ -0,0 +1,203 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014, 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.test.cut;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class for testing composite user types with more than two fields.
|
||||||
|
*
|
||||||
|
* @author Etienne Miret
|
||||||
|
*/
|
||||||
|
public class CompositeDateTime implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 7401750071679578453L;
|
||||||
|
|
||||||
|
private Integer year;
|
||||||
|
|
||||||
|
private Integer month;
|
||||||
|
|
||||||
|
private Integer day;
|
||||||
|
|
||||||
|
private Integer hour;
|
||||||
|
|
||||||
|
private Integer minute;
|
||||||
|
|
||||||
|
private Integer second;
|
||||||
|
|
||||||
|
public CompositeDateTime(final Integer year, final Integer month, final Integer day, final Integer hour,
|
||||||
|
final Integer minute, final Integer second) {
|
||||||
|
super();
|
||||||
|
this.year = year;
|
||||||
|
this.month = month;
|
||||||
|
this.day = day;
|
||||||
|
this.hour = hour;
|
||||||
|
this.minute = minute;
|
||||||
|
this.second = second;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Constructor for those who hate auto (un)boxing.
|
||||||
|
*/
|
||||||
|
public CompositeDateTime(final int year, final int month, final int day, final int hour,
|
||||||
|
final int minute, final int second) {
|
||||||
|
this( new Integer( year ), Integer.valueOf( month ), Integer.valueOf( day ), Integer.valueOf( hour ),
|
||||||
|
Integer.valueOf( minute ), Integer.valueOf( second ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompositeDateTime(final CompositeDateTime other) {
|
||||||
|
super();
|
||||||
|
this.year = other.year;
|
||||||
|
this.month = other.month;
|
||||||
|
this.day = other.day;
|
||||||
|
this.hour = other.hour;
|
||||||
|
this.minute = other.minute;
|
||||||
|
this.second = other.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getYear() {
|
||||||
|
return year;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setYear(final Integer year) {
|
||||||
|
this.year = year;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getMonth() {
|
||||||
|
return month;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMonth(final Integer month) {
|
||||||
|
this.month = month;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getDay() {
|
||||||
|
return day;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDay(final Integer day) {
|
||||||
|
this.day = day;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getHour() {
|
||||||
|
return hour;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHour(final Integer hour) {
|
||||||
|
this.hour = hour;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getMinute() {
|
||||||
|
return minute;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMinute(final Integer minute) {
|
||||||
|
this.minute = minute;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getSecond() {
|
||||||
|
return second;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSecond(final Integer second) {
|
||||||
|
this.second = second;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result + ( ( day == null ) ? 0 : day.hashCode() );
|
||||||
|
result = prime * result + ( ( hour == null ) ? 0 : hour.hashCode() );
|
||||||
|
result = prime * result + ( ( minute == null ) ? 0 : minute.hashCode() );
|
||||||
|
result = prime * result + ( ( month == null ) ? 0 : month.hashCode() );
|
||||||
|
result = prime * result + ( ( second == null ) ? 0 : second.hashCode() );
|
||||||
|
result = prime * result + ( ( year == null ) ? 0 : year.hashCode() );
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if ( this == obj ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if ( obj == null ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ( !( obj instanceof CompositeDateTime ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
CompositeDateTime other = (CompositeDateTime) obj;
|
||||||
|
if ( day == null ) {
|
||||||
|
if ( other.day != null ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( !day.equals( other.day ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ( hour == null ) {
|
||||||
|
if ( other.hour != null ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( !hour.equals( other.hour ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ( minute == null ) {
|
||||||
|
if ( other.minute != null ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( !minute.equals( other.minute ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ( month == null ) {
|
||||||
|
if ( other.month != null ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( !month.equals( other.month ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ( second == null ) {
|
||||||
|
if ( other.second != null ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( !second.equals( other.second ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ( year == null ) {
|
||||||
|
if ( other.year != null ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( !year.equals( other.year ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,158 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014, 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.test.cut;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
import org.hibernate.HibernateException;
|
||||||
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
|
import org.hibernate.type.StandardBasicTypes;
|
||||||
|
import org.hibernate.type.Type;
|
||||||
|
import org.hibernate.usertype.CompositeUserType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class for testing composite user types with more than two fields.
|
||||||
|
*
|
||||||
|
* @author Etienne Miret
|
||||||
|
*/
|
||||||
|
public class CompositeDateTimeUserType implements CompositeUserType {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] getPropertyNames() {
|
||||||
|
return new String[] { "year", "month", "day", "hour", "minute", "second" };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Type[] getPropertyTypes() {
|
||||||
|
return new Type[] { StandardBasicTypes.INTEGER, StandardBasicTypes.INTEGER, StandardBasicTypes.INTEGER,
|
||||||
|
StandardBasicTypes.INTEGER, StandardBasicTypes.INTEGER, StandardBasicTypes.INTEGER };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getPropertyValue(Object component, int property) throws HibernateException {
|
||||||
|
final CompositeDateTime dateTime = (CompositeDateTime) component;
|
||||||
|
switch ( property ) {
|
||||||
|
case 0:
|
||||||
|
return dateTime.getYear();
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
return dateTime.getMonth();
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
return dateTime.getDay();
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
return dateTime.getHour();
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
return dateTime.getMinute();
|
||||||
|
|
||||||
|
case 5:
|
||||||
|
return dateTime.getSecond();
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new HibernateException( "This type has only 6 fields." );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPropertyValue(Object component, int property, Object value) throws HibernateException {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<CompositeDateTime> returnedClass() {
|
||||||
|
return CompositeDateTime.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object x, Object y) throws HibernateException {
|
||||||
|
return x == null ? y == null : x.equals( y );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode(Object x) throws HibernateException {
|
||||||
|
return x == null ? 0 : x.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner) throws HibernateException, SQLException {
|
||||||
|
final Integer year = rs.getObject( names[0], Integer.class );
|
||||||
|
final Integer month = rs.getObject( names[1], Integer.class );
|
||||||
|
final Integer day = rs.getObject( names[2], Integer.class );
|
||||||
|
final Integer hour = rs.getObject( names[3], Integer.class );
|
||||||
|
final Integer minute = rs.getObject( names[4], Integer.class );
|
||||||
|
final Integer second = rs.getObject( names[5], Integer.class );
|
||||||
|
if ( year == null && month == null && day == null && hour == null && minute == null && second == null ) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return new CompositeDateTime( year, month, day, hour, minute, second );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) throws HibernateException, SQLException {
|
||||||
|
if ( value == null ) {
|
||||||
|
for (int i = 0; i < 6; i++ ) {
|
||||||
|
st.setObject( index + i, null );
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
final CompositeDateTime dateTime = (CompositeDateTime) value;
|
||||||
|
st.setObject( index, dateTime.getYear() );
|
||||||
|
st.setObject( index + 1, dateTime.getMonth() );
|
||||||
|
st.setObject( index + 2, dateTime.getDay() );
|
||||||
|
st.setObject( index + 3, dateTime.getHour() );
|
||||||
|
st.setObject( index + 4, dateTime.getMinute() );
|
||||||
|
st.setObject( index + 5, dateTime.getSecond() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompositeDateTime deepCopy(Object value) throws HibernateException {
|
||||||
|
return value == null ? null : new CompositeDateTime( (CompositeDateTime) value );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMutable() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Serializable disassemble(Object value, SessionImplementor session) throws HibernateException {
|
||||||
|
return deepCopy( value );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object assemble(Serializable cached, SessionImplementor session, Object owner) throws HibernateException {
|
||||||
|
return deepCopy( cached );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object replace(Object original, Object target, SessionImplementor session, Object owner) throws HibernateException {
|
||||||
|
return deepCopy( original );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -11,13 +11,16 @@ import java.math.BigDecimal;
|
||||||
import java.util.Currency;
|
import java.util.Currency;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.hibernate.Query;
|
||||||
import org.hibernate.Session;
|
import org.hibernate.Session;
|
||||||
import org.hibernate.criterion.Restrictions;
|
import org.hibernate.criterion.Restrictions;
|
||||||
import org.hibernate.dialect.DB2Dialect;
|
import org.hibernate.dialect.DB2Dialect;
|
||||||
import org.hibernate.dialect.HSQLDialect;
|
import org.hibernate.dialect.HSQLDialect;
|
||||||
import org.hibernate.dialect.SybaseASE15Dialect;
|
import org.hibernate.dialect.SybaseASE15Dialect;
|
||||||
|
import org.hibernate.hql.internal.ast.QuerySyntaxException;
|
||||||
import org.hibernate.testing.SkipForDialect;
|
import org.hibernate.testing.SkipForDialect;
|
||||||
import org.hibernate.testing.SkipForDialects;
|
import org.hibernate.testing.SkipForDialects;
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
@ -52,7 +55,8 @@ public class CompositeUserTypeTest extends BaseCoreFunctionalTestCase {
|
||||||
assertEquals( result.size(), 1 );
|
assertEquals( result.size(), 1 );
|
||||||
result = s.createQuery("from Transaction where value = (1.5, 'AUD')").list();
|
result = s.createQuery("from Transaction where value = (1.5, 'AUD')").list();
|
||||||
assertEquals( result.size(), 1 );
|
assertEquals( result.size(), 1 );
|
||||||
|
result = s.createQuery( "from Transaction where value != (1.4, 'AUD')" ).list();
|
||||||
|
assertEquals( result.size(), 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
s.delete(tran);
|
s.delete(tran);
|
||||||
|
@ -102,5 +106,185 @@ public class CompositeUserTypeTest extends BaseCoreFunctionalTestCase {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
/**
|
||||||
|
* Tests the {@code =} operator on composite types.
|
||||||
|
*/
|
||||||
|
public void testEqualOperator() {
|
||||||
|
final Session s = openSession();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
|
||||||
|
final Transaction txn = new Transaction();
|
||||||
|
txn.setDescription( "foo" );
|
||||||
|
txn.setValue( new MonetoryAmount( new BigDecimal( 42 ), Currency.getInstance( "AUD" ) ) );
|
||||||
|
txn.setTimestamp( new CompositeDateTime( 2014, 8, 23, 14, 35, 0 ) );
|
||||||
|
s.persist( txn );
|
||||||
|
|
||||||
|
final Query q = s.createQuery( "from Transaction where value = :amount" );
|
||||||
|
|
||||||
|
/* Both amount and currency match. */
|
||||||
|
q.setParameter( "amount", new MonetoryAmount( new BigDecimal( 42 ), Currency.getInstance( "AUD" ) ) );
|
||||||
|
assertEquals( 1, q.list().size() );
|
||||||
|
|
||||||
|
/* Only currency matches. */
|
||||||
|
q.setParameter( "amount", new MonetoryAmount( new BigDecimal( 36 ), Currency.getInstance( "AUD" ) ) );
|
||||||
|
assertEquals( 0, q.list().size() );
|
||||||
|
|
||||||
|
/* Only amount matches. */
|
||||||
|
q.setParameter( "amount", new MonetoryAmount( new BigDecimal( 42 ), Currency.getInstance( "EUR" ) ) );
|
||||||
|
assertEquals( 0, q.list().size() );
|
||||||
|
|
||||||
|
/* None match. */
|
||||||
|
q.setParameter( "amount", new MonetoryAmount( new BigDecimal( 76 ), Currency.getInstance( "USD" ) ) );
|
||||||
|
assertEquals( 0, q.list().size() );
|
||||||
|
|
||||||
|
final Query qTimestamp = s.createQuery( "from Transaction where timestamp = :timestamp" );
|
||||||
|
|
||||||
|
/* All matches. */
|
||||||
|
qTimestamp.setParameter( "timestamp", new CompositeDateTime( 2014, 8, 23, 14, 35, 0 ) );
|
||||||
|
assertEquals( 1, qTimestamp.list().size() );
|
||||||
|
|
||||||
|
/* None matches. */
|
||||||
|
qTimestamp.setParameter( "timestamp", new CompositeDateTime( 2013, 9, 25, 12, 31, 25 ) );
|
||||||
|
assertEquals( 0, qTimestamp.list().size() );
|
||||||
|
|
||||||
|
/* Year doesn't match. */
|
||||||
|
qTimestamp.setParameter( "timestamp", new CompositeDateTime( 2013, 8, 23, 14, 35, 0 ) );
|
||||||
|
assertEquals( 0, qTimestamp.list().size() );
|
||||||
|
|
||||||
|
/* Month doesn't match. */
|
||||||
|
qTimestamp.setParameter( "timestamp", new CompositeDateTime( 2014, 9, 23, 14, 35, 0 ) );
|
||||||
|
assertEquals( 0, qTimestamp.list().size() );
|
||||||
|
|
||||||
|
/* Minute doesn't match. */
|
||||||
|
qTimestamp.setParameter( "timestamp", new CompositeDateTime( 2014, 8, 23, 14, 41, 0 ) );
|
||||||
|
assertEquals( 0, qTimestamp.list().size() );
|
||||||
|
|
||||||
|
/* Second doesn't match. */
|
||||||
|
qTimestamp.setParameter( "timestamp", new CompositeDateTime( 2014, 8, 23, 14, 35, 28 ) );
|
||||||
|
assertEquals( 0, qTimestamp.list().size() );
|
||||||
|
|
||||||
|
s.delete( txn );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the {@code <>} operator on composite types.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
@TestForIssue( jiraKey = "HHH-5946" )
|
||||||
|
public void testNotEqualOperator() {
|
||||||
|
final Session s = openSession();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
|
||||||
|
final Transaction t1 = new Transaction();
|
||||||
|
t1.setDescription( "foo" );
|
||||||
|
t1.setValue( new MonetoryAmount( new BigDecimal( 178 ), Currency.getInstance( "EUR" ) ) );
|
||||||
|
t1.setTimestamp( new CompositeDateTime( 2014, 8, 23, 14, 23, 0 ) );
|
||||||
|
s.persist( t1 );
|
||||||
|
|
||||||
|
final Transaction t2 = new Transaction();
|
||||||
|
t2.setDescription( "bar" );
|
||||||
|
t2.setValue( new MonetoryAmount( new BigDecimal( 1000000 ), Currency.getInstance( "USD" ) ) );
|
||||||
|
t1.setTimestamp( new CompositeDateTime( 2014, 8, 22, 14, 23, 0 ) );
|
||||||
|
s.persist( t2 );
|
||||||
|
|
||||||
|
final Transaction t3 = new Transaction();
|
||||||
|
t3.setDescription( "bar" );
|
||||||
|
t3.setValue( new MonetoryAmount( new BigDecimal( 1000000 ), Currency.getInstance( "EUR" ) ) );
|
||||||
|
t3.setTimestamp( new CompositeDateTime( 2014, 8, 22, 14, 23, 01 ) );
|
||||||
|
s.persist( t3 );
|
||||||
|
|
||||||
|
final Query q1 = s.createQuery( "from Transaction where value <> :amount" );
|
||||||
|
q1.setParameter( "amount", new MonetoryAmount( new BigDecimal( 178 ), Currency.getInstance( "EUR" ) ) );
|
||||||
|
assertEquals( 2, q1.list().size() );
|
||||||
|
|
||||||
|
final Query q2 = s.createQuery( "from Transaction where value <> :amount and description = :str" );
|
||||||
|
q2.setParameter( "amount", new MonetoryAmount( new BigDecimal( 1000000 ), Currency.getInstance( "USD" ) ) );
|
||||||
|
q2.setParameter( "str", "bar" );
|
||||||
|
assertEquals( 1, q2.list().size() );
|
||||||
|
|
||||||
|
final Query q3 = s.createQuery( "from Transaction where timestamp <> :timestamp" );
|
||||||
|
q3.setParameter( "timestamp", new CompositeDateTime( 2014, 8, 23, 14, 23, 0 ) );
|
||||||
|
assertEquals( 2, q3.list().size() );
|
||||||
|
|
||||||
|
s.delete( t3 );
|
||||||
|
s.delete( t2 );
|
||||||
|
s.delete( t1 );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the {@code <} operator on composite types. As long as we don't support it, we need to throw an exception
|
||||||
|
* rather than create a random query.
|
||||||
|
*/
|
||||||
|
@Test( expected = QuerySyntaxException.class )
|
||||||
|
@TestForIssue( jiraKey = "HHH-5946" )
|
||||||
|
public void testLessThanOperator() {
|
||||||
|
final Session s = openSession();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
|
||||||
|
final Query q = s.createQuery( "from Transaction where value < :amount" );
|
||||||
|
q.setParameter( "amount", new MonetoryAmount( BigDecimal.ZERO, Currency.getInstance( "EUR" ) ) );
|
||||||
|
q.list();
|
||||||
|
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the {@code <=} operator on composite types. As long as we don't support it, we need to throw an exception
|
||||||
|
* rather than create a random query.
|
||||||
|
*/
|
||||||
|
@Test( expected = QuerySyntaxException.class )
|
||||||
|
@TestForIssue( jiraKey = "HHH-5946" )
|
||||||
|
public void testLessOrEqualOperator() {
|
||||||
|
final Session s = openSession();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
|
||||||
|
final Query q = s.createQuery( "from Transaction where value <= :amount" );
|
||||||
|
q.setParameter( "amount", new MonetoryAmount( BigDecimal.ZERO, Currency.getInstance( "USD" ) ) );
|
||||||
|
q.list();
|
||||||
|
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the {@code >} operator on composite types. As long as we don't support it, we need to throw an exception
|
||||||
|
* rather than create a random query.
|
||||||
|
*/
|
||||||
|
@Test( expected = QuerySyntaxException.class )
|
||||||
|
@TestForIssue( jiraKey = "HHH-5946" )
|
||||||
|
public void testGreaterThanOperator() {
|
||||||
|
final Session s = openSession();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
|
||||||
|
final Query q = s.createQuery( "from Transaction where value > :amount" );
|
||||||
|
q.setParameter( "amount", new MonetoryAmount( BigDecimal.ZERO, Currency.getInstance( "EUR" ) ) );
|
||||||
|
q.list();
|
||||||
|
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the {@code >=} operator on composite types. As long as we don't support it, we need to throw an exception
|
||||||
|
* rather than create a random query.
|
||||||
|
*/
|
||||||
|
@Test( expected = QuerySyntaxException.class )
|
||||||
|
@TestForIssue( jiraKey = "HHH-5946" )
|
||||||
|
public void testGreaterOrEqualOperator() {
|
||||||
|
final Session s = openSession();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
|
||||||
|
final Query q = s.createQuery( "from Transaction where value >= :amount" );
|
||||||
|
q.setParameter( "amount", new MonetoryAmount( BigDecimal.ZERO, Currency.getInstance( "USD" ) ) );
|
||||||
|
q.list();
|
||||||
|
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -26,6 +26,14 @@
|
||||||
<column name="amount" not-null="true"/>
|
<column name="amount" not-null="true"/>
|
||||||
<column name="currency" not-null="true"/>
|
<column name="currency" not-null="true"/>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="timestamp" type="userDateTime">
|
||||||
|
<column name="year"/>
|
||||||
|
<column name="month"/>
|
||||||
|
<column name="day"/>
|
||||||
|
<column name="hour"/>
|
||||||
|
<column name="minute"/>
|
||||||
|
<column name="second"/>
|
||||||
|
</property>
|
||||||
</class>
|
</class>
|
||||||
|
|
||||||
<class name="MutualFund" table="MutualFund">
|
<class name="MutualFund" table="MutualFund">
|
||||||
|
|
|
@ -17,7 +17,8 @@ public class Transaction {
|
||||||
private Long id;
|
private Long id;
|
||||||
private String description;
|
private String description;
|
||||||
private MonetoryAmount value;
|
private MonetoryAmount value;
|
||||||
|
private CompositeDateTime timestamp;
|
||||||
|
|
||||||
public String getDescription() {
|
public String getDescription() {
|
||||||
return description;
|
return description;
|
||||||
}
|
}
|
||||||
|
@ -42,4 +43,12 @@ public class Transaction {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CompositeDateTime getTimestamp() {
|
||||||
|
return timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTimestamp(CompositeDateTime timestamp) {
|
||||||
|
this.timestamp = timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,4 +11,5 @@
|
||||||
|
|
||||||
<hibernate-mapping package="org.hibernate.test.cut">
|
<hibernate-mapping package="org.hibernate.test.cut">
|
||||||
<typedef name="money" class="org.hibernate.test.cut.MonetoryAmountUserType"/>
|
<typedef name="money" class="org.hibernate.test.cut.MonetoryAmountUserType"/>
|
||||||
</hibernate-mapping>
|
<typedef name="userDateTime" class="org.hibernate.test.cut.CompositeDateTimeUserType"/>
|
||||||
|
</hibernate-mapping>
|
||||||
|
|
|
@ -1441,11 +1441,6 @@ public class ASTParserLoadingTest extends BaseCoreFunctionalTestCase {
|
||||||
s.createQuery( "from Human h where ('John', 'X', 'Doe') = h.name" ).list();
|
s.createQuery( "from Human h where ('John', 'X', 'Doe') = h.name" ).list();
|
||||||
s.createQuery( "from Human h where ('John', 'X', 'Doe') <> h.name" ).list();
|
s.createQuery( "from Human h where ('John', 'X', 'Doe') <> h.name" ).list();
|
||||||
|
|
||||||
// HANA only allows '=' and '<>'/'!='
|
|
||||||
if ( ! ( getDialect() instanceof AbstractHANADialect ) ) {
|
|
||||||
s.createQuery( "from Human h where ('John', 'X', 'Doe') >= h.name" ).list();
|
|
||||||
}
|
|
||||||
|
|
||||||
s.createQuery( "from Human h order by h.name" ).list();
|
s.createQuery( "from Human h order by h.name" ).list();
|
||||||
|
|
||||||
s.getTransaction().commit();
|
s.getTransaction().commit();
|
||||||
|
|
Loading…
Reference in New Issue